Newsgroups: comp.sources.unix From: rca@ingres.com (Bob Arnold) Subject: v28i069: saenv_alldisks - sysadmin env, disk management and backups, Part05/06 References: <1.771948808.8446@gw.home.vix.com> Sender: unix-sources-moderator@gw.home.vix.com Approved: vixie@gw.home.vix.com Submitted-By: rca@ingres.com (Bob Arnold) Posting-Number: Volume 28, Issue 69 Archive-Name: saenv_alldisks/part05 #!/bin/sh # this is saenv_alld.05 (part 5 of saenv_alld) # do not concatenate these parts, unpack them in order with /bin/sh # file src/backup/backup continued # if test ! -r _shar_seq_.tmp; then echo 'Please unpack part 1 first!' exit 1 fi (read Scheck if test "$Scheck" != 5; then echo Please unpack part "$Scheck" next! exit 1 else exit 0 fi ) < _shar_seq_.tmp || exit 1 if test ! -f _shar_wnt_.tmp; then echo 'x - still skipping src/backup/backup' else echo 'x - continuing file src/backup/backup' sed 's/^X//' << 'SHAR_EOF' >> 'src/backup/backup' && X ;; X noauto) X autoverify=false X autoarg=$1 X ;; X nocheck) X check=false X ;; X nofitguess) X fitguess=false X ;; X nojoke) X joke=false X ;; X nolabelq) X labelq=false X ;; X nomail) X mail=false X mailarg=nomail X ;; X nooffline) X offline=false X ;; X noprobq) X probq=false X ;; X noupdate) X update=false X ;; X notcont) X cont2next=false X ;; X showdd) X showdd=true X BDDSHOW=true X export BDDSHOW X showddarg=$1 X ;; X skip) X shift X fileskip="$1" X getmode=knownskip X labelq=false X ;; X target) X shift X target="$1" X targetarg=true X ;; X verifytoo|verify2) X verifytoo=true X ;; X [0-9]|[12][0-9]) X extravol=$1 X nvol=`expr $extravol + 1` X n=$extravol X while test $n -gt 0 ; do X case "$2" in X /*|unknown) X shift X firstfslist="$firstfslist $1" X case "$2" in X cont*) X shift X # use "cont" as canonical spelling X firstfslist="$firstfslist cont" X ;; X esac X n=`expr $n - 1` X ;; X *) X break X ;; X esac X done X ;; X [01][0-9][0123][0-9].*[a-z]) X parent=$1 X offline=false X joke=false X labelq=false X ;; X *) X echo "$pr: Option '$1' not understood. Quitting." X echo "$USAGE" X exit 1 X ;; X esac X shift Xdone X# pass these args to any child backup processes, for example: X# when a backup does a "verifytoo" X# when a "verify alldisks" does a "verify onedisk" Xchildargs="$cpioarg $showddarg $autoarg $mailarg" X X## make sure we know who is doing this backup ('cron' option sets $OPER to X## cron, otherwise we hope to get it from our environment) Xfor f in $oplist $oplistloc ; do X test -f $f && opfiles="$opfiles $f" Xdone Xwhile test "$OPER" = "" -o "$OPER" = '??' -o -z "`egrep '^'$OPER'[ ]|^'$OPER'$' $opfiles`" ; do X echo "$pr: I don't know who you are." X echo $epre "$pr: Please enter your initials: "$esuf X eval "$READ" OPER X # break out of here if we know who $OPER is X egrep "^$OPER[ ]|^$OPER\$" $opfiles > /dev/null && break X # otherwise try to find out X while : ; do X echo "$pr: I don't know who '$OPER' is." X echo $epre "$pr: Do you wish to be added as a backup operator? [yn] "$esuf X eval "$READ" ans X case $ans in X [nN]*) X break 2 X ;; X [yY]*) X echo $epre "$pr: Enter your login name: "$esuf X eval "$READ" login X case $login in X *' '*|[A-Z0-9]*) X echo "$pr: Invalid login name '$login'" X continue X ;; X [a-z]*) X : do nothing since we seem to be ok X ;; X *) X echo "$pr: Invalid login name '$login'" X continue X ;; X esac X echo $epre "$pr: Enter your Full Name: "$esuf X eval "$READ" name X echo "$OPER $login $name" >> $oplist X break 2 X ;; X esac X done Xdone Xoperlogin=`grep "^$OPER[ ]" $opfiles | awk '{print $2; exit}'` Xexport OPER # in case we do verifytoo or this is a 'verify alldisks' X X## if backups have to be done as root, make sure the operator is su'd Xif test `ls -l $0 2>&- | grep -c '^...x'` -eq 1 ; then X # find out effective user id - this is a guessing game but the X # following rule seems best: whoami > id > $USER > $LOGNAME X whoami=`( whoami ) 2> /dev/null` X id=`( id | sed -e 's/).*//' -e 's/.*(//' ) 2> /dev/null` X for arg in whoami id USER LOGNAME ; do X eval "test -n \"\$$arg\" && result=\$$arg && break" X done X case $result in X *root) : we are root so we are OK ;; X *) echo "$pr: Backups on $lhost must be done as root." ; exit 1 ;; X esac Xfi X X## check mode specs and make some early decisions Xcase "$mode" in X'') X echo "$pr: 'mode' was not specified. Valid modes are:" X echo "$pr: 'help', 'full', 'incr', 'get', 'verify', or 'devcheck'." X echo "$USAGE" X exit 1 X;; Xfull|incr|tincr) X report=$breport X if test -z "$multi" ; then X echo "$pr: 'filesystem' was not specified. Valid filesystems are:" X echo "$pr: '/fsname', 'alldisks', 'listN', 'list listfile', or 'unlisted'." X echo "$USAGE" X exit 1 X fi X;; Xget|verify) X report=$gvreport X if test -z "$getmode" ; then X echo "$pr: 'getmode' was not specified. Valid getmodes are:" X echo "$pr: 'onedisk', 'listdisks', '/fsname', 'lastdisk', or alldisks'." X echo "$USAGE" X exit 1 X fi X;; Xdevcheck) X : nothing special needs to be done here X;; X*) X echo "$pr: Do not understand mode '$mode'." X echo "$USAGE" X exit 1 X;; Xesac X X## double check on a couple of unusual possible requests X# if the operator says to do an incremental of just one filesystem, verify it. Xcase $mode$multi in X*incrfalse) X checkq="Do you REALLY want to run an INCREMENTAL on '$fs'?" X eval "$CHECKQ" X;; X# if the operator specified a full alldisks but there are list files present Xfulltrue) X if test "$multitype" = alldisks -a "`echo bkp.list[0-9]*`" != "bkp.list[0-9]*" ; then X echo "$pr: There are list files in backup's home directory," X echo "$pr: so we are probably managing tape usage for full" X echo "$pr: backups of $lhost with a 'list1/unlisted' scheme." X ls -l bkp.list[0-9]* X checkq="Are you SURE you want to do a 'full alldisks'?" X eval "$CHECKQ" X fi X;; Xesac X X## check media stuff X# select device data file Xif test -f $hdir/$devdata ; then X devdata=$hdir/$devdata X echo "$pr: WARNING: using '$devdata' for device data." Xelif test -f $DTGT/$devdata ; then X devdata=$DTGT/$devdata Xelse X echo "$pr: No '$devdata' in '$DTGT' or '$hdir'. Quitting." Xfi X# see if $mhost and $media are ok; note: a host may have no valid local media Xmtype=`expr "$media" : '\([^0-9]*\)'` Xmdata=`egrep "^$mhost[ ]+$media[ ]" $devdata` Xcase "$mtype" in X# if operator didn't specify media X'') X echo "$pr: 'media' was not specified." X badmedia=true X;; X# if $mtype is null, no more validation needed since we always have /dev/null Xnull) X : do nothing X;; X# $mtype is dir or file, so we are writing or reading a file, not a tape device Xdir|file) X # make sure we're doing the right thing X case "$mode" in X devcheck) X echo "$pr: 'devcheck' mode not supported for 'file' archives. Quitting." X exit 1 X ;; X get|verify) X case $diskfile$multi in X -true) echo "$pr: Cannot read alldisks from STDIN" ; exit 1 ;; X esac X ;; X # some kind of backup X *) X case $diskfile$multi in X -true) echo "$pr: Cannot write alldisks to STDOUT" ; exit 1 ;; X esac X ;; X esac X;; X# $mtype is devnames, so make sure we are in devcheck mode Xdevnames) X if test "$mode" != devcheck ; then X echo "$pr: Cannot specify device names except in devcheck mode." X badmedia=true X fi X;; X# $mtype is dat or video, so we only need to see if $media is valid Xdat|video) X if test -z "$mdata" ; then X echo "$pr: '$media' is not a valid media for host '$mhost'" X badmedia=true X fi X;; X# $mtype isn't null, dat or video, so see if $media is valid, and also X# make sure we don't do a full multi-filesystem backup to non-video/dat media X*) X if test -z "$mdata" ; then X echo "$pr: '$media' is not a valid media for host '$mhost'" X badmedia=true X elif test "$mode" = full -a "$multi" = true -a "$fitguess" = true ; then X echo "$pr: A 'full alldisks' will not fit on a '$mtype'." X badmedia=true X fi X;; Xesac Xif test "$badmedia" = true ; then X # print devices available on the media host and quit X vmedia=`egrep "^$mhost[ ]" $devdata | awk '{print $2}'` X vmedia=`echo $vmedia` # strip newlines X if test -n "vmedia" ; then X echo "$pr: $mhost has these media: '$vmedia'." X fi X echo "$pr: Look at '$devdata' for a list of valid" X echo "$pr: media hosts and their devices." X echo "$pr: Quitting." X exit 1 Xfi X# now that media info is ok, get info from $devdata by way of $mdata X# for dir, file, null, and devnames, obs of 5120 is arbitrary, X# maxocount of 100000 blocks is very arbitrary, and we pick 330000 X# for backup program options because it's our biggest valid "$bopt" Xcase $mtype in Xdir|file|null) X set $mhost $mtype xx 100000 null null 330000 X;; Xdevnames) X set $mhost $mtype xx 100000 $rewdev $norewdev X;; X*) X set $mdata X;; Xesac Xreserved=$3 # document that we don't use this field since 4.22 Xmaxocount=$4 # maximum number of output blocks per tape Xrewdev=/dev/$5 # name of rewind device we're using Xnorewdev=/dev/$6 # name of no-rewind device we're using X# should say "shift 6" here but CCI's BSD "sh" doesn't like it Xshift ; shift ; shift ; shift ; shift ; shift Xbopts="$*" # backup program (cpio/dump) options, if any X# if $media is null, check with user, and set variables Xif test $media = null ; then X echo "$pr: WARNING!!! media is '$media' !!!" X echo "$pr: This backup will be USELESS !!!" X eval "$EXITQ" X update=false X offline=false Xfi X# if we're skipping media checks and we haven't already checked it, then Xif test $check != true -a -z "$parent" ; then X echo "$pr: WARNING: You are skipping media checks !!!" X echo "$pr: You had better know what YOU are doing !!!" X eval "$EXITQ" Xfi X X###### Handle some real strange problems Xcase $mlocal$multi$OS_S in X# This shouldn't be a problem, but it is, so we'd better not even try this: XfalsefalseAIX) X echo "$pr: AIX network cpio onedisk backups *don't* work." X echo "$pr: FYI, this is mysterious, because, so far as we know:" X echo "$pr: 1) AIX network cpio multi-filesystem backups *do* work." X echo "$pr: 2) Both onedisk and multi-filesystem network cpio backups" X echo "$pr: for other UNIXs *do* work." X echo "$pr: The problem is that the archive is missing the first 88k or" X echo "$pr: so of the archive. It is unknown why this happens." X exit 1 X;; Xesac X# This is a real problem: Xcase $mlocal$multi$mistape$OS_S$OSLEVEL_S$rewdev in Xfalsetruetruedgux5.4*/dev/rmt/*) X echo "$pr: WARNING: Under dgux 5.4, if a multi-filesystem network" X echo "$pr: backup to a '/dev/rmt' device uses more than one tape," X echo "$pr: and it looks like it works beautifully, BE AWARE:" X echo "$pr: the filesystem which is split accross two tapes may be" X echo "$pr: missing 50 blocks (or so) of buffered data which the remote" X echo "$pr: system was unable to write to it's tape drive when it hit" X echo "$pr: physical EOT (end of tape)." X echo "$pr: You can try setting up and using a pseudo mag tape" X echo "$pr: '/dev/pmt' device on $lhost instead." X eval "$EXITQ" X;; Xesac X X# now that our mode has been set, we can make sure we don't conflict X# with another currently running backup/get/verify Xif test -f $lockf -a $mode != devcheck -a -z "$parent" ; then X echo "$pr: A conflicting cpio backup/get/verify seems to be in progress." X cat $lockf X echo "$pr: Check with 'ps $PSALL_K'. Quitting." X # take the lock file out of $rmlist before exiting! X rmlist=`echo $rmlist | sed -e "s,$lockf ,,"` X exit Xfi X X# See if we know how many extra volumes are in the backup set. X# This only makes sense if we're doing a get or verify. Xif test -n "$extravol" ; then X case $mode in X get|verify) : we are ok but do we do not have to do anything ;; X *) echo "$USAGE" ; exit 1 ;; X esac Xfi X X# if user specified a restore target on the command line, make sure we're X# in "get" mode and that they really did specify *some* target (which we'll X# check out more thoroughly later). Xif test "$targetarg" = true ; then X case $mode in X get) X if test -z "$target" ; then X echo "$pr: Target directory not specified. Quitting." X echo "$USAGE" X exit 1 X fi X ;; X *) X echo "$pr: 'target ' only valid for 'get' mode. Quitting." X echo "$USAGE" X exit 1 X ;; X esac Xfi X X# if user specified a listfile on the command line, make sure it exists X# and has something in it. Xif test -n "$listf" ; then X if test ! -f $listf ; then X echo "$pr: No such listfile '$listf'. Quitting." X exit 1 X elif test ! -s $listf ; then X echo "$pr: Listfile '$listf' is empty. Quitting." X exit 1 X fi Xfi X X## we've checked as much command syntax as we can without making a working X## directory, but we need one now. X# It's name has a short form "$wdir" and long form "$workdir". X# It's "$wdir" name is based on the X# a) date, b) mode, and c) onedisk vs. multi-filesystem archive. X# "g" for get, "f" for full, "i" for incremental, "t" for test_incremental, X# and "v" for verify; X# "m" for multi-filesystem (alldisks), "o" for onedisk Xcase "$mode$multi" in Xdevcheck*) wdir=$date4.${time6}d ;; Xget*) wdir=$date4.${time6}g ;; Xverifytrue) wdir=$date4.${time6}vm ;; Xverify*) wdir=$date4.${time6}vo ;; Xfulltrue) wdir=$date4.${time6}fm ;; Xincrtrue) wdir=$date4.${time6}im ;; Xtincrtrue) wdir=$date4.${time6}tm ;; Xfull*) wdir=$date4.${time6}fo ;; Xincr*) wdir=$date4.${time6}io ;; Xtincr*) wdir=$date4.${time6}to ;; Xesac Xcase "$parent" in X'') workdir=$hdir/$wdir ;; X*) workdir=$hdir/$parent/$wdir ;; Xesac X# make sure creation of $workdir succeeds, because if it doesn't the X# filesystem is probably full, and we can end up with a truncated bkp.donot X# among other disasters. Xmkdir $workdir Xif test $? -ne 0 ; then X echo "$pr: Could not make '$workdir'." X echo "$pr: The filesystem holding backup's home directory is probably full." X echo "$pr: Quitting." X exit 1 Xfi Xcd $workdir X X## sample "df" outputs - needed if we're doing a backup X# X## normal BSD output X# Filesystem kbytes used avail capacity Mounted on X# /dev/xd0a 15720 4564 9584 32% / X# X## System V output (including "/adj" multi-cpu concept from 3B4000 (bigbird)) X# / (/dev/dsk/c0t7d0s0): 0 blocks 51134 i-nodes X# /adj (/dev/adj ): 32568 blocks 4582 i-nodes X# /proc (/proc ): 0 blocks 859 i-nodes X# /adj/pe96/dev (/adj/pe96/dev/icfs): 179 blocks 413 i-nodes X# /install/62 (/adj/pe96/dev/dsk/c0t4d0s0): 328800 blocks 61126 i-nodes X# X## AIX 2.2.1: output with "/native" NFS-ish concept. Note 7 fields. X# Device Mounted on total free used ifree used X# /dev/hd0 / 38684 8144 78% 9297 7% X# / /native 38684 8144 78% 9297 7% X# X## AIX 3.1: Note 7 fields but mountpoint is the last field as it should be. X# Filesystem Total KB free %used iused %iused Mounted on X# /dev/hd4 40960 1128 97% 1245 12% / X# /dev/hd2 376832 47336 87% 7852 8% /usr X# X## TI Sys V 3.2.1: Note *two* colons: X#/ (/dev/dsk/sys:root): 1726 blocks 2139 i-nodes X#/pipe (/dev/dsk/sys:pipe): 989 blocks 452 i-nodes X#/usr (/dev/dsk/sys:usr): 1357 blocks 5925 i-nodes X#/install/62/supp (/dev/dsk/dsk2:supp): 91011 blocks 36947 i-nodes X# X## IRIX 3.3.2: note /debug which is not a real filesystem X# Filesystem Type blocks use avail %use Mounted on X# /dev/root efs 31360 26001 5359 83% / X# /dev/usr efs 1860180 1132421 727759 61% /usr X# /debug dbg 143936 12344 131592 9% /debug X# X## NonStop-UX 4.0 "df" doesn't show filesystem type so we have to look it X## up in /etc/vfstab or use "df -n". X## NonStop-UX 4.0 "df -k -l" X# abalone 125# df -k -l X# filesystem kbytes used avail capacity mounted on X# /dev/vol/root 65536 56069 9467 86% / X# /proc 0 0 0 0% /proc X# /dev/fd 0 0 0 0% /dev/fd X# /config 0 0 0 0% /config X# /dev/vol/usr 256000 195626 60374 76% /usr X# /dev/dsk/sc1d3s10 282933 149152 133781 53% /install/64 X## NonStop-UX 4.0 "df -n" X# abalone 126# df -n X# / : vxfs X# /proc : proc X# /dev/fd : fdfs X# /config : cfs X# /usr : vxfs X# /install/64 : ufs X# abalone 127# X## NonStop-UX 4.0 end of "df" outputs X# X## END of "df" sample outputs X X# if we are doing a backup of one or more filesystems, then X# get df output and make sure our bkp.donot file excludes strange filesystems X# else take care of a few other little things Xcase $mode$fsbkp in Xdevcheck*|get*|verify*) X : do nothing special X;; Xfullfalse) X if test ! -d $fs ; then X echo "$pr: $fs is not a directory. Quitting." X exit 1 X fi X devlist=$fs X;; X*false) X echo "$pr: Incrementals OK for filesystems only. Quitting." X exit 1 X;; Xfull*|incr*|tincr*) X ## get list of valid filesystems for backup. X # see sample "df" outputs above X # We use "df" because it's output is more similar across OS platforms X # than "mount" and Sys V mount doesn't always show the root filesystem. X # Unfortunately, df can hang waiting for info from an NFS filesystem. X # "df > $dft1 & ; sleep 5 ; ..." isn't a workaround because in that X # usage "df" won't put out any info until it completes. X # Oh, well, there's no good answer yet, except on some machines X # where "df" has a filesystem type key X if test "$OS_S" = NonStop-UX ; then X dfargs="-l" X elif test -n "$DFFSTYPE_K" -a -n "$LOCFSTYPE_S" ; then X dfargs="$DFFSTYPE_K $LOCFSTYPE_S" X else X dfargs="" X fi X df $dfargs | egrep '/dev/' > $dft1 X X # if we have SysV df output X if egrep '\):' $dft1 > /dev/null ; then X sed -e 's/(/ /' -e 's/):/ /' $dft1 | awk '{printf "%-16s %6d %s %6d %s %s\n",$2,$3,$4,$5,$6,$1}' > $dft2 X # else if we're AIX 2.2.1 X elif awk '{print $2}' $dft1 | grep / > /dev/null ; then X egrep '/dev/' $dft1 | awk '{printf "%-16s %6d %6d %4s %6d %4s %s\n",$1,$3,$4,$5,$6,$7,$2}' > $dft2 X # else we're normal BSD or AIX 3.1 X else X cp $dft1 $dft2 X fi X X # Some operating systems have filesystems we never want to back up X case "$OS_S$OSLEVEL_S" in X AIX2.2.1|IRIX3*|NonStop-UX4.0) X case "$OS_S$OSLEVEL_S" in X AIX2.2.1) bumfs=/native ;; X IRIX3*) bumfs=/debug ;; X NonStop-UX4.0) bumfs=/config ;; X esac X if test ! -f $nobkp ; then X echo $bumfs > $nobkp X elif egrep $bumfs $nobkp > /dev/null ; then X : do nothing we are already protected X else X echo $bumfs >> $nobkp X sort -u -o $nobkp $nobkp X fi X ;; X esac X X ## We have three filters for filesystems which we may not want X ## to back up. Two of them are config files, and the third we X ## implement in code. X # X # filesystem filters: X # a) $nobkp, lists filesystems we never want to back up, and we make X # sure it includes the following filesystems (see $bumfs above) X # For AIX 2.2.1, don't back up /native (see above) X # For IRIX 3.*, don't back up /debug X # For NonStop-UX, don't back up /config X # Otherwise, $nobkp is configured by the user X # b) $nofm, lists filesystems we never want to do full multivolume X # backups on (i.e. we don't do full alldisks with). Typically X # this file might list 1Gig filesystems which we want to do X # seperate full onedisk backups on. X # c) don't backup /cdrom/unnamed_cdrom, /cdrom*, /export/swap, /proc, X # /tmp, or NFS filesystems X # X ## We also may have some number of listfiles (e.g. bkp.list0) to check X ## valid formats. The format for the listfiles is the same as the X ## filesystem filter files. X # X # NOTE: X # we must carefully delimit filesystem name for egrep, both here and X # in $nobkptmp. X # The regular expression must include '[]/fsname' X # This example would prevent backing up a /scratch filesystem: X # [ ]/scratch$ X X # massage config file filesystem filters into $nobkptmp, if we X # have them and want to use them; X # also massage $listf into $listftmp if necessary X rm -f $nobkptmp $listftmp X case $mode$multi in X fulltrue) fsfilters="$nobkp $nofm" ;; X *) fsfilters="$nobkp" ;; X esac X case "$multitype" in X unlisted) X cd $hdir X listfiles=`echo bkp.list[0-9]*` X if test "$listfiles" != "bkp.list[0-9]*" ; then X # sed strips comments and blank lines in $listfiles X sed -e 's/[ ]*\#.*//' -e '/^[ ]*$/d' $listfiles > $workdir/bkp.listed X fsfilters="$fsfilters $workdir/bkp.listed" X fi X cd $workdir X ;; X esac X for ff in $fsfilters $listf ; do X if test -f $ff ; then X ## make sure $ff is in correct format X # assume leading blanks, trailing blanks, and blank X # lines are benign, and quietly fix them if present X sed -e 's/^[ ]*//' -e 's/[ ]*$//' -e '/^$/d' $ff > $ff.t X if test `wc -c < $ff.t` -lt `wc -c < $ff` ; then X mv $ff.t $ff X fi X # strip comments, then see if $ff.t1 has any X # real data left X sed -e 's/[ ]*\#.*//' -e '/^[ ]*$/d' $ff > $ff.t1 X if test ! -s $ff.t1 ; then X case $ff in X */bkp.donot|*/bkp.nofm) X echo "$pr: WARNING - '$ff' is empty or has only comments; please fix or remove; continuing ..." | tee -a $failrpt X continue X ;; X *) X echo "$pr: Listfile '$ff' is empty. Quitting." | tee -a $failrpt X exit 1 X ;; X esac X fi X # check for common mistakes: putting device name X # instead of mount point. X if egrep '^/(adj/.*)*dev/' $ff > /dev/null ; then X echo "$pr: '$ff' contains device names" X echo "$pr: instead of mount points. Quitting." X exit 1 X fi X ## make sure $nobkptmp is in correct format, with a X # []filesystemname (for dump) X # []directoryname (for cpio) X sed -n -e 's,^\(/[a-zA-Z0-9_/\.\+-]*\)$,[ ]\1$,p' $ff.t1 > $ff.t X nlinesorig=`wc -l < $ff.t1` X nlinestmp=` wc -l < $ff.t` X # if the number of lines in $ff.t1 and $ff.t X # are unequal, create failure report and quit. X if test $nlinesorig -eq $nlinestmp ; then X case $ff in X */bkp.donot|*/bkp.nofm|*/bkp.listed) X cat $ff.t >> $nobkptmp X ;; X *) X cat $ff.t >> $listftmp X ;; X esac X else X exec 1> $failrpt X echo "" X echo "$pr: '$ff' is not in correct format." X echo "$pr: '$ff' must list one filesystem per line" X echo "$pr: (although comments beginning with '#' are OK)" X echo "$pr: Please fix '$ff'. Quitting." X exec 1>&9 X cat $failrpt X exit 1 X fi X rm -f $ff.t1 $ff.t X fi X done X X # strip unwanted filesystems, now that we have $nobkptmp X # "/adj/.*dev/" selects Sys V devices, e.g. /adj/pe96/dev/ on 3B4000's X # "/cdrom" is for SunOS's read only CDROM X # "/cdrom/unnamed_cdrom" is for Solaris's 2.2+ read only CDROM X # "/export/swap", "/proc", and "/tmp" are scratch so we don't care X # X # first egrep strips filesystems we never want X # "if" subshell strips any filesystems in $nobkptmp if it exists X # second egrep selects info on devices X egrep -v '[ ]/(cdrom.*|export/swap|proc|tmp)$' $dft2 \ X | if test ! -s $nobkptmp ; then X cat X else X # $egrepff, $egrepfi, $egrepfo, and $egrepfv for $EGREPF X egrepff=$nobkptmp X egrepfi="" X egrepfo="" X egrepfv="-v" X eval "$EGREPF" X fi \ X | egrep '^/dev/|^/adj/.*dev/' > $dft3 X X # put /, /usr, and /var *first* X # (In alldisks versions before 3.00, / and /usr were last.) X # (From alldisks versions 3.00 thru 4.46, / and /usr were first.) X # (Since alldisks version 4.47, /, /usr, and /var are first.) X egrep '[ ]/$' $dft3 > $dfout X egrep '[ ]/usr$' $dft3 >> $dfout X egrep '[ ]/var$' $dft3 >> $dfout X egrep -v '[ ](/|/usr|/var)$' $dft3 >> $dfout X X # select filesystems from $listf X if test -n "$listf" ; then X mv $dfout $dflocal X # $egrepff, $egrepfi, $egrepfo, and $egrepfv for $EGREPF X egrepff=$listftmp X egrepfi=$dflocal X egrepfo=$dfout X egrepfv="" X eval "$EGREPF" X fi X X if test ! -s $dfout ; then X echo "$pr: '$dfout' is empty. Something is wrong." X echo "$pr: Quitting." X exit 1 X fi X X ## get list of actual filesystem devices - necessary because X ## a) 4.1BSD dump matches 1st *similar* pattern, not real thing X ## b) NCR SVR4 does not look up mount point in /etc/vfstab X # if $fs wasn't specified then we're doing an alldisks backup X if test -z "$fs" ; then X devlist=`awk '{print $1}' $dfout` X # else $fs was specified, so check its validity X else X # if $fs is in $dfout we're cool X devlist=`egrep "[ ]$fs\$" $dfout | awk '{print $1}'` X if test -z "$devlist" ; then X # maybe $fs is in $nobkp (and hence in $dft2 but not $dfout) X devlist=`egrep "[ ]$fs\$" $dft2 | awk '{print $1}'` X if test -n "$devlist" ; then X echo "$pr: Filesystem '$lhost:$fs' is not usually backed up." X eval "$EXITQ" X # else we really aren't a mounted filesystem X else X echo "$pr: Bad filesystem name '$fs'" X exit 1 X fi X fi X fi X;; Xesac X Xecho "$pr: Your command looks AOK to me. Thanks." X X# build local and remote commands (no dd command since we're using $bdd script) Xcase $mhost in X$lhost) mlocal=true ;; # the media is local X*) mlocal=false ;; # the media is remote Xesac Xif test $mlocal = true ; then X cmp="cmp" X ls="ls" X mt="mt" X rm="rm" X tar="tar" Xelif test -z "$rsh" ; then X echo "$pr: \$RSH_C is not set in /etc/saenv:" X grep '^RSH_C=' /etc/saenv X echo "$pr: Quitting." X exit 1 X# "date" output is same on BSD, SunOS, SysV, NCROS, UTS, AIX, Solaris, SVR4 X#elif test `$rsh $mhost date 2> /dev/null | wc -w` -ne 6 ; then Xelif $rsh $mhost date > /dev/null 2>&1 ; then X cmp="$rsh $mhost cmp" X ls="$rsh $mhost ls" X mt="$rsh $mhost mt" X rm="$rsh $mhost rm" X tar="$rsh $mhost tar" Xelse X echo "$pr: $rsh $mhost date" X $rsh $mhost date X echo "$pr: 'root' on $lhost does not have permission to run" X echo "$pr: remote shell commands at media host $mhost. Check:" X echo "$pr: -> Make sure '$lhost root' is in /.rhosts on $mhost." X echo "$pr: -> Make sure '$lhost' has a valid entry in /etc/hosts on $mhost." X echo "$pr: Quitting." X exit Xfi X X## make sure backup.dd script is usable X# export environment variables needed by backup.dd XMHOST=$mhost XLHOST=$lhost Xexport MHOST LHOST RSH_C X# if we haven't tested it already, do so now Xif test -z "$parent" ; then X eval $SHOWDD Make sure $bdd script is usable X echo "$pr: you should never see this" | $bdd of=/dev/null 2> err.dd X if test $? -ne 0 ; then X cat err.dd X echo "$pr: '$bdd' is not usable for some reason. Quitting." X exit 1 X fi Xfi Xrm -f err.dd X X# build mt command if mt exists Xif test $mhost = $lhost ; then X mtkey="$MT_K" Xelse X mtkey="`$rsh $mhost grep 'MT_K=' /etc/saenv | sed -n -e '/^MT_K=/s/^MT_K=\([^ ]*\)[ ].*/\1/p'`" Xfi Xcase "$mtkey" in X'') mt='' ;; # mt command does not exist on media host X*) mt="$mt $mtkey" ;; # mt command does exist on media host Xesac X X## figure out which backup/get program(s) we're using X# if the user specified cpio on the command line Xif test "$bprog" = cpio ; then X restore=cpio X# else if we're on Dynix Sequent using a video drive Xelif test -n "$HDUMP_P" -a $mtype = video ; then X bprog=$HDUMP_P X restore=$RESTOR_P X# else if we have BSD dump by some name Xelif test -n "$DUMP_P" ; then X bprog=$DUMP_P X restore=$RESTOR_P X# else we're using cpio Xelse X bprog=cpio X restore=cpio Xfi Xif test $mhost != $lhost ; then X # set remote dump/restore if bprog is "dump" X case $bprog in X *dump*) X # set remote dump - warn and die if unavailable X case $bprog in X $HDUMP_P) bprog=$HRDUMP_P ;; # Dynix "hdump/hrdump" X *) bprog=$RDUMP_P ;; # normal "dump/rdump" X esac X if test -z "$bprog" ; then X echo "$pr: Remote dump unavailable on '$lhost' (see \$RDUMP_P in /etc/saenv)." X echo "$pr: Cannot do dumps over net from '$lhost'." X echo "$pr: Try 'cpio' option to do network cpio backups." X exit 1 X fi X # set remote restore - warn and die if unavailable X if test -n "$RRESTOR_P" ; then X restore=$RRESTOR_P X else X echo "$pr: Remote restore unavailable on '$lhost' (see \$RRESTOR_P in /etc/saenv)." X echo "$pr: Cannot do restores over net from '$lhost'." X echo "$pr: Try 'cpio' option to do network cpio restores." X exit 1 X fi X ;; X esac Xfi X# header program Xcase $bprog in Xcpio) headprog=cpio ;; # header archive is cpio format X*dump*) headprog=tar ;; # header archive is tar format Xesac X# lock out other cpio backups/gets/verifies, or lock if we're asked to Xif test $bprog = cpio -o $optlk = true ; then X echo "$pr: LOCK: PID=$$, $workdir, $pr $cmdargs" > $lockf Xfi X# other initial stuff - if we're updating make sure we can Xcase $update$bprog in X*cpio) X # if this is a bad (but real) joke X if test $joke = true -a $mode != devcheck ; then X echo "$pr: We are using cpio - help!" X echo "$pr: Oh, I'm feeling sick ... " X echo $epre "$pr: cough, "$esuf X sleep 1 X echo $epre " choke . . . "$esuf X sleep 1 X echo "gagghhhhh" X echo "$pr: (THUD)." X echo '' X sleep 2 X echo "$pr: Bones: He's dead, Jim." X sleep 2 X echo '' X echo "$pr: Spock: Correction - he's braindead." X echo '' X sleep 2 X echo "$pr: Kirk: Well then, Bones, thanks to the miracle of" X echo "$pr: the alldisks script, we can still do the backup." X echo "$pr: Carry on." X echo '' X fi X;; Xtrue*dump*) X # make sure /etc/dumpdates exists X if test ! -f /etc/dumpdates ; then X echo "$pr: /etc/dumpdates does not exist, creating /etc/dumpdates." X echo "$pr: We do this because some versions of BSD dump abort if" X echo "$pr: /etc/dumpdates doesn't exist." X echo "$pr: This is probably the first time BSD dump has been used on $lhost." X touch /etc/dumpdates X echo "$pr: `ls -l$LSGROUP_K /etc/dumpdates`" X echo "$pr: We're OK now, continuing with the backup." X fi X X # Make a feeble effort to make sure dump can read and write dumpdates. X # We test to see if the script can read and write dumpdates, and X # act accordingly. However, that doesn't tell us what dump/rdump X # will do when we call it. Unfortunately, this is the best we can do. X # Even using "dump W" to test readability won't reliably produce X # useful results, because under HP-UX 8.00 (and probably many other X # UNIXs), if "dump W" is called from a setuid root script, it can read X # /etc/dumpdates even if permissions are 000. X if test ! -r /etc/dumpdates -o ! -w /etc/dumpdates ; then X touch /etc/dumpdates X echo "$pr: `ls -l$LSGROUP_K /etc/dumpdates`" | tee -a $workdir/$report X echo chmod u+rw /etc/dumpdates | tee -a $workdir/$report X chmod u+rw /etc/dumpdates X fi X # quit if we weren't able to fix it X if test ! -r /etc/dumpdates -o ! -w /etc/dumpdates ; then X echo "$pr: `ls -l$LSGROUP_K /etc/dumpdates`" | tee -a $workdir/$report X echo "$pr: Cannot read/write /etc/dumpdates. Quitting." X exit 1 X fi X X # HACK4HPUX8 is from $site; it may make dumpdates 664 group operator X eval "$HACK4HPUX8" X;; Xesac X X# now that $bprog and $restore are set, turn off actual backup work X# for demonstrations Xif test $demo = true ; then X bprog="echo $pr demo: $bprog" # echo backup command X restore="echo $pr demo: $restore" # echo get command X mt="echo $pr demo: $mt" # echo mt command X # dd command is tricky, so tailor it wherever it is used Xfi X X# decide whether we're using a file, dir, rewind device, norewind device X# mdevbase wouldn't be needed if we were only supporting tape devices, X# but since we're supporting alldisks to disk files, we'll be reasigning X# mdev based on $mdevbase. Xif test $mtype = dir ; then X if test $mode = get -o $mode = verify ; then X # a parent could be like either "0206.164423fm" X # or "0206.164423fm/0206.164448vm" X if test -n "$parent" ; then X # $parenttop is roughly the opposite of basename $parent X parenttop=`echo $parent | sed -e 's/\/.*//'` X mdevbase=$diskfile/$parenttop X # or we have no parent, and we assume the directory has X # files from only one backup X else X cd $diskfile X mdevbase=$diskfile/`echo [01][0-9][0123][0-9].*[a-z].[0-9][0-9] | sed -e 's/ .*$//' -e 's/\.[0-9][0-9]$//'` X cd $workdir X fi X else X mdevbase=$diskfile/$wdir X fi Xelif test $mtype = file ; then X mdevbase=$diskfile Xelif test $mode = get -o $mode = verify ; then X mdevbase=$rewdev Xelif test "$multi" = false ; then X mdevbase=$rewdev Xelse X mdevbase=$norewdev Xfi Xmdev=$mdevbase X X## deal with cpio/dump/restore keys and options X# if the backup/get/verify program is cpio Xcase $bprog in Xcpio) X # check $maxocount X case $maxocount in X [1-9][0-9]*) X : do nothing X ;; X *) X echo "$pr: Maximum output blocks for $mhost:$media in" X echo "$pr: $devdata is '$maxocount'. Quitting." X exit 1 X ;; X esac X # get cpio options X ckey='' # initialize cpio key X for i in $bopts ; do X # see comments in the NOTES file about making X # "cpio ... | dd ... " work, given possible problems with X # cpio output block size, pipesize, dd's ibs and obs, and X # the device driver for the output device; also the size X # $RSH_C on both hosts can handle if were doing a backup X # over the net. X # $cpioobs cpio's output blocksize X # $ckey cpio key (ckey=C$obs || ckey=B) X # $obs from $devdata X # based on pipesize from $SAHOST:$SABIN/getpipesize X case $i in X C) X ckey=${ckey}C$obs # cpio block size is $obs X ibs=$obs # easiest if they match X ;; X DAT1|DAT2|E82|E85|QIC*|TK50|TK70) X continue # this info for humans only X ;; X# TI Sys V can't read multiple cpio archives put on with their -T option X# T) X# ckey=${ckey}T # write portable cpio archives on TI's X# ;; X *) X if test $mistape != true ; then X echo "$pr: dump option '$i' in '$devdata' ignored." X fi X ;; X esac X done X # if $ckey doesn't include "C" then X if echo "$ckey" | grep -v C > /dev/null ; then X ckey=B$ckey X ibs=5120 # make dd ibs match X fi X;; X# $bprog is BSD dump/restore (by some name) X# we build the dump command line here. It's also convenient to build X# most (not all) of the restore key. We'll need to finish the X# job later if we're really doing a get, by asking the user whether X# to do an interactive restore or to restore the entire dump. X*dump*) X # set dump level X case $mode in X full) dlevel=0 ;; X incr) dlevel=$incr ;; X tincr) dlevel=$test_incr ;; X esac X # if we're not supposed to update or we're dumping to the bit-bucket X if test $update != true -o $media = null ; then X updkey= # don't update /etc/dumpdates X else X updkey=u # update /etc/dumpdates X fi X # figure out restore opts key, restore opts, dump key, and dump opts X # we have to deal with DEC_OSF/1 strangeness here for roptkey, since the X # roptkey can't have an "f" in it because rrestore's command syntax is: X # /usr/sbin/rrestore -f host:/device -$rmode$roptkey $ropts X # According to the manual page DEC_OSF/1 doesn't mess with the X # syntax for local restore's, but this works too: X # /usr/sbin/restore -f /device -$rmode$roptkey $ropts X case "$OS_S" in X DEC_OSF/1) roptkey='' ;; X *) roptkey=f ;; X esac X dkey=$dlevel${updkey}f X dopts='' # dump options based on $dkey and $bopts X d2mtype='' # DG dump2's media type option X d2stats='' # DG dump2's statistics report option X X # modify the keys according to dump/restore options, if any X for i in $bopts ; do X case $i in X # "-d" (density in BPI) X # 1600, 3200 and 6250 for 9tracks X # 6670 for tk50's X # ???? for tk70's X # 1000 for QIC11/QIC24/QIC150 carts, X # 23000 for MIPS 120M carts X # 141000 for auspex 8500 exabytes X 1000|1600|3200|6250|6670|23000|141000) X dkey=${dkey}d X ;; X # "-t" (tracks: cartridge only) X # 4 for QIC11, 9 for QIC24, 18 for QIC150 X 4|9|18) X dkey=${dkey}t X ;; X # "-b" (blocking factor: either 512 characters or X # 1024 characters per tape block depending on the OS) X # 126 for videos on suns, 346 for video on DYNIX, X # 100 for auspex 8500 exabytes, X # else any even two-digit number X 100|126|346|[1-9][02468]) X dkey=${dkey}$DRB_K # tapeblock size ... X roptkey=${roptkey}$DRB_K # was specified ... X if test -n "$DRB_K" ; then X ropts="$ropts $i" # and is $i X else X echo "$pr: Blocksize '$i' in $devdata" X echo "$pf: ignored, because this OS does not support it." X fi X ;; X # "-s" (size in feet) X # 11500 for auspex 8500 exabytes X # 70000 for dats X # 165000 for Exabyte 8200s X # 330000 for Exabyte 8500s X # any other three- or four-digit number ending in "00" or "25" X # (see $mdev for why) X 11500|70000|165000|330000|[1-9][02][05]|[1-9][0-9][02][05]) X dkey=${dkey}s # size was specified X ;; X # "c" for Sun cartridge drives X # "C" for Bull cartridge drives X c|C) X # only need to change dump key not restore key for suns X dkey=${dkey}$i # cart was specified (suns) X continue # so $i isn't put in $dopts X ;; X M) X d2mtype="$i $mtype" # dump2's mediatype key and arg X continue # so $i isn't put in $dopts X ;; X s) X d2stats=s # dump2's statistics key X continue # so $i isn't put in $dopts X ;; X DAT1|DAT2|E82|E85|QIC*|TK50|TK70) X continue # this info for humans only X ;; X *) X echo "$pr: I do not understand $bprog option '$i' in '$devdata'" X echo "$pr: Quitting." X exit 1 X ;; X esac X dopts="$dopts $i" X done X X # Dec's OSF/1 version of dump/rdump automatically ejects the tape X # after the dump is done, unless you put the "N" in the dump key. X case "$OS_S" in X DEC_OSF/1) dkey=${dkey}N ;; X esac X X # build backup command for local vs. remote media X # $DRMINUS is for Bull OS, ICL, and other weirdos X # dump2 code is for DG's dump2 X case $bprog in X *dump2) X test -n "$opfifo" && d2opts="$d2opts $DRMINUS$opfifo" X test -n "$d2mtype" && d2opts="$d2opts $DRMINUS$d2mtype" X test -n "$d2stats" && d2opts="$d2opts $DRMINUS$d2stats" X ;; X *) X if test -n "$opfifo$d2mtype$d2stats" ; then X echo "$pr: Data General 'dump2' arguments '$opfifo$d2mtype$d2stats' in '$devdata'" X echo "$pr: do not work on non-DG machines. Quitting." X exit 1 X fi X ;; X esac X case $mhost$diskfile in X $lhost-) X # the "sleep" is to give the shell time to open b.$fsnn.out X bcmd='$bprog $DRMINUS$dkey $mdev $dopts $d2opts $fsdev 1>&8 2> b.$fsnn.out & bpid=$! ; sleep 2 ; tail -f b.$fsnn.out & tailpid=$!' X ;; X *-) X echo "$pr: Cannot dump to standard out on remote host." X exit 1 X ;; X $lhost*) X bcmd='$bprog $DRMINUS$dkey $mdev $dopts $d2opts $fsdev 2>&1 | tee -i b.$fsnn.out' X ;; X *) X bcmd='$bprog $DRMINUS$dkey $mhost:$mdev $dopts $d2opts $fsdev 2>&1 | tee -i b.$fsnn.out' X ;; X esac X;; Xesac X X############################################################################### X## Device testing X## if $demo is false, $check is true, and $mtype isn't dir, file or null ; then X## case $mode in X## get|verify) X## verify read of rewind device X## ;; X## full|incr|tincr|devcheck) X## verify write to rewind *and* norewind devices X## ;; X## esac X## endif X## The actual test code is written to avoid indenting more than one level X X## First, make sure rewind and norewind devices are block/character X## special files (trust symlinks). X## (But don't do it if $mtype is dir or file.) X# The "ls -l" writes to standard error if $rewdev doesn't exist, X# so "wc -l" gives 0. This trickiness is needed because we may be X# dealing with a remote machine. Remote shell (rsh) reports success X# if it had permission to run a command on the remote box, and doesn't X# care if the command itself works or not. Also, we assume symbolic X# links are cool because it's really hard to verify them, especially on X# remote boxes. That's why we egrep for '^[bcl]'. Xif test $mtype != dir -a $mtype != file -a `$ls -l $rewdev | egrep -c '^[bcl]'` -ne 1 ; then X badrewdev=true X echo "$pr: No device node for rewind device '$rewdev'" >> $failrpt Xfi Xif test $mtype != dir -a $mtype != file -a `$ls -l $norewdev | egrep -c '^[bcl]'` -ne 1 ; then X badnorewdev=true X echo "$pr: No device node for norewind device '$norewdev'" >> $failrpt Xfi Xif test "$badrewdev" = true -o "$badnorewdev" = true ; then X echo "$pr: Media data file '$devdata' is wrong." >> $failrpt X echo "$pr: Notify a UNIX System Administrator IMMEDIATELY ! ! !" >> $failrpt X cat $failrpt X exit 1 Xfi X X## Second, set up media test block sizes and test files on the media host. X## Do before all real media tests. Xcase $bprog$multi in Xcpio*) X mtestibs=10b # header file is cpio, backup is cpio X;; X*dump*true) X mtestibs=20b # header file is tar X;; X*dump*) X mtestibs=63k # backup is dump, so choose max dump blocksize X # deal here with special weird mtestibs requirements: X # Bull's B.O.S. can't read more than 60k from a cart X # DYNIX and DYNIX/ptx can't read more than 32k from "xt" devices; X # we could get down to that level, but this ought to be good enough. X case "$OS_S" in X B.O.S.) mtestibs=60k ;; X DYNIX|DYNIX/ptx) mtestibs=32k ;; X esac X;; Xesac X# For media test files, we can't just use /etc/passwd and /etc/group X# because the test files must be modulus 512 in size for cartridge drives X# (a hardware limitation). We also need test files to be modulus 10k for X# some video units (we don't know why, but 1k is too small). On the X# other hand 5k is the max on AT&T 3B5 (coyote), maybe because it's X# pipesize is so strange (6144 characters). So, we create the first and X# second test files on the fly. All media test files should be in a X# world writeable directory, not $workdir, because we may have to create X# it on a remote machine. X# X# We need test files for rewind/norewind device testing and also for X# tape testing for cpio backups. Xcase $mode in Xdevcheck|full|incr|tincr) X eval $SHOWDD Create two test files X echo "script: '$pr', mtestf1 '$mtestf1'; workdir '$lhost:$workdir'" \ X | $bdd of=$mtestf1 bs=$mtestobs conv=sync 2> /dev/null X echo "script: '$pr', mtestf2 '$mtestf2'; workdir '$lhost:$workdir'" \ X | $bdd of=$mtestf2 bs=$mtestobs conv=sync 2> /dev/null X;; Xesac X X## Third, if we're doing a get/verify, make sure we can read the rewind device X## (But check other stuff if $mtype is dir or file) Xwhile test $demo = false -a $check = true -a \( $mode = get -o $mode = verify \) -a $mtype != null ; do X # if we're reading from file or directory, we have simple tests; X # if it's null we don't do anything X case "$mtype" in X dir) X if test ! -d $diskfile ; then X if test $? -ne 0 ; then X echo "$pr: Cannot read $mtype $diskfile. Quitting." X exit 1 X fi X fi X ;; X file) X if test ! -f $diskfile ; then X if test $? -ne 0 ; then X echo "$pr: Cannot read $mtype $diskfile. Quitting." X exit 1 X fi X fi X ;; X esac X if test -z "$parent" -a $mtype != file -a $mtype != dir ; then X eval $SHOWDD Make sure we can read the rewind device X $bdd if=$rewdev of=/dev/null count=1 bs=$mtestibs 2> err.dd X if test $? -eq 0 ; then X rm -f err.dd X else X cat err.dd X eval "$CHKMREAD" X eval "$EXITQ" X continue X fi X fi X break Xdone X X## Fourth, if we're making a backup or doing a devcheck, we check both X## the rewind and norewind device names from $devdata. This is so important X## that we do it whether or not we'll end up using the norewind device. X## (But check other stuff if $mtype is dir, file, or null) X# X# Later on, if it's a cart and we're using cpio, we'll need to test the X# cart to make sure that we can write large amounts of data to it. X# Oddly enough, low density (low "ftpi" (frame tracks per inch)) carts X# work with high density drives if we're only writing a block or two. X# This is strange, but I've tested it pretty extensively in 150M and X# 120M cartridge drives using carts of 8000, 10000, and 12500 ftpi. X# We only have to worry about this if it's cpio because BSD dump takes X# care of this kind of problem for us. X# X# We only intend to do this code once, but we have to use a "while" X# so we can "break" out of it if $rewdev is wrong. Xwhile test $demo = false -a $check = true -a \( $mode = full -o $mode = incr -o $mode = tincr -o $mode = devcheck \) ; do X X # if we're writing to a file or directory, we have simple tests; X # if it's null we don't do anything X case "$mtype" in X dir) X if test ! -d $diskfile ; then X mkdir $diskfile X if test $? -ne 0 ; then X echo "$pr: Cannot create $mtype $diskfile. Quitting." X exit 1 X fi X fi X break X ;; X file) X if test $diskfile != "-" -a ! -f $diskfile ; then X echo "$pr: can we create $diskfile" > $diskfile X if test $? -ne 0 ; then X echo "$pr: Cannot create $mtype $diskfile. Quitting." X exit 1 X fi X fi X break X ;; X null) X break X ;; X esac X X ## First, make sure we can write to the rewind device - the operator may X ## have forgotten to put the drive on line or left off the write ring. X $rm -f $mtestf3 # just to make sure X while : ; do X # write 1st file, rewind media X eval $SHOWDD Make sure we can write to the rewind device X $bdd if=$mtestf1 of=$rewdev bs=$mtestobs 2> err.dd X bddstat=$? X recout=` egrep records err.dd | awk 'NR == 2 {print $1}'` X if test $bddstat -eq 0 -a "$recout" = "1+0" ; then X rm -f err.dd X break X else X cat err.dd X eval "$CHKMWRITE" X eval "$EXITQ" X fi X done X X ## Second, make sure the rewind device name is really a rewind device. X # Write 1st file, rewind media, then read it back out. The count=40 X # prevents humungous read from accidental norewind device, which X # could mean writing to and possibly filling up the filesystem X # containing $mtestf3. X eval $SHOWDD Make sure rewind device name really does a rewind X $bdd if=$mtestf1 of=$rewdev bs=$mtestobs 2> /dev/null X $bdd if=$rewdev of=$mtestf3 bs=$mtestobs count=40 2> err.dd X bddstat=$? X recin=` egrep records err.dd | awk 'NR == 1 {print $1}'` X # if we got a bad read from the media X if test $bddstat -ne 0 -o "$recin" != "1+0" ; then X X exec 1> $failrpt X echo "$pr: Expected '$bdd' status '0'; got status '$bddstat'." X echo "$pr: Expected '1+0 records in/out'; got:" X cat err.dd X echo "$pr: This may be a real HARDWARE problem." X exec 1>&9 X cat $failrpt X eval "$CHKMREAD" X echo "$pr: Quitting." X exit 1 X fi X rm -f err.dd X # input should be identical to output X if test `$cmp $mtestf1 $mtestf3 2>&1 | wc -l` -gt 0 ; then X badrewdev=true X $cmp $mtestf1 $mtestf3 >> $failrpt X echo "$pr: '$mhost:$rewdev' is supposed to be a rewind device but is NOT." >> $failrpt X break # can't reliably test the norewind device now X fi X X ## Third and last, verify the norewind device is a norewind device. X # The structure here is OK since we just verified the rewind device. X # put first file on media, don't rewind X # put different file on media, rewind it X # read first file back out, rewind media X eval $SHOWDD Make sure norewind device name really does not rewind X $bdd if=$mtestf1 of=$norewdev bs=$mtestobs 2> /dev/null X $bdd if=$mtestf2 of=$rewdev bs=$mtestobs 2> /dev/null X $bdd if=$rewdev of=$mtestf3 bs=$mtestobs 2> /dev/null X # input should be identical to output X if test `$cmp $mtestf1 $mtestf3 2>&1 | wc -l` -gt 0 ; then X badnorewdev=true X $cmp $mtestf1 $mtestf3 >> $failrpt X # check for possible reasons X if test `$cmp $mtestf2 $mtestf3 2>&1 | wc -l` -eq 0 ; then X echo "$pr: GACK! The so-called norewind device actually rewinds the $media!" >> $failrpt X fi X echo "$pr: '$mhost:$norewdev' is supposed to be a norewind device but is NOT." >> $failrpt X fi X X break # defense! we only want to do this code once. Xdone X X## Fifth - evaluate and report results of device testing X# (note: keep media test files for later) Xif test "$badrewdev" = true -o "$badnorewdev" = true ; then X echo "$pr: Media data file '$devdata' is wrong." >> $failrpt X echo "$pr: Notify a UNIX System Administrator IMMEDIATELY ! ! !" >> $failrpt X cat $failrpt X exit 1 Xfi X X## Sixth and last - clean up and quit if we were asked only to check the media Xcase $mode in Xdevcheck) X echo "$pr devcheck: The rewind device: '$rewdev' and" X echo "$pr devcheck: the norewind device: '$norewdev'" X echo "$pr devcheck: on media host $mhost PASS the devcheck tests." X exit 0 X;; Xesac X X############################################################################### X X## start the report Xcd $workdir Xexec 1> $report Xecho "#Invocation: $pr $cmdargs" Xecho "#Version: $version" Xecho "#Start time: $date" Xecho "#Workdir: $wdir" Xecho "#Dev Data: $devdata" Xecho "#lhost mhost mode media mdevbase multi OPER voln hfstat" X# print variables (note $hfstat isn't set since the header file hasn't X# been put on the media yet) Xecho "$lhost $mhost $mode $media $mdevbase $multi $OPER $voln ${hfstat-NA}" Xexec 1>&9 X X## OK! Ready to *make* the backup or *get/verify* files from the backup! Xcase $mode in Xfull|incr|tincr) X X # show operator our assumptions X echo "" X echo $pr: X echo "backup media media media backup" X echo "level host alias workdir device program" X echo "------- ------- ------- ------------- --------------- -----------" X echo "$mode $mhost $media $wdir $mdevbase $bprog" X echo "" X echo "$pr: About to backup:" X case $multi$fsbkp in X *false) echo "$devlist (directory, not a filesystem)" ;; X true*) awk ' {print $1 " (" $NF ")" }' $dfout ;; X *) awk '$1 == "'$devlist'" {print $1 " (" $NF ")" }' $dfout ;; X esac X echo "" X X # later on, if we're doing a cpio onedisk backup to a cart, we'll X # need this $mtestf4 for every cart X if test $bprog = cpio -a $mdev = $rewdev -a $mtype = cart ; then X # create 150k test file - do it in 50k X # chunks because many machines can't X # do it all at once X eval $SHOWDD Create 150k test file for carts X echo "$pr: $workdir 150k $mtestf4" | $bdd of=$mtestf4 bs=50k conv=sync 2> err.dd X echo "$pr: $workdir 150k $mtestf4" | $bdd of=$mtestf4 bs=50k conv=sync seek=1 2> err.dd X echo "$pr: $workdir 150k $mtestf4" | $bdd of=$mtestf4 bs=50k conv=sync seek=2 2> err.dd X # show user if it's not 150k X $ls -l $mtestf4 | grep -v ' 153600 ' X fi X X ## do the backup X fsnn=00 # 2-digit filesystem number X # put the list of known problems into $problist and X # list of known not_problems into $falseprob for later check X echo "$KNOWNPROBS" > $problist X echo "$KNOWNFALSEPROBS" > $falseprob X # start the exit status list X echo '#bstat devname fsname known_errors' > $statlist X # if multi-volume backup or it's a onedisk but we're putting on a X # header anyway, put tar/cpio header file onto media; X # the header is tar if we're using dump, cpio if we're using cpio; X # the header includes $dfout, $report, all scripts, and any/all X # config files ($hdir/bkp.media overrides $DTGT/bkp.media) X #if test $multi = true -o $header = true ; then X if test $multi = true ; then X # put required files in $workdir X # we must make sure we have local paths, not absolute paths X x="$dfout $report $pr `basename $bdd` bkp.media" X ln ../$pr . X cp $bdd . X cp $devdata bkp.media X case "$multitype" in X list) X # so we always have the standard name 'bkp.listf' X bnlistf=`basename $listf` X cp $listf $bnlistf X ln $bnlistf bkp.listf X ;; X esac X cp ../bkp.donot . 2> /dev/null && x="$x bkp.donot" X cp ../bkp.host . 2> /dev/null && x="$x bkp.host" X test -f bkp.listed && x="$x bkp.listed" X test -f bkp.listf && x="$x bkp.listf" X cp ../bkp.media . 2> /dev/null && x="$x bkp.media" X cp ../bkp.nofm . 2> /dev/null && x="$x bkp.nofm" X cp $DTGT/bkp.site . 2> /dev/null && x="$x bkp.site" X test -n "$bnlistf" && x="$x $bnlistf" X # added because NonStop-UX and other OS have multiple X # filesystem types and it's often documented in thes files X for f in $fstablist ; do X cp /etc/$f . 2> /dev/null && x="$x $f" X done X headlist="$x" X if test $bprog = cpio ; then X echo "$pr: ================================backup>>> alldisks_header (cpio)" X else X echo "$pr: ================================backup>>> alldisks_header (tar)" X fi X # make absolutely sure the header gets on the media - don't X # continue until it does X X eval "$MDEV" X while : ; do X # each case has 3 lines X # 1) echo commented command line to $report X # 2) echo command line to screen X # 3) do or "demo" the command (prettified by ";:") X eval $SHOWDD Put alldisks header on $mhost:$media using $bdd X case $bprog$demo in X cpiotrue) X echo \#find $headlist -print "| { cpio -oc$ckey $copt" '2> err.head ; echo $? > stat.head ; } | {' $bdd of=$mdev obs=5k 2> err.dd '; echo $? > stat.dd ; }' >> $report X echo find $headlist -print "| { cpio -oc$ckey $copt" '2> err.head ; echo $? > stat.head ; } | {' $bdd of=$mdev obs=5k 2> err.dd '; echo $? > stat.dd ; }' X echo $pr: demo find $headlist -print "| { cpio -oc$ckey $copt" '2> err.head ; echo $? > stat.head ; } | {' $bdd of=$mdev obs=5k 2> err.dd '; echo $? > stat.dd ; }' X ;; X cpio*) X echo \#find $headlist -print "| { cpio -oc$ckey $copt" '2> err.head ; echo $? > stat.head ; } | {' $bdd of=$mdev obs=5k 2> err.dd '; echo $? > stat.dd ; }' >> $report X echo find $headlist -print "| { cpio -oc$ckey $copt" '2> err.head ; echo $? > stat.head ; } | {' $bdd of=$mdev obs=5k 2> err.dd '; echo $? > stat.dd ; }' X : ; find $headlist -print | { cpio -oc$ckey $copt 2> err.head ; echo $? > stat.head ; } | { $bdd of=$mdev obs=5k 2> err.dd ; echo $? > stat.dd ; } X ;; X *dump*true) X echo \#\{ tar cfb - 20 $headlist 2> err.head '; echo $? > stat.head ; } | {' $bdd of=$mdev obs=10k 2> err.dd '; echo $? > stat.dd ; }' >> $report X echo \{ tar cfb - 20 $headlist 2> err.head '; echo $? > stat.head ; } | {' $bdd of=$mdev obs=10k 2> err.dd '; echo $? > stat.dd ; }' X echo $pr: demo \{ tar cfb - 20 $headlist 2> err.head '; echo $? > stat.head ; } | {' $bdd of=$mdev obs=10k 2> err.dd '; echo $? > stat.dd ; }' X ;; X *dump*) X #echo \#\{ tar cfb - 20 $headlist 2> err.head '; echo $? > stat.head ; } | {' $bdd of=$mdev obs=10k 2> err.dd '; echo $? > stat.dd ; }' >> $report X #echo \{ tar cfb - 20 $headlist 2> err.head '; echo $? > stat.head ; } | {' $bdd of=$mdev obs=10k 2> err.dd '; echo $? > stat.dd ; }' X #: ; { tar cfb - 20 $headlist 2> err.head ; echo $? > stat.head ; } | { $bdd of=$mdev obs=10k 2> err.dd ; echo $? > stat.dd ; } X echo \#\{ tar cfb $tarhead 20 $headlist 2> err.head '; echo $? > stat.head ; } ; {' cat $tarhead | $bdd of=$mdev obs=10k 2> err.dd '; echo $? > stat.dd ; }' >> $report X echo \{ tar cfb $tarhead 20 $headlist 2> err.head '; echo $? > stat.head ; } ; {' cat $tarhead | $bdd of=$mdev obs=10k 2> err.dd '; echo $? > stat.dd ; }' X : ; { tar cfb $tarhead 20 $headlist 2> err.head ; echo $? > stat.head ; } ; { cat $tarhead | $bdd of=$mdev obs=10k 2> err.dd ; echo $? > stat.dd ; } X# { tar cfb $tarfile 20 $headlist 2> err.head ; echo $? > stat.head ; } ; { $bdd if=$tarfile of=$mdev obs=20b 2> err.dd ; echo $? > stat.dd ; } X ;; X esac X cat err.head err.dd | tee -a $report X hfstat=`cat stat.head``cat stat.dd` X # if the disk holding $bhdir fills up, $hfstat could X # be a null string, and "sh" treats a null string X # as numerically equal to zero, so test carefully X if test -z "$hfstat" ; then X echo "$pr: The disk holding $bhdir" X echo "$pr: is probably full." X df $bhdir # works on most newer UNIX's X echo "$pr: Please consult a UNIX sysadmin." X echo "$pr: Quitting." X exit 1 X # else if $hfstat is "00" we are ok X elif test "$hfstat" -eq 0 ; then X break X # else we've got a problem X else X echo "$pr: Something went wrong with putting the $headprog header archive" X echo "$pr: on the $media. Check:" X eval "$CHKMWRITE" X eval "$EXITQ" X fi X done X fi X X # put backups on tape, and keep track of which filesystems are on X # which tapes X voln=1 # volume number of cart/dat/tape/tk/video X sumrecin=0 # sum of dd output records for cpio archives X obleft=$maxocount # number of output blocks left on media X nearend=false # are we so near the end of the media that X # we have to change tapes X echo $sumrecin $obleft > $pass # initialize $pass X /bin/rm -f $firstblist X for fsdev in $devlist ; do X eval "$FSNNPLUS1" X eval "$MDEV" X case $fsbkp in X # occasionally we back up a directory X false) X fs=$fsdev X ;; X # but normally we're backing up a filesystem X *) X # get $fs from $dft2 - if we're backing up a filesystem X # listed in $nobkp, $fs will be in $dft2 but not $dfout X fs=`egrep "^$fsdev[ ]" $dft2 | awk '{print $NF}'` X ;; X esac X echo "$pr: ================================backup>>> $fs" X X # if we're using some version of dump X case $bprog in X *dump*) X # special code for NonStop-UX4.0 which has both X # vxfs and ufs filesystem types: choose which dump X # to use ufsdump or vxdump. X case "$OS_S$OSLEVEL_S" in X NonStop-UX4.0) X fstype=`awk '/^#/ {next} ; $3 == "'$fs'" {print $4}' /etc/vfstab` X case $fstype in X ufs) bprog=$DUMP_P ;; X vxfs) bprog=/sbin/vxdump ;; X esac X ;; X esac X # echo the backup command - trickier than you'd think!! X # we need the x=`echo ...` to get the desired evaluation X # the first sed expression compresses whitespace to one X # space, the second one puts a backquote in front X # of every single shell-special character we might see X # in $bcmd, the third puts single quotes around $! in X # case we are dumping to standard out X x=`echo $bcmd | sed -e 's/[ ][ ]*/ /g' -e 's/[&;|>]/\\\\&/g' -e "s/\$\!/'\$\!'/"` X eval echo "$pr: $x" X eval echo "\#bcmd: $x" \>\> $report X X # if we're rdumping to a disk file on another host X # then make sure it exists, since SunOS, Solaris, X # and perhaps other rdump's seem to require the X # file to exist before it can open the file for X # writing the dump archive. X case $bprog$mtype in X *dump*file|*dump*dir) X if test $mhost != $lhost ; then X $rsh $mhost touch $mdev X fi X ;; X esac X X # now do it for real (but sync twice first just in case) X sync ; sync X # if we were dumping to a tape or diskfile X if test -z "$diskfile" -o "$diskfile" != "-" ; then X eval $bcmd # do dump in forground X eval bstat$fsnn=$? # get exit status X # else we're dumping to standard out X else X eval $bcmd # do dump in background X wait $bpid # wait for it X eval bstat$fsnn=$? # exit status from wait X echo $epre "$pr: Killing 'tail' on b.$fsnn.out: "$esuf X kill -9 $tailpid 2> /dev/null # kill tail X fi X # If we couldn't read/write dumpdates, then fix, X # report, and break out of filesystem loop. If X # it happened when trying to update dumpdates, X # this is the best we can do because dump has X # already written the entire archive before X # trying the update. We might handle this earlier X # with $HACK4HPUX8, but probably not. X updateprob=`egrep '/etc/dumpdates: Permission denied' b.$fsnn.out` X if test -n "$updateprob" ; then X echo "$pr: There were permissions problems reading or writing /etc/dumpdates." X echo "$pr: Permissions were (using 'ls -l /etc/dumpdates'):" X echo "$pr: `ls -l$LSGROUP_K /etc/dumpdates`" | tee -a $workdir/$report X chmod 664 /etc/dumpdates X chgrp operator /etc/dumpdates X echo "$pr: Fixed permissions are now:" X echo "$pr: `ls -l$LSGROUP_K /etc/dumpdates`" | tee -a $workdir/$report X echo "$pr: Try the backup again - it should work next time." X # break out of loop so we can do postprocessing X break X fi X # If we couldn't read the actual device we're dumping, X # then fix and try the dump again. This strategy works X # because we know dump hasn't moved the tape. X permprob=`egrep '[cC]annot open' b.$fsnn.out` X if test -n "$permprob" ; then X # actual device dumped is often raw device, but X # can be block device under some configurations X # like DGUX with disk-spanning filesystems X actualdev=`echo $permprob | awk '{print $NF}'` X if test -n "`echo $actualdev | egrep '^/dev/[-a-zA-Z0-9_:/]*$'`" ; then X echo "$pr: NOTE: There were permissions problems reading the actual device." X echo "$pr: Permissions were (using 'ls -l$LSGROUP_K $actualdev'):" X echo "$pr: `ls -l$LSGROUP_K $actualdev`" | tee -a $workdir/$report X chgrp operator $actualdev X chmod g+r $actualdev X echo "$pr: Fixed permissions are now:" X echo "$pr: `ls -l$LSGROUP_K $actualdev`" | tee -a $workdir/$report X echo "$pr: Trying the dump again." X mv b.$fsnn.out b.$fsnn.out.prob X sync ; sync X eval $bcmd X eval bstat$fsnn=$? X fi X fi X # else we're using cpio - much trickier than dump/rdump X ;; X cpio) X # There's a ton of stuff to do here as a frontend X # to cpio. As much as possible, we basically have X # to do everything that BSD dump does. X X ## The first BIG problem is to generate a list of files X # for $fs *only*. This list has to exclude any X # filesystem mounted on top of the one we're backing X # up, e.g. we exclude "/usr" if we're backing up "/". X # We also exclude anything in $nobkp if it exists. X # Once the list is generated we can basically do: X # "cd $fs ; find $top $stayinfs $newer | fgrep -v -f $filter" X # This requires adding a leading "X" and trailing "/" in X # each dir/fs name. X X # First, build $filter to screen mounted subdirs X # and anything relevant in $nobkp from list. X # We're trying to create list of *excluded* stuff here. X # Use $dft2, not $dfout, since it has all filesystems. X cd $workdir X case "$fs$fsbkp" in X # we're backing up the root filesystem X /true) X # egrep -v filters root, awk appends "/" X egrep -v "^$fsdev[ ]" $dft2 \ X | awk '{print $NF"/"}' > $filtert1 X if test -r $nobkp ; then X cat $nobkp >> $filtert1 X fi X # AIX 3.2 cpio does "exit 2" if it sees devices, X # AIX 3.[01] cpio does "exit 0" but complains X # if it sees devices, X case "$OS_S" in X AIX) echo /dev >> $filtert1 ;; X esac X # sed substitutes leading "X" and trailing "/" X sed -e 's,^/,X,' -e 's,[^/]$,&/,' $filtert1 > $filter X ;; X # we're backing up some other filesystem X *true) X # awk appends "/", egrep matches for $fs, X # next egrep -v filters $fs itself X # Second egrep can't be grep because X # a bug in AIX 2.2.1 grep -v yields a X # newline when it's input is empty! X # Bummer because Ultrix 2.0 egrep -v X # has the same bug. X awk '{print $NF"/"}' $dft2 \ X | egrep "^${fs}/" \ X | egrep -v "^${fs}/$" > $filtert1 X if test -r $nobkp ; then X # sed appends "/", egrep matches $fs X # egrep -v filters $fs itself X sed -e 's,$,/,' $nobkp \ X | egrep "^$fs/" \ X | egrep -v "^$fs/$" >> $filtert1 X fi X # sed substitutes "X" for $fs"/" X sed -e "s,^$fs/,X," $filtert1 > $filter X ;; X # $fs isn't a filesystem so create an empty $filter X *) X > $filter X ;; X esac X X # Second, put list of files at the top level of $fs X # in $top X # X # sneaky: .?* matches because ".." always exists X # Pray there aren't too many files at top level of $fs. X # (This could be made slightly more efficient, but X # save that for later.) X # Anyway, take our first cut at $top: X top=`cd $fs ; echo .?* * | sed -e 's/\.\.//'` X # if $filter has real stuff in it then use it to X # strip mounted filesystems from $top. X if test -s $filter ; then X # Create $topfilter: the sed removes two-plus X # level subdirs (with two slashes) since it's X # too hard to deal with filtering those, X # and changes trailing "/" to "X" for fgrep X # which doesn't support metacharacters X sed -e '/\/.*\//d' -e 's,^.\(.*\)/$,X\1X,' $filter > $topfilter X # Needed the following "if test ..." to X # deal with HP-UX's fgrep -v, which fails if X # handed a null filter file. But what the X # heck, this is smarter anyway. X if test -s $topfilter ; then X # "for" echo's X${i}X thru fgrep filter X # thru sed to strip "X"s through X # awk to merge back into one line X for i in $top ; do echo X${i}X ; done \ X | fgrep -v -f $topfilter \ X | sed -e 's/^X\(.*\)X$/\1/' \ X | awk '{printf "%s ", $1}' > $toplist X top=`cat $toplist` X fi X fi X X # Third, start $flist (list of files to be backed up). X # Begin with hard-coded paths for $report and $flist; X # we have to do this for ease of cpio file restoration. X # Unfortunately, this means that we can only run one X # backup at a time. X echo "$pr: generating list of files to put in cpio archive for $fs" X echo /usr/tmp/$report > $flist X echo /usr/tmp/$flist >> $flist X X # Fourth, put list of files we're backing up into $flist X # If we're doing an incremental of $fs, find out when X # it's last successful full backup was. X newer='' X if test $mode = incr ; then X lastfull=`grep '^full[ ].*[ ]'$fs'[ ]*$' $bdatef | awk '{print $2}'` X if test -n "$lastfull" ; then X touch $lastfull $touchf X if test $? -ne 0 -o ! -f $touchf ; then X echo "$pr: Something went wrong with creating the touch file. Quitting." X exit 1 X fi X newer="-newer $touchf" X fi X fi X # try to force "find" to stay in the filesystem X # use $FINDXDEV_S if we have it, else try "FINDFSTYPE_S" X if test -n "$FINDXDEV_S" ; then X stayinfs=$FINDXDEV_S X elif test -n "$FINDFSTYPE_S" ; then X stayinfs=$FINDFSTYPE_S X else X stayinfs='' X fi X cd $fs X # get the start date of this backup X # we'd like datecpio to be able to set to the nearest X # second, unfortunately although date can report it X # that way Sys V touch can't set it that way. Drat. X datecpio=`date '+%m%d%H%M%y%t%a %h %d %H:%M 19%y'` X # ideally we'd sort the output from find, but it X # could be too big for sort to handle which would X # be a bummer. X # At last, we can use $top and $filter to generate X # flist: X if test -s $workdir/$filter ; then X # sed's add and strip an "X" for fgrep filter X find $top $stayinfs $newer -print | sed -e 's/^/X/' | fgrep -v -f $workdir/$filter | sed -e 's/^X//' >> $workdir/$flist X else X find $top $stayinfs $newer -print >> $workdir/$flist X fi X rm -f $touchf X X # Fifth and last, put $report and $flist into /usr/tmp X # where we're planning to back them up *first*! X # just in case we can save some space, try to hardlink X # them to /usr/tmp - don't want to archive a symlink! X # Remove them from /usr/tmp to prep for link attempt. X echo "#cpio archive of '$fs' filesystem" >> $workdir/$report X rm -f /usr/tmp/$flist /usr/tmp/$report X ln $workdir/$flist $workdir/$report /usr/tmp 2> /dev/null \ X || cp $workdir/$flist $workdir/$report /usr/tmp X # need to do this because /usr/tmp may not have enough room for $flist X if test $? -ne 0 ; then X echo "$pr: 'cp $workdir/$flist /usr/tmp' failed" | tee -a $workdir/b.$fsnn.out X echo "$pr: Backup of '$fs' ABORTED, need more room in /usr/tmp." | tee -a $workdir/$b.$fsnn.out X break X fi X X ## The second BIG problem is that our backup may not X # fit on the media. So we have to pipe the cpio into X # a while loop which manages the process of changing X # tapes and writing the archive onto the media. X fsvoln=1 # volume number for cpio archive of *this* filesystem X recinint= # dd records in (integer truncation) X recoutint= # dd records out (integer truncation) X # get info from initialization or "| while" loop X set `cat $pass` X sumrecin=$1 X obleft=$2 X ## if earlier cpio archives filled up most of the X # current volume, change the media. X # "100" is an arbitrary small number X if test $obleft -lt 100 ; then X # we use nearend later when tracking the X # number of volumes in the backup X nearend=true X voln=`expr $voln + 1` X sumrecin=0 X obleft=$maxocount X eval "$REW" X echo "$pr: Please put in $media volume $voln" X eval "$BREAKQ" X fi X cd $fs X # have to use a file to record cpio and dd exit status X # This is weird: "{ date ; x=$? ; } ; echo $x" works X # but "{ date ; x=$? ; } | cat ; echo $x" fails X # We'll break out of the while when we're done or if X # the user says to quit X echo "$pr: dd'ing archive of '$fs' onto filesystem volume $fsvoln" X echo "$pr: { cpio -oc$ckey < /usr/tmp/$flist 2> $workdir/err.cpio ; echo \$? > $workdir/stat.cpio ; } \\" X echo "$pr: | while : ; do" X { cpio -oc$ckey < /usr/tmp/$flist 2> $workdir/err.cpio ; echo $? > $workdir/stat.cpio ; } \ X | while : ; do X cd $workdir X ## but do some initial media checking first X # if we're not an alldisks then it's OK for us X # to check media for write protection or X # other problems. X # If we *are* doing an alldisks, it would still X # be OK to check if we're at the beginning X # of a tape, but since I don't know what X # happens when cpio hits EOT there's no way X # to test for this (yet). X if test $mdev = $rewdev ; then X eval $SHOWDD Make sure we can write to this volume X $bdd if=$mtestf1 bs=$obs of=$rewdev count=1 2> err.dd X if test $? -ne 0 ; then X cat err.dd | tee -a b.$fsnn.out X eval "$CHKMWRITE" X eval "$BREAKQ" X # continue if we don't break out X continue X fi X fi X X # if it's a cart, test it for density (ftpi) X # compatibility. We do this by trying to write X # thirty blocks to the cart. If this fails X # we have a problem. Empirical tests show that X # it will fail within eighteen blocks (and X # more often with fourteen or even seven), X # but we'll write thirty just to make sure. X # Also, only do this if it's a onedisk. X # We may never get here but if we do this X # test is very important. X if test $mtype = cart -a $mdev = $rewdev ; then X # write it to cart (use conv=sync in X # case we fill up /tmp so it's not 150k) X eval $SHOWDD Try to write 150k test file to $media to check density X $bdd if=$mtestf4 bs=$obs of=$rewdev count=30 conv=sync 2> err.dd X if test $? -ne 0 ; then X cat err.dd | tee -a b.$fsnn.out X echo "$pr: Your $mtype is incompatible with" X echo "$pr: the density of drive $mhost:$media." X echo "$pr: Replace your $mtype with a 12,500ftpi $mtype." X eval "$BREAKQ" X # continue if we don't break out X continue X fi X fi X X ## ok, now we're finally putting the cpio X ## archive on the media X icount=`expr $obleft \* $obs / $ibs` X # if we're writing to a local archive X if test $MHOST = $LHOST ; then X echo "$pr: $bdd of=$mdev ibs=$ibs obs=$obs count=$icount 2> err.dd" X eval $SHOWDD Putting archive on this volume X $bdd of=$mdev ibs=$ibs obs=$obs count=$icount 2> err.dd X bddstat=$? X # else we're doing backup over the net X # we have to split up archive into 1k blocks X # before sending it over the net X else X realmhost=$MHOST X eval $SHOWDD Putting archive on this volume, X eval $SHOWDD using one to split and the other to join X echo "$pr: { MHOST=$LHOST ; $bdd ibs=5k obs=1k count=$icount 2> err.split ; echo \$? > stat.split ; } \\" X echo "$pr: | { MHOST=$realmhost ; $bdd of=$mdev ibs=1k obs=$obs 2> err.join ; echo \$? > stat.join ; }" X { MHOST=$LHOST ; $bdd ibs=5k obs=1k count=$icount 2> err.split ; echo $? > stat.split ; } \ X | { MHOST=$realmhost ; $bdd of=$mdev ibs=1k obs=$obs 2> err.join ; echo $? > stat.join ; } X splitstat=`cat stat.split` X joinstat=`cat stat.join` X bddstat=$splitstat$joinstat X # try to ignore data from split X grep 'records in' err.split > err.dd X grep 'records out' err.join >> err.dd X fi X # pass info to parent shell X echo $bddstat > stat.dd X cat err.dd >> b.$fsnn.out X echo $fs volume $fsvoln dd status: $bddstat >> b.$fsnn.out X # the semicolon in the awk shouldn't be needed, X # but the AIX 3.1 version requires it X recinint=` awk -F+ '$2 ~ /records in/ && $1 ~ /^[0-9][0-9]*$/ {x=$1} ; END {if (x == "") x=0 ; print x}' err.dd` X recoutint=`awk -F+ '$2 ~ /records out/ && $1 ~ /^[0-9][0-9]*$/ {x=$1} ; END {if (x == "") x=0 ; print x}' err.dd` X rm -f err.dd X # if we had a problem or this filesystem is done X if test $bddstat -ne 0 -o $recoutint -ne $obleft ; then X sumrecin=`expr $sumrecin + $recinint` X # if we had a problem with this X # filesystem, change the media X if test $bddstat -ne 0 ; then X obleft=0 # force change X # else we're ok X else X # this is a holdover from when we supported different block sizes, X # but it could be simplified to: X # obleft=`expr $maxocount - $sumrecin` X obleft=`expr $maxocount - \( $sumrecin \* $ibs / $obs \)` X fi X # pass info from this "| while" X # subshell to its parent X echo $sumrecin $obleft > $pass X if test $bddstat -eq 0 ; then X break X else X errs='err.split err.join err.dd' X for err in $errs ; do X if test -f $err ; then X echo $err X cat $err X fi X done X echo "$pr: Backup of '$fs' volume $fsvoln ABORTED." | tee -a b.$fsnn.out X # exit of "| while" subshell X # should abort only this X # filesystem X exit 1 X fi X # else we need to change volumes for this filesystem X else X sumrecin=0 X obleft=$maxocount X # pass info from this "| while" X # subshell to its parent X echo $sumrecin $obleft > $pass X # make sure the media gets rewound X eval "$REW" X fsvoln=`expr $fsvoln + 1` X # emulate dump's "Change Volumes" message X echo "$pr: Change Volumes: put in filesystem '$fs' volume $fsvoln" | tee -a b.$fsnn.out X eval "$BREAKQ" X fi X done X # end of "| while" loop X echo "$pr: done" X # attempt to put cpio archive on $media is done. X X ## finish up the work for this cpio archive X cd $workdir X # show the user cpio's message if any X cat err.cpio X cat err.cpio >> b.$fsnn.out X cpiostat=`cat stat.cpio` X # The AIX 3.2 version of cpio has several "features" X # 1) it won't back up special files or FIFOs (named X # pipes); when asked to do so it exits with X # status "2" and says something like: X # cpio: special file not archived X # 2) if cpio is asked to back up a file which doesn't X # exist, it exits with status "2" and says roughly: X # < tmp/Ex20006 > ? X # (Other versions of cpio complain about missing files X # but still exit with status 0.) X # If these are the only problem in the logs, we can X # safely "lie" about the exit status of the cpio X # process. Lines we don't worry about in err.cpio X # under AIX 3.x look like this: X # cpio: special file not archived X # < tmp/Ex20006 > ? X # cpio: 0511-025 Cannot get information about /ingres/data/default/replicatedb/aaaaabgn.t00 X # 10 blocks X # Hopefully, err.cpio includes only lines we don't X # worry about. X case $OS_S$cpiostat in X AIX2) X nlines=`wc -l < err.cpio` X nottoworry=`egrep -c '^[0-9]* blocks$|special file' err.cpio` X missingfiles=`awk ' X /^< .+ > \?$/ {print $2} X /cpio: .*special file <.+> not archived/ {print substr($4,2,length($4)-2)} X /cpio: .*Cannot get information about / {print $NF}' X ' err.cpio` X # make sure any supposedly missing files X # are really missing X x=0 X if test -n "$missingfiles" ; then X cd $fs X for f in $missingfiles ; do X test ! -f $f && x=`expr $x + 1` X done X cd $workdir X fi X nottoworry=`expr $nottoworry + $x` X if test $nlines -eq $nottoworry ; then X cpiostat=0 X fi X ;; X esac X echo $fs cpio status: $cpiostat >> b.$fsnn.out X cpiostat=$cpiostat`cat stat.dd` X rm -f err.cpio X eval bstat$fsnn=$cpiostat X # if cpio is successful and we're updating X if test $cpiostat -eq 0 -a $update = true ; then X if test -f $bdatef ; then X # the sed is a tad clumsy because $fs X # has slashes in it X sed -e 's,^'$mode'[ ].*[ ]'$fs'[ ]*$,,' -e '/^[ ]*$/d' $bdatef > $bdatef.tmp X fi X echo "$mode $datecpio $fs" >> $bdatef.tmp X sort +7 -8 +0 -1 $bdatef.tmp > $bdatef X rm -f $bdatef.tmp X fi X ;; X esac X X ## Kevin Malloy put this in - I suppose it's needed X if test "$OS_S" = dgux ; then X sleep 60 X fi X X ## warn about known problems in this backup (see $KNOWNPROBS X ## and $KNOWNFALSEPROBS) X bprogerr="`fgrep -f $problist b.$fsnn.out | fgrep -v -f $falseprob`" X test -n "$bprogerr" && bprogerr=" $bprogerr" X eval echo \""\$bstat$fsnn $fsdev $fs$bprogerr"\" \>\> $statlist X X ## report on first backups on each tape as we go along X # We don't care about media write errors on the first X # backup since that only means the tape was bad or X # too short. The operator just restarts these, which X # doesn't add a new volume to the set. X if test $fsnn -eq 1 ; then X echo "Volume '$voln': First backup is $fs" >> $firstblist X # else if this backup is a dump and it got media write errors, X # then it started in the middle of the media and had to be X # restarted with a new volume. It's important to get X # dump's "write error" message right. X # Some message types (with samples from the listed OS): X # Pyramid OSx, Ultrix 2.0/3.0, SunOS 3.2: X # DUMP: Write error on tape 4 X # CCI SysV, Gould UTS 2.1a, Pyramid OSx, Seguent DYNIX: X # DUMP: Tape write error on tape 1 X # 4.3BSD, CCI BSD, Mt. Xinu BSD, SunOS 4.X: X # DUMP: Tape write error 277 feet into tape 4 X # DUMP: Write error on tape 1 X # Bull B.O.S. 02.00: X # FSDUMP: Tape write error 815 feet into tape 1 X # SVR4 variants from NCR and ???: X # UFSDUMP: ????? X # SVR4 variants from Pyramid: X # UFSDUMP: Tape write error: EOT (end of tape) encountered 419 feet into tape1 X # DG/UX says X # write: No space left on device X # Error writing tape: Address already in use X # but notice that it does *not* say "DUMP: whatever". X # We rely on this. X # cpio - don't know what this looks like, maybe we avoid anyway X elif egrep 'DUMP:.* [Ww]rite error:* .* tape *[1-9]' b.$fsnn.out > /dev/null ; then X voln=`expr $voln + 1` X echo "Volume '$voln': First backup is $fs" >> $firstblist X # else we are doing a cpio alldisks backup and we got so close X # to the end of the media that we had to prompt for a new one X # before this cpio archive could start X elif test "$nearend" = true ; then X echo "Volume '$voln': First backup is $fs" >> $firstblist X nearend=false X fi X # else do nothing - this backup started in the middle X # of the media but did not run out room. X X ## Did this backup take more than one volume? In other X ## words, was it continued onto the next tape? X # This can happen if: X # a) we're doing a onedisk backup that won't fit on one tape X # b) we're doing an alldisks backup using cpio X # c) we're doing an alldisks backup using a version of dump X # that knows how to handle EOT (e.g. DG's "dump2" and X # Solaris 2.X "ufsdump") X # d) we're doing an incremental alldisks backup, and an X # incremental of one of the filesystems is too big to fit X # on one tape X # X # The key is to look for the following messages in X # the b.$fsnn.out file: X # This alldisks script says "Change Volumes", X # SunOS 4.0.3 and Solaris 2.2 say "Change Volumes" too, X # OSF from DEC says "Change Cartridges", X # DG's "dump2" says "dump2: Time to change tapes." - dump2 X # does this even when it hits EOT on a video drive when using X # using the -M option - gads! X # Solaris 2.2 ufsdump says: X # DUMP: End-of-tape detected X # DUMP: Change Volumes: Mount volume #N X # All others say "Change Tapes." when it's time to start the X # next tape. X # X # Unfortunately, some versions of dump say "Change Tapes" X # when they are rewriting the volume, too: X # ULTRIX V3.1 dump gets a -SIGTERM, it says X # DUMP: SIGTERM() try rewriting X # DUMP: Rewriting attempted as response to unknown signal. X # DUMP: Change Tapes: Mount tape #1 X # X # Pyramid's OSx "dump" says: X # DUMP: Tape write error on tape 1 X # ..... X # DUMP: replace the faulty tape with a new one; X # DUMP: this dump volume will be rewritten. X # DUMP: Change Tapes: Mount tape #1 X # X # Pyramid's SVR4 OSx "ufsdump" says: X # UFSDUMP: Tape write error: EOT (end of tape) encountered 419 feet into tape1 X # UFSDUMP: NEEDS ATTENTION: Do you want to restart?: ("yes" or "no") X # UFSDUMP: This tape will rewind. After it is rewound, X # UFSDUMP: replace the tape and this dump volume will be rewritten, X # UFSDUMP: or abort and restart the dump, specifying correct tape capacity. X # UFSDUMP: Closing tape device X # Note that if it hits premature EOT, X # it never says "Change Tapes: Mount tape #1", X # but it does say "Change Tapes: Mount tape #2" (and 3, 4, ...) X # and it also says "will be rewritten" X X # So, we have to get rather tricky. X x=`egrep -c 'Change Tapes|Change Volumes|Change Cartridges|change tapes' b.$fsnn.out` X y=`egrep -c 'try rewriting|will be rewritten' b.$fsnn.out` X z=`egrep -c 'Mount tape #1' b.$fsnn.out` X if test $y -eq 1 -a $z -eq 0 ; then X y=0 X fi X x=`expr $x - $y` X while test $x -gt 0 ; do X voln=`expr $voln + 1` X x=`expr $x - 1` X echo "Volume '$voln': First backup is $fs (continued)" >> $firstblist X done X done X ## finished with writing backup to media!! X X ## do $REW/$OFFLINE as soon as loop finishes so user doesn't X ## have to wait X # if we're verifying this backup, rewind now, take it offline X # after the verify completes X if test $verifytoo = true ; then X eval "$REW" X # else do $OFFLINE work in "/" in case user wants to X # umount a filesystem we may have just backed up X # and do it in background so operator doesn't have to wait as long X else X cd / X eval "$OFFLINE" & X fi X cd $workdir # now finish up in $workdir X echo "Volume '$voln': Last volume." >> $firstblist X rm -f $pass X X ## generate report for mailing to $rptto. Report to include: X # put standard out in $report X exec 1>> $report X echo "#lhost mhost mode media mdevbase multi OPER voln hfstat" X # print variables (if $hfstat is set use it else substitute "NA") X echo "$lhost $mhost $mode $media $mdevbase $multi $OPER $voln ${hfstat-NA}" X cat $statlist $firstblist X if test -s $nobkptmp ; then X sed -e 's/^\[[ ]*\]\(.*\)\$/#Not backed up: \1/' $nobkptmp X fi X echo "#End time: `date`" X exec 1>&9 X X ## mail semi-final backup report to $rptto X eval "$MAILRPT" X X ## get operator info - known problems and operator report X # Give BIG warning message if we had problems (see $KNOWNPROBS) X # exit status 0 or 1 are OK for dump, but exit status 1 bad for cpio X awk ' X BEGIN {bprog="'$bprog'"} # get $bprog X $0 ~ /^\#bstat/ {next} # skip header if any X NF != 3 {print; next} # we have known problems X $1 > 1 {print; next} # exit status > 1 always bad X $1 == 1 && bprog ~ /cpio/ {print; next} # status 1 bad for cpio X ' $statlist > $statprob X # if we have no problems, clean up X if test ! -s $statprob ; then X rm -f $statprob $probsent X # else report them if we have to X else X # foreach problem filesystem X grep '^[0-9][0-9]* ' $statprob \ X | while read probstat probfs probdir probdes ; do X # if the problem has been reported X if test -f $probsent && egrep " $probfs " $probsent ; then X : do nothing - we already tried to report it X # else get ready to report it now X else X echo "$wdir $probstat $probfs $probdir $probdes" | tee -a $probsend X # "DUMP: read error! sector 49310 of /dev/rdsk/c0t1d0s6" (Solaris 2.3 ufsdump got a block read error) X if egrep "$probfs.*(bread|read error!)" $statprob > /dev/null ; then X echo "$pr: WARNING! Block read errors found!" X echo "$pr: Block read errors could mean either:" X echo "$pr: a) The disk has hard errors - a real bummer." X echo "$pr: Check system logs with dmesg/messages/uerf/hdelogger/errpt/whatever." X echo "$pr: b) The disk is ok but the filesystem is corrupt," X echo "$pr: e.g. an inode is pointing at impossibly large block numbers." X echo "$pr: Fix by umount'ing and fsck'ing the filesystem." X echo "$pr:" X fi | tee -a $probsend X fi X done X # tell operator X echo '' X echo "$pr: WARNING! The backup report shows big PROBLEMS:" X cat $statprob X echo "$pr: Please REPORT THIS to na-system !!!" X eval "$EXITQ" X fi X X ## finish report at last X if test -f $failrpt ; then X exec 1>> $report X echo "Operator '$OPER' reported that this backup failed for the following reason:" X cat $failrpt X echo "" # make sure there's a newline X echo "End of Operator failure report." X exec 1>&9 X fi X # report generation done, so put standard out back on the tty X X ## finish X if test $verifytoo != true ; then X echo "$pr: This backup is done." X else X echo "$pr: This backup is done; will start 'verifytoo'." X # if we just made a multi-volume tape set, try to take the X # tape offline and then tell the operator to put the X # first tape in the drive X case $mistape$voln in X true[2-9]|true[1-9][0-9]) X eval "$OFFLINE" X echo "$pr: This backup took $voln tapes." X echo "$pr: Before we begin the 'verifytoo', please put" X echo "$pr: volume '1' of this alldisks tape set into $media." X eval "$MREADYQ" X ;; X esac X extravol=`expr $voln - 1` X case "$multi" in X false) vfsarg=onedisk ;; X true) vfsarg=alldisks ;; X esac X vcmd="./$pr verify $vfsarg $marg $diskfile $extravol $wdir $childargs nomail" X echo '' X echo $vcmd | tee -a $report X echo '' X cd $hdir X $vcmd X cd $workdir X echo "#VerToo end: `date`" >> $report X # take it offline in background so user doesn't have to wait X eval "$OFFLINE" & X fi X;; X X## do get or verify if that's what we're doing Xget|verify) X X ## onvol by definition is "1" if it's a onedisk backup, even X ## if the backup spanned tapes (as in a 9track backup); X ## otherwise we set it later X if test $mode = verify -a $getmode = onedisk ; then X onvol=1 X fi X X ## get number of volumes (in most cases we care but some we don't): X ## $mode type do_we_care_about_$nvol_and_$onvol X ## get onedisk no_and_no: we're not autoverifying X ## get alldisks yes_and_yes: we need positioning X ## verify onedisk yes_and_yes: to autoverify if we can X ## verify alldisks yes_and_yes: we need positioning X ## So, "$nvol" can be null if we're doing a get from a onedisk backup; X # X # if it's a get from a onedisk, we don't really care but user may X # have specified so why not? X if test $mode = get -a $getmode = onedisk ; then X nvol=$nvol X # else we care, so try to figure it out ... X # if we're getting from disk file(s), we don't really have X # any tapes but we need to act as if it's all on one tape X elif test $mtype = file -o $mtype = dir ; then X nvol=1 X # else if it's a onedisk, assume it will always fit on a video tape X elif test $getmode = onedisk -a $mtype = video ; then X nvol=1 X # else we've got to find out the number of volumes/tapes and the X # name of the first filesystem on each volume/tape X else X # for any cpio backup or an alldisks backup, we need to know: X # while test $bprog = cpio -o $getmode = knownfs -o $getmode = listdisks -o $getmode = lastdisk -o $getmode = alldisks ; do X # for any onedisk or alldisks backup X while : ; do X if test -n "$nvol" ; then X echo "$pr: This backup set has '$nvol' volume(s)." X else X echo "$pr: How many volumes are in this backup set?" X echo $epre "$pr: Enter the number: "$esuf X eval "$READ" nvol X fi X # validate $nvol X if test "$nvol" -lt 1 -o "$nvol" -gt $maxvol ; then X echo "$pr: '$nvol' can't be correct. Try again." X nvol='' X continue X else X extravol=`expr $nvol - 1` X break X fi X done X fi X # if $nvol isn't set, then we don't need to know X case "$nvol\X$mtype" in X *file|*dir) x="$nvol (mtype=$mtype)" ;; X X*) x=NA ;; X *) x=$nvol ;; X esac X echo "#volumes in backup set: $x" >> $report X X # if we think we're getting from a multi-filesystem backup, then X # extract the header archive and get positioning info X case $getmode in X knownfs|knownskip|listdisks|lastdisk|alldisks) X # If this is a multi-fs backup we need to extract from the X # tar/cpio header file, or get the necessary info from the X # parent directory. X # X # If we are extracting from media, make absolutely sure it X # succeeds, and don't continue until it does. This is the X # second time we've actually tried to read from the media. X fsnn=00 X eval "$MDEV" X cd $workdir X while : ; do X # Do tar/cpio extraction (or get $dfout from the parent) X # The count for the "dd" below is to make sure that X # we don't read a huge file if we aren't reading a X # header archive, which should be less than 200k. X case $bprog$showdd$mhost in X cpio*) : ;; X *false*) : ;; X *true$lhost) : ;; X *true*) eval $SHOWDD Get alldisks header from $mhost:$media ;; X esac X case $parent-$bprog$demo$mhost in X # parent is a backup called with "verifytoo" X *[fit]?-*) eval "$LNFSTABLIST" ; ln ../$dfout ../$breport . ;; X # parent is ordinary verify X *[a-z]-*) eval "$LNFSTABLIST" ; ln ../$dfout ../$breport ../$volmap . ;; X # the eight choices have no parent, i.e. this an X # ordinary verify X *cpiotrue$lhost) echo "$pr demo: cpio -icum$ckey < $mdev" ;; X *cpio*$lhost) : ; cpio -icum$ckey < $mdev ;; X *cpiotrue*) echo "$pr demo: $bdd if=$mdev bs=5k 2\> /dev/null \| cpio -icum$ckey" ;; X *cpio*) : ; $bdd if=$mdev bs=5k 2> /dev/null | cpio -icum$ckey ;; X *true$lhost) echo "$pr demo: tar xf $mdev" ;; X *$lhost) : ; tar xf $mdev ;; X *true*) echo "$pr demo: $bdd if=$mdev bs=10k count=20 2\> /dev/null \| tar xf -" ;; X *) : ; $bdd if=$mdev bs=10k count=20 2> /dev/null | tar xf - ;; X esac X hfstat=$? X # if we had no problems getting $dfout X # note that SunOS 4.1.2 tar exits ok when it reads X # a dump - very strange! X if test "$hfstat" -eq 0 -a -s $dfout ; then X break X else X echo "$pr: We had some trouble extracting the header archive from the $media." X echo "$pr: Doing some investigating ..." X if test ! -s $dfout ; then X echo "$pr: Filesystem list '$dfout' was not extracted." X echo "$pr: Extracting the header archive failed. Check:" X echo "$pr: -> Is the $media a 'onedisk' backup (not an 'alldisks')?" X eval "$CHKMEDIA" X echo "$pr: Quitting." X exit 1 X else X echo "$pr: Filesystem list '$dfout' was extracted - ok so far ..." X echo "$pr: Doing simple checks on '$dfout' ..." X # $dfout should have same number of words on each line X isit1=`awk '{print NF}' $dfout | sort -n -u | wc -l` SHAR_EOF true || echo 'restore of src/backup/backup failed' fi echo 'End of saenv_alld part 5' echo 'File src/backup/backup is continued in part 6' echo 6 > _shar_seq_.tmp exit 0