#!/bin/sh arg1() { echo "$1" ; } getmnts() { sed '-es|_|/|g' ; } getmnt() { echo "$1" | getmnts ; } getstatus() { cat "$CTL/$1"/status ; } getstate() { ctls="$(ls "$CTL")" for ctl in $ctls ; do st="$(getstatus "$ctl")" [ "$st" = "$1" ] && echo "$ctl" done } # Resync while write blocked and reanabe this copy # before unblocking so that all further changes stay # in sync. Args are mount points. msync() { # GOOD_MNT BAD_MNT BAD_STATUS if [ -z "$1" ] ; then usage echo "ERROR: You must specify the good mount point" >&2 echo "" >&2 exit fi if [ -z "$2" ] ; then usage echo "ERROR: You must specify the bad mount point" >&2 echo "" >&2 exit fi if [ -z "$3" ] ; then usage echo "ERROR: You must specify the bad status ctl file" >&2 echo "" >&2 exit fi echo "Resyncing with write block from $1 to $2 (STAT:$3, RSYNC_OPTS:$RSYNC_OPTS)" >&2 echo B > "$3" if rsync $RSYNC_OPTS "$1/" "$2" ; then echo 0 > "$3" echo U > "$3" return fi echo U > "$3" return 1 } presync() { typeset -i sw_num=1 n=0 case "$1" in -*) sw_num="${1:1}" ; shift ;; esac good="$1" bad="$2" stg="$(getstatus "$good")" stb="$(getstatus "$bad")" [ "$stg" != "0" ] && return 1 [ "$stb" != "2" ] && return 2 mntg="$(getmnt "$good")" mntb="$(getmnt "$bad")" # Bring it up to date without blocking first since there # may be major changes from when the sync was lost while [ $n -lt $sw_num ] ; do n=$(($n +1)) echo "Resyncing($n of $sw_num) from $mntg to $mntb (RSYNC_OPTS:$RSYNC_OPTS )" >&2 rsync $RSYNC_OPTS "$mntg/" "$mntb" || return 3 done # Ensure 100% sync while write blocked (changes may have # already occured since the first sync!) and reenable this # copy before unblocking so that all further changes stay # in sync. Hopefully there will be very few changes during # the write block since we just did a sync without # blocking to catch up. msync "$mntg" "$mntb" "$CTL/$bad/status" } usage() { cat - >&2 < Flags for rsync. The default are: $RSYNC_OPTS -1 Only rysnc once (during write block) -2 Presync before write blocking EOF } RSYNC_OPTS='-a -A -H -X --numeric-ids --delete -S -c' SW_NUM='-2' READ='' while [ $# -gt 0 ] ; do case "$1" in -h|-u|--help) usage ; exit ;; --ctl) shift ; CTL="$1" ;; --rsyncopts) shift ; RSYNC_OPTS="$1" ;; --sync) shift ; GMNT="$1" ; BMNT="$2" ; BCTL="$3" ; shift 2 ;; -1) SW_NUM="$1" ;; -2) SW_NUM="$1" ;; --read) shift ; READ="$READ $1" ;; esac shift done [ ! -z "$GMNT$BMNT$BCTL" ] && { msync "$GMNT" "$BMNT" "$BCTL" ; exit ; } if [ -z "$CTL" ] ; then usage echo "ERROR: You must provide the location of the CHIRCTL filesystem" >&2 echo "" >&2 exit fi debug() { for ctl in $CTLS ; do mnt="$(getmnt "$ctl")" st="$(getstatus "$ctl")" echo "MNT: $mnt, STATUS: $st" done } GOOD="$(getstate 0)" BAD="$(getstate 2)" [ ! -z "$GOOD" ] && echo "GOOD: " $GOOD [ ! -z "$BAD" ] && echo "BAD: " $BAD [ -z "$BAD" ] && exit # which good one should we use (not :), but we don't have this info" G="$(arg1 $GOOD)" for bad in $BAD ; do presync $SW_NUM "$G" "$bad" done GOOD="$(getstate 0)" BAD="$(getstate 2)" [ ! -z "$GOOD" ] && echo "GOOD: " $GOOD [ ! -z "$BAD" ] && echo "BAD: " $BAD [ ! -z "$BAD" ] && exit 1