chiark / gitweb /
rsync-backup.8, rsync-backup.in: New dry-run mode for testing logic.
authorMark Wooding <mdw@distorted.org.uk>
Fri, 14 Dec 2012 23:06:10 +0000 (23:06 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Fri, 14 Dec 2012 23:06:10 +0000 (23:06 +0000)
There's a tweak to retention policy coming up, and it turns out to be bad
to test such things on one's production backups.

rsync-backup.8
rsync-backup.in

index b36153a2def9f3a4f29da86b6aa82caf3f09c56f..20682ea90488481f467f7f5e2ebff75c5ad40e27 100644 (file)
@@ -7,7 +7,7 @@
 .TH rsync-backup 8 "7 October 2012" rsync-backup
 .SH SYNOPSIS
 .B rsync-backup
-.RB [ \-v ]
+.RB [ \-nv ]
 .RB [ \-c
 .IR config-file ]
 .SH DESCRIPTION
@@ -73,6 +73,10 @@ in the
 .B \-V
 output).
 .TP
+.B \-n
+Don't actually take a backup, or write proper logs: instead, write a
+description of what would be done to standard error.
+.TP
 .B \-v
 Produce verbose progress information on standard output while the backup
 is running.  This keeps one amused while running a backup
index ade72316736378a6b1551c0ed7286b91aada6ede..292c6ebefe869d5ab2f12d19286706c876abb927 100644 (file)
@@ -35,6 +35,7 @@ fshashdir=@fshashdir@
 conf=@sysconfdir@/rsync-backup.conf
 
 verbose=:
+dryrun=nil
 
 ###--------------------------------------------------------------------------
 ### Utility functions.
@@ -57,26 +58,51 @@ do_rsync () {
 }
 
 log () {
-  now=$(date +"%Y-%m-%d %H:%M:%S %z")
-  echo >&9 "$now $*"
+  case $dryrun in
+    t)
+      echo >&2 "               *** $*"
+      ;;
+    nil)
+      now=$(date +"%Y-%m-%d %H:%M:%S %z")
+      echo >&9 "$now $*"
+      ;;
+  esac
+}
+
+maybe () {
+  ## Run CMD, if this isn't a dry run.
+
+  case $dryrun in
+    t) echo >&2 "              +++ $*" ;;
+    nil) "$@" ;;
+  esac
 }
 
 run () {
   tag=$1 cmd=$2; shift 2
   ## Run CMD, logging its output in a pleasing manner.
 
-  log "BEGIN $tag"
-  rc=$(
-    { { { ( set +e
-           "$cmd" "$@" 3>&- 4>&- 5>&- 9>&-
-           echo $? >&5; ) |
-         while IFS= read line; do echo "| $line"; done >&4; } 2>&1 |
-       while IFS= read line; do echo "* $line"; done >&4; } 4>&1 |
-      cat >&9; } 5>&1 </dev/null
-  )
-  case $rc in
-    0) log "END $tag" ;;
-    *) log "FAIL $tag (rc = $rc)" ;;
+  case $dryrun in
+    t)
+      echo >&2 "               *** RUN $tag"
+      echo >&2 "               +++ $cmd $*"
+      rc=0
+      ;;
+    nil)
+      log "BEGIN $tag"
+      rc=$(
+       { { { ( set +e
+               "$cmd" "$@" 3>&- 4>&- 5>&- 9>&-
+               echo $? >&5; ) |
+             while IFS= read line; do echo "| $line"; done >&4; } 2>&1 |
+           while IFS= read line; do echo "* $line"; done >&4; } 4>&1 |
+         cat >&9; } 5>&1 </dev/null
+      )
+      case $rc in
+       0) log "END $tag" ;;
+       *) log "FAIL $tag (rc = $rc)" ;;
+      esac
+      ;;
   esac
   return $rc
 }
@@ -488,11 +514,17 @@ expire_backups () {
     done; } |
   expire |
   while read op date; do
-    case $op in
-      RETAIN)
+    case $op,$dryrun in
+      RETAIN,t)
+       echo >&2 "              --- keep   $date"
+       ;;
+      EXPIRE,t)
+       echo >&2 "              --- delete $date"
+       ;;
+      RETAIN,nil)
        echo "keep   $date"
        ;;
-      EXPIRE)
+      EXPIRE,nil)
        echo "delete $date"
        $verbose -n "   expire $date..."
        rm -rf $date $date.*
@@ -530,7 +562,15 @@ do_backup () {
   while :; do
 
     ## Create and mount the remote snapshot.
-    snapmnt=$(snap_$snap $snapargs $fs $fsarg) || return $?
+    case $dryrun in
+      t)
+       maybe snap_$snap $fs $fsarg
+       snapmnt="<snapshot>"
+       ;;
+      nil)
+       snapmnt=$(snap_$snap $snapargs $fs $fsarg) || return $?
+       ;;
+    esac
     $verbose " create snapshot"
 
     ## Build the list of hardlink sources.
@@ -541,8 +581,11 @@ do_backup () {
     done
 
     ## Copy files from the remote snapshot.
-    mkdir -p new/
-    $verbose -n "      running rsync..."
+    maybe mkdir -p new/
+    case $dryrun in
+      t) $verbose "    running rsync" ;;
+      nil) $verbose -n "       running rsync..." ;;
+    esac
     set +e
     run "RSYNC of $host:$fs (snapshot on $snapmnt)" do_rsync \
       $linkdests \
@@ -550,18 +593,21 @@ do_backup () {
       $snapmnt/ new/
     rc_rsync=$?
     set -e
-    $verbose " done"
+    case $dryrun in nil) $verbose " done" ;; esac
 
     ## Collect a map of the snapshot for verification purposes.
     set +e
-    $verbose -n "      remote fshash..."
+    case $dryrun in
+      t) $verbose "    remote fshash" ;;
+      nil) $verbose -n "       remote fshash..." ;;
+    esac
     run "@$host: fshash $fs" remote_fshash
     rc_fshash=$?
     set -e
-    $verbose " done"
+    case $dryrun in nil) $verbose " done" ;; esac
 
     ## Remove the snapshot.
-    unsnap_$snap $snapargs $fs $fsarg
+    maybe unsnap_$snap $snapargs $fs $fsarg
     $verbose " remove snapshot"
 
     ## If we failed to copy, then give up.
@@ -572,11 +618,14 @@ do_backup () {
     esac
 
     ## Get a matching map of the files received.
-    mkdir -m750 -p $STOREDIR/tmp
+    maybe mkdir -m750 -p $STOREDIR/tmp/
     localmap=$STOREDIR/tmp/fshash.$host.$fs.$date
-    $verbose -n "      local fshash..."
+    case $dryrun in
+      t) $verbose "    local fshash" ;;
+      nil) $verbose -n "       local fshash..." ;;
+    esac
     run "local fshash $host:$fs" local_fshash || return $?
-    $verbose " done"
+    case $dryrun in nil) $verbose " done" ;; esac
 
     ## Compare the two maps.
     set +e
@@ -599,27 +648,35 @@ do_backup () {
   done
 
   ## Glorious success.
-  rm -f $localmap
+  maybe rm -f $localmap
   $verbose "   fshash match"
 
   ## Commit this backup.
-  backup_precommit_hook $host $fs $date
-  mv new $date
-  mv new.fshash $date.fshash
-  backup_commit_hook $host $fs $date
-  mkdir hack
-  ln -s $date hack/last
-  mv hack/last .
-  rmdir hack
+  case $dryrun in
+    nil)
+      backup_precommit_hook $host $fs $date
+      mv new $date
+      mv new.fshash $date.fshash
+      backup_commit_hook $host $fs $date
+      mkdir hack
+      ln -s $date hack/last
+      mv hack/last .
+      rmdir hack
+      ;;
+  esac
   $verbose "   commit"
 
   ## Expire old backups.
-  case "${expire_policy+t}" in
-    t) run "expiry for $host:$fs" expire_backups ;;
+  case "${expire_policy+t},$dryrun" in
+    t,nil) run "expiry for $host:$fs" expire_backups ;;
+    t,t) expire_backups ;;
   esac
 
   ## Report success.
-  log "SUCCESSFUL BACKUP of $host:$fs"
+  case $dryrun in
+    t) log "END BACKUP of $host:$fs" ;;
+    nil) log "SUCCESSFUL BACKUP of $host:$fs" ;;
+  esac
 }
 
 backup () {
@@ -648,19 +705,23 @@ backup () {
 
     ## Move to the store directory and set up somewhere to put this backup.
     cd $STOREDIR
-    if [ ! -d $host ]; then
-      mkdir -m755 $host
-      chown root:root $host
-    fi
-    if [ ! -d $host/$fs ]; then
-      mkdir -m750 $host/$fs
-      chown root:backup $host/$fs
-    fi
+    case $dryrun in
+      nil)
+       if [ ! -d $host ]; then
+         mkdir -m755 $host
+         chown root:root $host
+       fi
+       if [ ! -d $host/$fs ]; then
+         mkdir -m750 $host/$fs
+         chown root:backup $host/$fs
+       fi
+       ;;
+    esac
     cd $host/$fs
 
     ## Find out if we've already copied this filesystem today.
     date=$(date +%Y-%m-%d)
-    if [ -d $date ]; then
+    if [ $dryrun = nil ] && [ -d $date ]; then
       $verbose "       already dumped"
       continue
     fi
@@ -669,16 +730,23 @@ backup () {
     ## deleted old logs from today, so just checking for an unused sequence
     ## number is insufficient.  Instead, check all of the logfiles for today,
     ## and use a sequence number that's larger than any of them.
-    seq=1
-    for i in "$logdir/$host/$fs.$date#"*; do
-      tail=${i##*#}
-      case "$tail" in [!1-9]* | *[!0-9]*) continue ;; esac
-      if [ -f "$i" -a $tail -ge $seq ]; then seq=$(( tail + 1 )); fi
-    done
-    log="$logdir/$host/$fs.$date#$seq"
+    case $dryrun in
+      t)
+       log=/dev/null
+       ;;
+      nil)
+       seq=1
+       for i in "$logdir/$host/$fs.$date#"*; do
+         tail=${i##*#}
+         case "$tail" in [!1-9]* | *[!0-9]*) continue ;; esac
+         if [ -f "$i" -a $tail -ge $seq ]; then seq=$(( tail + 1 )); fi
+       done
+       log="$logdir/$host/$fs.$date#$seq"
+       ;;
+    esac
 
     ## Do the backup of this filesystem.
-    mkdir -p $logdir/$host
+    case $dryrun in nil) mkdir -p $logdir/$host ;; esac
     if ! do_backup $date $fs $fsarg 9>$log 1>&9; then
       echo >&2
       echo >&2 "$quis: backup of $host:$fs FAILED!"
@@ -693,7 +761,7 @@ backup () {
     done
 
     ## If there are too many, go through and delete some early ones.
-    if [ $nlog -gt $MAXLOG ]; then
+    if [ $dryrun = nil ] && [ $nlog -gt $MAXLOG ]; then
       n=$(( nlog - MAXLOG ))
       for i in "$logdir/$host/$fs".*; do
        if [ ! -f "$i" ]; then continue; fi
@@ -742,12 +810,13 @@ EOF
 
 whine () { echo >&8 "$@"; }
 
-while getopts "hVvc:" opt; do
+while getopts "hVvc:n" opt; do
   case "$opt" in
     h) usage; exit 0 ;;
     V) version; config; exit 0 ;;
     v) verbose=whine ;;
     c) conf=$OPTARG ;;
+    n) dryrun=t ;;
     *) exit 1 ;;
   esac
 done