Snapshot-RSync: Unterschied zwischen den Versionen

Aus Neobikers Wiki
Zur Navigation springen Zur Suche springen
Keine Bearbeitungszusammenfassung
 
(25 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
Ich sichere 3x täglich per Snapshot meine Daten mit folgendem Script. Zusätzlich führe ich 2x die Woche einen Filesystemcheck auf /backup aus. Beises sind cronjobs.
Ich sichere 3x täglich per Snapshot meine Daten mit folgendem Script. Zusätzlich führe ich einen Filesystemcheck auf /backup aus (cronjobs).
 
= Installation =
Der '''Cronjob''':
<pre>
### Daten-Server Backup
4 6,16,19 * * * /usr/local/sbin/snapshot-rsync >/dev/null
### fsck -n
0 5 * * 0 /usr/local/sbin/fsck_server.sh
</pre>
 
Skript: /usr/local/sbin/fsck_server.sh
<pre>#!/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
 
fsck -s -A -N | cut -d] -f2 | cut -d\  -f3 | grep '^/dev/' | xargs fsck -n | grep '^/dev/'
</pre>
 
= Konfiguration =
Die Konfiguration erfolgt im Skript im obersten Abschnitt.
 
Das Backup-Skript sichert hierhin: ''/srv/backup/snapshot''
<pre>
# This is the local root of the backup directories. (where to backup to)
# backuproot must be the mount point and will be mounted ro/rw
backuproot=/srv/backup
 
# root directory for snapshots $backuproot/$snaproot
snaproot="snapshot"
</pre>
 
Das Backup-Skript '''archiviert''' die Backups wie folgt:
archiviere die letzten
* 3x Snapshot-Sicherungen, plus
* 6x Tages-Sicherungen, plus
* 4x Wochen-Sicherungen, plus
* 12x Monats-Sicherungen, plus
* 10x Jahres-Sicherungen
 
<pre>
# number of snapshots to archive
savehours=3
savedays=6
saveweeks=4
savemonths=12
saveyears=10</pre>
 
Folgende '''Verzeichnisse''' werden gesichert:
<pre>
# list directories to backup
allsrcdir="
/home/
/srv/
"</pre>
 
Diese Verzeichnisse werden '''nicht''' gesichert:
<pre>
# list directories to skip during in backup
# or leave blank
# EXCLUDES=""
 
EXCLUDES="--filter=. /tmp/excludes-${snaproot}"
 
cat > /tmp/excludes-${snaproot} << EOF
- lost+found
- \$RECYCLE.BIN
- temp
- Temp
- Downloads
- .univention-skel
- System Volumen Information
+ *
EOF
</pre>
 
Das ist das Ergebnis:
<pre>
<pre>
#!/bin/sh
root@ucsmail:/srv/backup/snapshot# ls -l *
# snapshot
-rw-r--r-- 1 root root    0 Dez  6 06:06 lastrun.time
lrwxrwxrwx 1 root root  47 Dez  6 06:05 latest -> /backup/snapshot/hourly/snapshot-2020-12-06__06
lrwxrwxrwx 1 root root  46 Dez  6 06:05 yesterday -> /backup/snapshot/daily/snapshot-2020-12-06__06
 
daily:
insgesamt 16
lrwxrwxrwx 1 root root  48 Dez  1 06:04 snapshot-2020-12-01__06 -> /backup/snapshot/monthly/snapshot-2020-12-01__06
drwxr-xr-x 3 root root 4096 Dez  2 06:04 snapshot-2020-12-02__06
drwxr-xr-x 3 root root 4096 Dez  3 06:04 snapshot-2020-12-03__06
drwxr-xr-x 3 root root 4096 Dez  4 06:04 snapshot-2020-12-04__06
drwxr-xr-x 3 root root 4096 Dez  5 06:04 snapshot-2020-12-05__06
lrwxrwxrwx 1 root root  47 Dez  6 06:05 snapshot-2020-12-06__06 -> /backup/snapshot/weekly/snapshot-2020-12-06__06
 
hourly:
insgesamt 8
drwxr-xr-x 3 root root 4096 Dez  5 16:04 snapshot-2020-12-05__16
drwxr-xr-x 3 root root 4096 Dez  5 19:04 snapshot-2020-12-05__19
lrwxrwxrwx 1 root root  46 Dez  6 06:05 snapshot-2020-12-06__06 -> /backup/snapshot/daily/snapshot-2020-12-06__06
 
monthly:
insgesamt 24
drwxr-xr-x 3 root root 4096 Jul  1 06:04 snapshot-2020-07-01__06
drwxr-xr-x 3 root root 4096 Aug  1 06:04 snapshot-2020-08-01__06
drwxr-xr-x 3 root root 4096 Sep  1 06:04 snapshot-2020-09-01__06
drwxr-xr-x 3 root root 4096 Okt  1 06:04 snapshot-2020-10-01__06
drwxr-xr-x 3 root root 4096 Nov  1 06:04 snapshot-2020-11-01__06
drwxr-xr-x 3 root root 4096 Dez  1 06:04 snapshot-2020-12-01__06
 
weekly:
insgesamt 16
drwxr-xr-x 3 root root 4096 Nov 15 06:04 snapshot-2020-11-15__06
drwxr-xr-x 3 root root 4096 Nov 22 06:04 snapshot-2020-11-22__06
drwxr-xr-x 3 root root 4096 Nov 29 06:04 snapshot-2020-11-29__06
drwxr-xr-x 3 root root 4096 Dez  6 06:04 snapshot-2020-12-06__06
 
yearly:
insgesamt 0
</pre>
 
= snapshot-rsync Script =
 
<pre>
#!/bin/bash
# snapshot-rsync
# make a snapshot from directories
# make a snapshot from directories
# an create hourly/daily/monthly/yearly archieves
# an create hourly/daily/monthly/yearly archieves
Zeile 10: Zeile 128:
# ...
# ...
# ...
# ...
# The directories are named 'snapshot-<year>-<month>-<day>-<hour>'
# The directories are named 'snapshot-<year>-<month>-<day>__<hour>'
#
#
# Each time snapshot runs, it date stamps a file in the <snapshot> directory called
# Each time snapshot runs, it date stamps a file in the <snapshot> directory called
Zeile 16: Zeile 134:
# date and time snapshot ran on that host.
# date and time snapshot ran on that host.
#
#
# The last thing you need to do is add snapshot in your crontab with the proper
# The last thing you need to do is add snapshot-rsync in your crontab with the proper
# times and switches.
# times and switches.
#
#
Zeile 27: Zeile 145:
# you get the idea
# you get the idea
# ...
# ...
#########################################################################
#########################################################################
# Start User Config Stuff
# Start User Config Stuff
snapshot="srv1-data"
snaphost=""            # localhost


# This is the local root of the backup directories. (where to backup to)
# This is the local root of the backup directories. (where to backup to)
# backuproot must be the mount point and will be mounted ro/rw
backuproot=/backup
backuproot=/backup


# You need to set the newdayhour to 00-23 depending on what hour you run
# exit if $backuproot is no Mount-Point
# the script in cron.
mount | grep -q "$backuproot " || exit 0
# 1 4,16,19 * * * /usr/local/sbin/snapshot-srv1
newdayhour=04


# number of snapshots to save
# root directory for snapshots $backuproot/$snaproot
savehours=3
snaproot="snapshot"
savedays=7
 
saveweeks=4
# [remote] host to backup or ""
savemonths=12
snaphost=""
saveyears=10


# --------------------------
# list directories to backup
# list directories to backup
# --------------------------
allsrcdir="
allsrcdir="
/home/
/srv/daten
/srv/
/var/lib/cyrus/
/var/spool/
/var/www/
"
"


# -----------------------------------------
# list directories to skip during in backup
# list directories to skip during in backup
# or leave blank
# or leave blank
# EXCLUDES=""
# EXCLUDES=""
# -----------------------------------------


EXCLUDES="--filter=. /tmp/excludes-${snapshot}"
EXCLUDES="--filter=. /tmp/excludes-${snaproot}"


cat > /tmp/excludes-${snapshot} << EOF
cat > /tmp/excludes-${snaproot} << EOF
- lost+found
- lost+found
- /backup/
- \$RECYCLE.BIN
- /snapshot/
- temp
- /var/spool/squid/
- Temp
- /var/spool/samba/
- Downloads
- .univention-skel
- System Volumen Information
+ *
+ *
EOF
EOF


# archivehour: hour (2 digits) when the snapshot will be moved to archive dirs
# daily, weekly, monthly, yearly
archivehour=06


# Mount and Dismount commands for all reasons are in the following functions
# number of snapshots to archive
# you can also mount windows-shares via smbclient e.g.
savehours=3
# here: mount for writing during backup, and mount readonly afterwards
savedays=6
 
saveweeks=4
mounting ()
savemonths=12
{
saveyears=10
    precom=0
    mount -o remount,rw ${backuproot} || mountfail
}
 
umounting ()
{
    postcom=0
    mount -o remount,ro ${backuproot} || umountfail
}
 
# Typical Unix saving localhost
if [ -n "snaphost" ]; then
    rsync="rsync -a -R -q --delete --numeric-ids -e ssh"
else
    rsync="rsync -a -R -q --delete"
fi
 
  # Typical Unix using ssh and public keys
  # rsync="rsync -aR -q  --numeric-ids -e ssh --delete"
  # This has settings for windows and expects to use a mounted share.
  # rsync="rsync -a -R -q --delete --modify-window=10"


# End User Config Stuff
# End User Config Stuff
############################################################################
############################################################################
# Start Static Code
# Start Static Code
PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin


cmdline=$1
cmdline=$1
PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
lockfile=${backuproot}/${snaproot}/syncing-now
 
# Typical Unix saving localhost
rsync="rsync -a -R -q --delete"
[ -n "${snaphost}" ] && rsync="${rsync} --numeric-ids -e ssh"


cmonth=`date +'%m'`
cmonth=`date +'%m'`
doweek=`date +'%w'`
doweek=`date +'%w'`
  cday=`date +'%d'`
cday=`date +'%d'`
chour=`date +'%H'`
chour=`date +'%H'`


  yeardir=${backuproot}/${snapshot}/yearly
  yeardir=${backuproot}/${snaproot}/yearly
monthdir=${backuproot}/${snapshot}/monthly
monthdir=${backuproot}/${snaproot}/monthly
  weekdir=${backuproot}/${snapshot}/weekly
  weekdir=${backuproot}/${snaproot}/weekly
   daydir=${backuproot}/${snapshot}/daily
   daydir=${backuproot}/${snaproot}/daily
  hourdir=${backuproot}/${snapshot}/hourly
  hourdir=${backuproot}/${snaproot}/hourly


snapshotdir=`date +'snapshot-%Y-%m-%d-%H'`
dosync ()
 
lockfile=${backuproot}/${snapshot}/syncing-now
 
lsync=`/bin/ls -1r ${hourdir} | head -1`
lday=`date +'snapshot-%Y-%m-%d-%H' -d '1 day ago'`
lweek=`date +'snapshot-%Y-%m-%d-%H' -d '1 week ago'`
 
makedirs ()
{
{
     [ -d ${yeardir} ]  || mkdir -p ${yeardir}
     # search a snapshot-base for rsync
    [ -d ${monthdir} ] || mkdir -p ${monthdir}
    for dir in ${hourdir} ${daydir} ${weekdir} ${monthdir} ${yeardir}; do
    [ -d ${weekdir} ]  || mkdir -p ${weekdir}
      sync=`/bin/ls -1 ${dir} | tail -1`
    [ -d ${daydir} ]   || mkdir -p ${daydir}
      if [ -n "${sync}" ]; then
    [ -d ${hourdir} ]  || mkdir -p ${hourdir}
        rsync="${rsync} --link-dest=${dir}/${sync}"
}
        break
      fi
    done


dosync ()
     touch $lockfile
{
     [ -d ${hourdir}/${snapshotdir} ] || mkdir -p ${hourdir}/${snapshotdir}
    [ -n "${lsync}" ] && rsync="${rsync} --link-dest=${hourdir}/${lsync}"


     for srcdir in ${allsrcdir}; do
     for srcdir in ${allsrcdir}; do
       if [ -n "$snaphost" ]; then
       if [ -n "${snaphost}" ]; then
         srcdir=${snaphost}:${srcdir}
         srcdir=${snaphost}:${srcdir}
       fi
       fi
       ${rsync} "${EXCLUDES}" ${srcdir} ${hourdir}/${snapshotdir}
       ${rsync} "${EXCLUDES}" ${srcdir} ${snapdir}.rsync
     done
     done
    [ -e ${snapdir} ] && rm -rf ${snapdir}
    mv ${snapdir}.rsync ${snapdir}
    [ -e ${backuproot}/${snaproot}/latest ] && rm ${backuproot}/${snaproot}/latest
    ln -s ${snapdir} ${backuproot}/${snaproot}/latest
    rm -f $lockfile
}
}


doyearly ()
movesnap ()
{
{
     [ ${saveyears} -eq 0 ] && return
     snap=`date +'snapshot-%Y-%m-%d__'`${archivehour}
    if [ -d ${monthdir}/${snapshotdir} ]; then
      cp -alf  ${monthdir}/${snapshotdir} ${yeardir}
    else
      echo >&2 "I can't find snapshot ${monthdir}/${snapshotdir}..."
    fi
}


domonthly ()
    case "$1" in
{
        d)
    [ ${savemonths} -eq 0 ] && return
          dir=$daydir
    if [ -d ${hourdir}/${snapshotdir} ]; then
          nr=$savedays
      mv ${hourdir}/${snapshotdir} ${monthdir}
          from=$hourdir
      ln -s ${monthdir}/${snapshotdir} ${hourdir}/${snapshotdir}
          ;;
    else
        w)
      echo >&2 "I can't find snapshot ${hourdir}/${snapshotdir}..."
          dir=$weekdir
     fi
          nr=$saveweeks
}
          from=$daydir
          ;;
        m)
          dir=$monthdir
          nr=$savemonths
          if [ "$doweek" -eq 0 ]; then
              from=$weekdir
          else
              from=$daydir
          fi
          ;;
        y)
          dir=$yeardir
          nr=$saveyears
          from=$monthdir
          ;;
        *)
          echo >&2 "movesnap: unknow option $1, aborting..."
          rm -f ${lockfile}
          rm -f /tmp/excludes-${snaproot}
          umounting
          exit 1
          ;;
     esac
    [ ${nr} -eq 0 ] && return


doweekly ()
     if [ ! -e "${from}/`date +'snapshot-%Y-%m-%d__'`${archivehour}" ]; then
{
        snap=`/bin/ls -1 ${from} | tail -1`
    [ ${saveweeks} -eq 0 ] && return
     if [ -d ${daydir}/${lweek} ]; then
      mv ${daydir}/${lweek} ${weekdir}
    else
      echo >&2 "I can't find snapshot ${daydir}/${lweek}..."
     fi
     fi
}
    if [ -d ${from}/${snap} ]; then
 
      [ -e ${dir}/${snap} ] && rm -rf ${dir}/${snap}
dodaily ()
      mv ${from}/${snap} ${dir}
{
      ln -s ${dir}/${snap} ${from}
    [ ${savedays} -eq 0 ] && return
      if [ "$1" = "d" ]; then
    if [ -d ${hourdir}/${lday} ]; then
        [ -e ${backuproot}/${snaproot}/yesterday ] && rm ${backuproot}/${snaproot}/yesterday
      mv ${hourdir}/${lday} ${daydir}
        ln -s ${dir}/${snap} ${backuproot}/${snaproot}/yesterday
      fi
     else
     else
       echo >&2 "I can't find snapshot ${hourdir}/${lday}..."
       echo >&2 "I can't find snapshot ${from}/${snap}..."
     fi
     fi
}
}
Zeile 199: Zeile 305:
     count=0
     count=0
     for i in `/bin/ls -r ${hourdir}`; do
     for i in `/bin/ls -r ${hourdir}`; do
       let count=count+1
       ((count++))
       if [ ${count} -gt ${savehours} ]; then
       if [ ${count} -gt ${savehours} ]; then
         rm -Rf ${hourdir}/${i}
         rm -Rf ${hourdir}/${i}
Zeile 205: Zeile 311:
     done
     done


    [ ${saveweeks} -gt 0 -a ${savedays} -lt 7 ] && savedays=7
     count=0
     count=0
     for i in `/bin/ls -r ${daydir}`; do
     for i in `/bin/ls -r ${daydir}`; do
       let count=count+1
       ((count++))
       if [ ${count} -gt ${savedays} ]; then
       if [ ${count} -gt ${savedays} ]; then
         rm -Rf ${daydir}/${i}
         rm -Rf ${daydir}/${i}
Zeile 216: Zeile 321:
     count=0
     count=0
     for i in `/bin/ls -r ${weekdir}`; do
     for i in `/bin/ls -r ${weekdir}`; do
       let count=count+1
       ((count++))
       if [ ${count} -gt ${saveweeks} ]; then
       if [ ${count} -gt ${saveweeks} ]; then
         rm -Rf ${weekdir}/${i}
         rm -Rf ${weekdir}/${i}
Zeile 224: Zeile 329:
     count=0
     count=0
     for i in `/bin/ls -r ${monthdir}`; do
     for i in `/bin/ls -r ${monthdir}`; do
       let count=count+1
       ((count++))
       if [ ${count} -gt ${savemonths} ]; then
       if [ ${count} -gt ${savemonths} ]; then
         rm -Rf ${monthdir}/${i}
         rm -Rf ${monthdir}/${i}
Zeile 232: Zeile 337:
     count=0
     count=0
     for i in `/bin/ls -r ${yeardir}`; do
     for i in `/bin/ls -r ${yeardir}`; do
       let count=count+1
       ((count++))
       if [ ${count} -gt ${saveyears} ]; then
       if [ ${count} -gt ${saveyears} ]; then
         rm -Rf ${yeardir}/${i}
         rm -Rf ${yeardir}/${i}
Zeile 241: Zeile 346:
inuse ()
inuse ()
{
{
   echo >&2 "I am already syncing snapshot ${snapshot}"
   echo >&2 "I am already syncing snapshot ${snaproot}"
   exit 1
   exit 1
}
}
Zeile 255: Zeile 360:
   echo >&2 "I can't unmount filesystem ${backuproot}"
   echo >&2 "I can't unmount filesystem ${backuproot}"
   exit 1
   exit 1
}
mounting ()
{
    mount -o remount,rw ${backuproot} || mountfail
}
umounting ()
{
    mount -o remount,ro ${backuproot} || umountfail
}
}


Zeile 263: Zeile 378:
[ -f ${lockfile} ] && inuse
[ -f ${lockfile} ] && inuse
mounting
mounting
makedirs
 
touch ${lockfile}
for dir in ${hourdir} ${daydir} ${weekdir} ${monthdir} ${yeardir}; do
  [ -d ${dir} ] || (echo "mkdir ${dir}"; mkdir -p ${dir})
done
 
snap=`date +'snapshot-%Y-%m-%d__%H'`
snapdir=${hourdir}/${snap}


case ${cmdline} in
case ${cmdline} in
   -y)
   -y)
     doyearly
     dosync
    movesnap "y"
     docleanup
     docleanup
     ;;
     ;;
   -m)
   -m)
     domonthly
     dosync
    movesnap "m"
    docleanup
    ;;
  -w)
    dosync
    movesnap "w"
    docleanup
    ;;
  -d)
    dosync
    movesnap "d"
     docleanup
     docleanup
     ;;
     ;;
  *)
  *)
     dosync
     dosync
     if [ ${newdayhour} -eq ${chour} ]; then
    if [ ! -e "${hourdir}/`date +'snapshot-%Y-%m-%d__'`${archivehour}" ]; then
       dodaily
        archivehour=`/bin/ls -1 ${hourdir} | tail -1 | cut -d_ -f3 | cut -d. -f1`
    fi
     if [ ${archivehour} -eq ${chour} ]; then
       movesnap "d"
       if [ ${doweek} -eq 0 ]; then
       if [ ${doweek} -eq 0 ]; then
         doweekly
         movesnap "w"
       fi
       fi
       if [ ${cday} -eq 01 ]; then
       if [ ${cday} -eq 01 ]; then
         domonthly
         movesnap "m"
         if [ ${cmonth} -eq 01 ]; then
         if [ ${cmonth} -eq 01 ]; then
           doyearly
           movesnap "y"
         fi
         fi
       fi
       fi
     fi
     fi
     docleanup
     docleanup
  ;;
    ;;
esac
esac


touch ${backuproot}/${snapshot}/lastrun.time
[ ! -e ${backuproot}/${snaproot}/yesterday ] && \
rm -f ${lockfile}
  ln -s ${backuproot}/${snaproot}/latest ${backuproot}/${snaproot}/yesterday
rm -f /tmp/excludes-${snapshot}
 
touch ${backuproot}/${snaproot}/lastrun.time
rm -f /tmp/excludes-${snaproot}


umounting
umounting
echo "Backup for ${snapshot} is complete..."
echo "Backup for ${snaproot} is complete..."
</pre>
</pre>

Aktuelle Version vom 14. Dezember 2020, 20:03 Uhr

Ich sichere 3x täglich per Snapshot meine Daten mit folgendem Script. Zusätzlich führe ich einen Filesystemcheck auf /backup aus (cronjobs).

Installation

Der Cronjob:

### Daten-Server Backup
4 6,16,19 * * * /usr/local/sbin/snapshot-rsync >/dev/null
### fsck -n
0 5 * * 0 /usr/local/sbin/fsck_server.sh

Skript: /usr/local/sbin/fsck_server.sh

#!/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

fsck -s -A -N | cut -d] -f2 | cut -d\  -f3 | grep '^/dev/' | xargs fsck -n | grep '^/dev/'

Konfiguration

Die Konfiguration erfolgt im Skript im obersten Abschnitt.

Das Backup-Skript sichert hierhin: /srv/backup/snapshot

# This is the local root of the backup directories. (where to backup to)
# backuproot must be the mount point and will be mounted ro/rw
backuproot=/srv/backup

# root directory for snapshots $backuproot/$snaproot
snaproot="snapshot"

Das Backup-Skript archiviert die Backups wie folgt: archiviere die letzten

  • 3x Snapshot-Sicherungen, plus
  • 6x Tages-Sicherungen, plus
  • 4x Wochen-Sicherungen, plus
  • 12x Monats-Sicherungen, plus
  • 10x Jahres-Sicherungen
# number of snapshots to archive
savehours=3
savedays=6
saveweeks=4
savemonths=12
saveyears=10

Folgende Verzeichnisse werden gesichert:

# list directories to backup
allsrcdir="
/home/
/srv/
"

Diese Verzeichnisse werden nicht gesichert:

# list directories to skip during in backup
# or leave blank
# EXCLUDES=""

EXCLUDES="--filter=. /tmp/excludes-${snaproot}"

cat > /tmp/excludes-${snaproot} << EOF
- lost+found
- \$RECYCLE.BIN
- temp
- Temp
- Downloads
- .univention-skel
- System Volumen Information
+ *
EOF

Das ist das Ergebnis:

root@ucsmail:/srv/backup/snapshot# ls -l *
-rw-r--r-- 1 root root    0 Dez  6 06:06 lastrun.time
lrwxrwxrwx 1 root root   47 Dez  6 06:05 latest -> /backup/snapshot/hourly/snapshot-2020-12-06__06
lrwxrwxrwx 1 root root   46 Dez  6 06:05 yesterday -> /backup/snapshot/daily/snapshot-2020-12-06__06

daily:
insgesamt 16
lrwxrwxrwx 1 root root   48 Dez  1 06:04 snapshot-2020-12-01__06 -> /backup/snapshot/monthly/snapshot-2020-12-01__06
drwxr-xr-x 3 root root 4096 Dez  2 06:04 snapshot-2020-12-02__06
drwxr-xr-x 3 root root 4096 Dez  3 06:04 snapshot-2020-12-03__06
drwxr-xr-x 3 root root 4096 Dez  4 06:04 snapshot-2020-12-04__06
drwxr-xr-x 3 root root 4096 Dez  5 06:04 snapshot-2020-12-05__06
lrwxrwxrwx 1 root root   47 Dez  6 06:05 snapshot-2020-12-06__06 -> /backup/snapshot/weekly/snapshot-2020-12-06__06

hourly:
insgesamt 8
drwxr-xr-x 3 root root 4096 Dez  5 16:04 snapshot-2020-12-05__16
drwxr-xr-x 3 root root 4096 Dez  5 19:04 snapshot-2020-12-05__19
lrwxrwxrwx 1 root root   46 Dez  6 06:05 snapshot-2020-12-06__06 -> /backup/snapshot/daily/snapshot-2020-12-06__06

monthly:
insgesamt 24
drwxr-xr-x 3 root root 4096 Jul  1 06:04 snapshot-2020-07-01__06
drwxr-xr-x 3 root root 4096 Aug  1 06:04 snapshot-2020-08-01__06
drwxr-xr-x 3 root root 4096 Sep  1 06:04 snapshot-2020-09-01__06
drwxr-xr-x 3 root root 4096 Okt  1 06:04 snapshot-2020-10-01__06
drwxr-xr-x 3 root root 4096 Nov  1 06:04 snapshot-2020-11-01__06
drwxr-xr-x 3 root root 4096 Dez  1 06:04 snapshot-2020-12-01__06

weekly:
insgesamt 16
drwxr-xr-x 3 root root 4096 Nov 15 06:04 snapshot-2020-11-15__06
drwxr-xr-x 3 root root 4096 Nov 22 06:04 snapshot-2020-11-22__06
drwxr-xr-x 3 root root 4096 Nov 29 06:04 snapshot-2020-11-29__06
drwxr-xr-x 3 root root 4096 Dez  6 06:04 snapshot-2020-12-06__06

yearly:
insgesamt 0

snapshot-rsync Script

#!/bin/bash
# snapshot-rsync
# make a snapshot from directories
# an create hourly/daily/monthly/yearly archieves
# ---------
# neobiker (2006)
# originally based on mirror Version 3.11 By Stu Sheldon stu@actusa.net
# ...
# ...
# The directories are named 'snapshot-<year>-<month>-<day>__<hour>'
#
# Each time snapshot runs, it date stamps a file in the <snapshot> directory called
# 'lastrun.time'. This file's date when listing it using ls -laF shows the last
# date and time snapshot ran on that host.
#
# The last thing you need to do is add snapshot-rsync in your crontab with the proper
# times and switches.
#
# If you are going for hourly sync's, add the following to your crontab:
# 0 * * * *    /usr/local/sbin/snapshot
#
# Every four hours would be:
# 0 0,4,8,12,16,20  * * *    /usr/local/sbin/snapshot
#
# you get the idea
# ...

#########################################################################
# Start User Config Stuff

# This is the local root of the backup directories. (where to backup to)
# backuproot must be the mount point and will be mounted ro/rw
backuproot=/backup

# exit if $backuproot is no Mount-Point
mount | grep -q "$backuproot " || exit 0

# root directory for snapshots $backuproot/$snaproot
snaproot="snapshot"

# [remote] host to backup or ""
snaphost=""

# list directories to backup
allsrcdir="
/srv/daten
"

# list directories to skip during in backup
# or leave blank
# EXCLUDES=""

EXCLUDES="--filter=. /tmp/excludes-${snaproot}"

cat > /tmp/excludes-${snaproot} << EOF
- lost+found
- \$RECYCLE.BIN
- temp
- Temp
- Downloads
- .univention-skel
- System Volumen Information
+ *
EOF

# archivehour: hour (2 digits) when the snapshot will be moved to archive dirs
# daily, weekly, monthly, yearly
archivehour=06

# number of snapshots to archive
savehours=3
savedays=6
saveweeks=4
savemonths=12
saveyears=10

# End User Config Stuff
############################################################################
# Start Static Code
PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin

cmdline=$1
lockfile=${backuproot}/${snaproot}/syncing-now

# Typical Unix saving localhost
rsync="rsync -a -R -q --delete"
[ -n "${snaphost}" ] && rsync="${rsync} --numeric-ids -e ssh"

cmonth=`date +'%m'`
doweek=`date +'%w'`
cday=`date +'%d'`
chour=`date +'%H'`

 yeardir=${backuproot}/${snaproot}/yearly
monthdir=${backuproot}/${snaproot}/monthly
 weekdir=${backuproot}/${snaproot}/weekly
  daydir=${backuproot}/${snaproot}/daily
 hourdir=${backuproot}/${snaproot}/hourly

dosync ()
{
    # search a snapshot-base for rsync
    for dir in ${hourdir} ${daydir} ${weekdir} ${monthdir} ${yeardir}; do
      sync=`/bin/ls -1 ${dir} | tail -1`
      if [ -n "${sync}" ]; then
        rsync="${rsync} --link-dest=${dir}/${sync}"
        break
      fi
    done

    touch $lockfile

    for srcdir in ${allsrcdir}; do
      if [ -n "${snaphost}" ]; then
        srcdir=${snaphost}:${srcdir}
      fi
      ${rsync} "${EXCLUDES}" ${srcdir} ${snapdir}.rsync
    done
    [ -e ${snapdir} ] && rm -rf ${snapdir}
    mv ${snapdir}.rsync ${snapdir}
    [ -e ${backuproot}/${snaproot}/latest ] && rm ${backuproot}/${snaproot}/latest
    ln -s ${snapdir} ${backuproot}/${snaproot}/latest

    rm -f $lockfile
}

movesnap ()
{
    snap=`date +'snapshot-%Y-%m-%d__'`${archivehour}

    case "$1" in
        d)
           dir=$daydir
           nr=$savedays
           from=$hourdir
           ;;
        w)
           dir=$weekdir
           nr=$saveweeks
           from=$daydir
           ;;
        m)
           dir=$monthdir
           nr=$savemonths
           if [ "$doweek" -eq 0 ]; then
               from=$weekdir
           else
               from=$daydir
           fi
           ;;
        y)
           dir=$yeardir
           nr=$saveyears
           from=$monthdir
           ;;
        *)
           echo >&2 "movesnap: unknow option $1, aborting..."
           rm -f ${lockfile}
           rm -f /tmp/excludes-${snaproot}
           umounting
           exit 1
           ;;
    esac
    [ ${nr} -eq 0 ] && return

    if [ ! -e "${from}/`date +'snapshot-%Y-%m-%d__'`${archivehour}" ]; then
        snap=`/bin/ls -1 ${from} | tail -1`
    fi
    if [ -d ${from}/${snap} ]; then
      [ -e ${dir}/${snap} ] && rm -rf ${dir}/${snap}
      mv ${from}/${snap} ${dir}
      ln -s ${dir}/${snap} ${from}
      if [ "$1" = "d" ]; then
        [ -e ${backuproot}/${snaproot}/yesterday ] && rm ${backuproot}/${snaproot}/yesterday
        ln -s ${dir}/${snap} ${backuproot}/${snaproot}/yesterday
      fi
    else
      echo >&2 "I can't find snapshot ${from}/${snap}..."
    fi
}

docleanup ()
{
    [ ${savehours} -lt 1 ] && savehours=1
    count=0
    for i in `/bin/ls -r ${hourdir}`; do
      ((count++))
      if [ ${count} -gt ${savehours} ]; then
        rm -Rf ${hourdir}/${i}
      fi
    done

    count=0
    for i in `/bin/ls -r ${daydir}`; do
      ((count++))
      if [ ${count} -gt ${savedays} ]; then
        rm -Rf ${daydir}/${i}
      fi
    done

    count=0
    for i in `/bin/ls -r ${weekdir}`; do
      ((count++))
      if [ ${count} -gt ${saveweeks} ]; then
        rm -Rf ${weekdir}/${i}
      fi
    done

    count=0
    for i in `/bin/ls -r ${monthdir}`; do
      ((count++))
      if [ ${count} -gt ${savemonths} ]; then
        rm -Rf ${monthdir}/${i}
      fi
    done

    count=0
    for i in `/bin/ls -r ${yeardir}`; do
      ((count++))
      if [ ${count} -gt ${saveyears} ]; then
        rm -Rf ${yeardir}/${i}
      fi
    done
}

inuse ()
{
  echo >&2 "I am already syncing snapshot ${snaproot}"
  exit 1
}

mountfail ()
{
  echo >&2 "I can't mount filesystem ${backuproot}"
  exit 1
}

umountfail ()
{
  echo >&2 "I can't unmount filesystem ${backuproot}"
  exit 1
}

mounting ()
{
    mount -o remount,rw ${backuproot} || mountfail
}

umounting ()
{
    mount -o remount,ro ${backuproot} || umountfail
}

####
#### Programm starts here ... ###########################
####

[ -f ${lockfile} ] && inuse
mounting

for dir in ${hourdir} ${daydir} ${weekdir} ${monthdir} ${yeardir}; do
  [ -d ${dir} ] || (echo "mkdir ${dir}"; mkdir -p ${dir})
done

snap=`date +'snapshot-%Y-%m-%d__%H'`
snapdir=${hourdir}/${snap}

case ${cmdline} in
  -y)
    dosync
    movesnap "y"
    docleanup
    ;;
  -m)
    dosync
    movesnap "m"
    docleanup
    ;;
  -w)
    dosync
    movesnap "w"
    docleanup
    ;;
  -d)
    dosync
    movesnap "d"
    docleanup
    ;;
   *)
    dosync
    if [ ! -e "${hourdir}/`date +'snapshot-%Y-%m-%d__'`${archivehour}" ]; then
        archivehour=`/bin/ls -1 ${hourdir} | tail -1 | cut -d_ -f3 | cut -d. -f1`
    fi
    if [ ${archivehour} -eq ${chour} ]; then
      movesnap "d"
      if [ ${doweek} -eq 0 ]; then
        movesnap "w"
      fi
      if [ ${cday} -eq 01 ]; then
        movesnap "m"
        if [ ${cmonth} -eq 01 ]; then
          movesnap "y"
        fi
      fi
    fi
    docleanup
    ;;
esac

[ ! -e ${backuproot}/${snaproot}/yesterday ] && \
  ln -s ${backuproot}/${snaproot}/latest ${backuproot}/${snaproot}/yesterday

touch ${backuproot}/${snaproot}/lastrun.time
rm -f /tmp/excludes-${snaproot}

umounting
echo "Backup for ${snaproot} is complete..."