rsync-backup.in, rsync-backup.8: Trim caches on fshash mismatch.
[rsync-backup] / rsync-backup.in
index d7267ca..2c1e3b6 100644 (file)
@@ -83,6 +83,14 @@ copy () {
 }
 
 run () {
+  stdinp=nil
+  while :; do
+    case $1 in
+      -stdin) stdinp=t; shift ;;
+      --) shift; break ;;
+      *) break ;;
+    esac
+  done
   tag=$1 cmd=$2; shift 2
   ## Run CMD, logging its output in a pleasing manner.
 
@@ -95,12 +103,13 @@ run () {
     nil)
       log "BEGIN $tag"
       rc=$(
+       case $stdinp in nil) exec </dev/null ;; esac
        { { { ( set +e
                "$cmd" "$@" 3>&- 4>&- 5>&- 9>&-
                echo $? >&5; ) |
              copy "|" >&4; } 2>&1 |
            copy "*" >&4; } 4>&1 |
-         cat >&9; } 5>&1 </dev/null
+         cat >&9; } 5>&1
       )
       case $rc in
        0) log "END $tag" ;;
@@ -111,6 +120,15 @@ run () {
   return $rc
 }
 
+run_diff () {
+  out=$1 old=$2 new=$3
+  ## Write a unified diff from OLD to NEW, to OUT.
+
+  set +e; diff -u "$old" "$new" >"$out"; rc=$?; set -e
+  case $rc in 1) cat "$out" ;; esac
+  return $rc
+}
+
 localp () {
   h=$1
   ## Answer whether H is a local host.
@@ -177,6 +195,30 @@ runhook () {
   done
 }
 
+remove_old_logfiles () {
+  base=$1
+  ## Remove old logfiles with names of the form BASE.DATE#N, so that there
+  ## are at most $MAXLOG of them.
+
+  ## Count up the logfiles.
+  nlog=0
+  for i in "$base".*; do
+    if [ ! -f "$i" ]; then continue; fi
+    nlog=$(( nlog + 1 ))
+  done
+
+  ## If there are too many, go through and delete some early ones.
+  if [ $dryrun = nil ] && [ $nlog -gt $MAXLOG ]; then
+    n=$(( nlog - MAXLOG ))
+    for i in "$base".*; do
+      if [ ! -f "$i" ]; then continue; fi
+      rm -f "$i"
+      n=$(( n - 1 ))
+      if [ $n -eq 0 ]; then break; fi
+    done
+  fi
+}
+
 ###--------------------------------------------------------------------------
 ### Database operations.
 
@@ -570,6 +612,7 @@ do_backup () {
 
   set -e
   attempt=0
+  fshash_diff=nil
 
   ## Run a hook beforehand.
   set +e; runhook setup $host $fs $date; rc=$?; set -e
@@ -597,6 +640,20 @@ do_backup () {
     esac
     $verbose " create snapshot"
 
+    ## If we had a fshash-mismatch, then clear out the potentially stale
+    ## entries, both locally and remotely.
+    case $fshash_diff in
+      nil) ;;
+      *)
+       $verbose "      prune cache"
+       run -stdin "local prune fshash" \
+         fshash -u -c$STOREDIR/fshash.cache -H$HASH new/ <$fshash_diff
+       run -stdin "@$host: prune fshash" \
+         _hostrun $userat$host <$fshash_diff \
+         "fshash -u -c$fshashdir/$fs.bkp -H$HASH ${snapmnt#*:}"
+       ;;
+    esac
+
     ## Build the list of hardlink sources.
     linkdests=""
     for i in $host $like; do
@@ -653,7 +710,9 @@ do_backup () {
 
     ## Compare the two maps.
     set +e
-    run "compare fshash maps for $host:$fs" diff -u new.fshash $localmap
+    fshash_diff=$STOREDIR/tmp/fshash-diff.$host.$fs.$date
+    run "compare fshash maps for $host:$fs" \
+      run_diff $fshash_diff new.fshash $localmap
     rc_diff=$?
     set -e
     case $rc_diff in
@@ -673,6 +732,7 @@ do_backup () {
 
   ## Glorious success.
   maybe rm -f $localmap
+  case $fshash_diff in nil) ;; *) maybe rm -f $fshash_diff ;; esac
   $verbose "   fshash match"
 
   ## Commit this backup.
@@ -744,23 +804,8 @@ run_backup_cmd () {
     bkprc=1
   fi
 
-  ## Count up the logfiles.
-  nlog=0
-  for i in "$logdir/$host/$fs".*; do
-    if [ ! -f "$i" ]; then continue; fi
-    nlog=$(( nlog + 1 ))
-  done
-
-  ## If there are too many, go through and delete some early ones.
-  if [ $dryrun = nil ] && [ $nlog -gt $MAXLOG ]; then
-    n=$(( nlog - MAXLOG ))
-    for i in "$logdir/$host/$fs".*; do
-      if [ ! -f "$i" ]; then continue; fi
-      rm -f "$i"
-      n=$(( n - 1 ))
-      if [ $n -eq 0 ]; then break; fi
-    done
-  fi
+  ## Clear away any old logfiles.
+  remove_old_logfiles "$logdir/$host/$fs"
 }
 
 backup () {
@@ -842,7 +887,7 @@ host () {
   $verbose "host $host"
 }
 
-snaptype () { snap=$1; shift; snapargs="$*"; retry=0; }
+snaptype () { snap=$1; shift; snapargs="$*"; retry=1; }
 rsyncargs () { rsyncargs="$*"; }
 like () { like="$*"; }
 retry () { retry="$*"; }