Xref: feenix.metronet.com comp.sys.sun.admin:10741
Path: feenix.metronet.com!news.ecn.bgu.edu!usenet.ins.cwru.edu!howland.reston.ans.net!spool.mu.edu!olivea!tardis!jms
From: jms@tardis.Tymnet.COM (Joe Smith)
Newsgroups: comp.sys.sun.admin
Subject: Re: Making Backups?
Message-ID: <3687@tardis.Tymnet.COM>
Date: 23 Aug 93 07:14:48 GMT
References: <CBp7Dt.KB5@news.udel.edu>
Organization: BT Tymnet, San Jose, CA
Lines: 1837

In article <CBp7Dt.KB5@news.udel.edu> sharris@chopin.udel.edu (Scott A Harris) writes:
>
>
>I'm just curious if there is a way to put
>rsd0a, rsd0h, and rsd0g all on one tape?
>Is there a way to just append the info?

Yes.  Just use /dev/nrst0 instead of /dev/rst0.
Here is a script I've written in PERL to do just that.
	-Joe

-rw-r--r--  1 root        14520 Jan 10  1993 usr/local/admin/dump/backup.doc
The shar (shell archive) starts 315 lines into this message.
					From: Joe Smith
					Date: 10-Jan-92
					Subject: Backup script for 8mm tapes

This 'backup' script has several advantages over other backup utilities:

  o  Dumps multiple disk partitions from multiple hosts to a single
     Exabyte (8mm) tape.

  o  Keeps a short table of contents (in human readable form) at the
     beginning of the tape.  It lists which partitions were saved and
     their file numbers, so that 'restore' can be told how many files
     to skip.  (You can use "cat /dev/rst0" to read the table of contents.)

  o  Includes a 'tar' save of shell scripts that are useful in restoring
     files from the tape.  Operators need not remember all the details
     required to restore files.  All they have to remember is that the tape
     can be read using "/usr/etc/extract_unbundled" and everything else is
     automatic.

  o  The 'tar' save also includes the output from 'du', which provides
     a summary of all directories saved on the tape.

  o  Keeps track of how many times a tape (or set of tapes) has been used.

  o  Logs all output from 'dump' to a disk file in /var/adm/dumplog.

  o  Keeps track of how many hours it took to dump each partition.

  o  Can handle multiple tape drives (such as /dev/nrst0 and /dev/nrst1).

  o  Can be used to save single partitions to multiple 1/2-inch or 1/4-inch
     tapes.  Automatically specifies the right size/density/tracks for
     each type of tape.

  o  Can be used in "long play" mode, where a week's worth of incremental
     saves are stored on a single, nonrewinding tape.

Sample commands:

	alpha# /usr/local/admin/dump/backup 8mm  all set-2
	beta#  /usr/local/admin/dump/backup cart all inc-01
	delta# /usr/local/admin/dump/backup c150 all inc-31
	gamma# /usr/local/admin/dump/backup 6250 all set-4 Fri

The arguments are:
  1) TapeType = type of tape (8mm 1600 6250 cart c150) or device (st1 mt9).
  2) HostSet = either the name of a single host to dump, or an alias.
  3) TapeSet = either the name of a single tape (for incrementals) or the
     name of a set of tapes (for level-0 saves of the entire file system).
     (If TapeSet is not supplied, a list of tape sets will be extracted
     from /etc/dumptapes and displayed for the user.)
  4) SchedDay = optional day-of-week for scheduling purposes.  In the last
     example above, it means to pretend that today is Friday.


The following files are part of the 'backup' package:

/usr/local/admin/dump/backup.doc	This document.
/usr/local/admin/dump/backup		The backup program, written in PERL.
/usr/local/admin/dump/retrieve		Invokes 'restore', also in PERL.
/usr/local/admin/dump/disk-usage	Creates summary for each local disk.
/usr/local/admin/restore/restore_8mm	Shell script put at beginning of tape.
/usr/local/admin/restore/install_unbundled	For /usr/etc/extract_unbundled.

/var/admin/dump/dumptapes	Counts how often each tape is used.
/var/admin/dump/{8mm,6250}/*	Table of Contents files for each tape.
/var/adm/dumplog/YYMMDD		Output from the 'dump' command, one per day.

/etc/admin/dump/candidates	Used to translate HostSet to list of hosts.
/etc/admin/dump/schedule.`hostname`	Used to define available tape drives.
/etc/admin/dump/schedule.*	Lists file systems and how often to dump them.

/etc/dumptapes			Symbolic link to /var/admin/dump/dumptapes.
/bin/perl			Symbolic link to /usr/local/bin/perl
(PERL 4.0.19 came from comp.sources.misc in April and November of 1991.)

		--------------------------------------

Tape format:

The first two files on the tape are:
  1) A human readable Table of Contents and copyright notice.
  2) A 'tar' save of files that can be used to read the rest of the tape.

Note that this layout is compatible with Sun's 'extract_unbundled' script.
If the tapes are labled with "Use /usr/etc/extract_unbundled", then it
means that you don't have to worry about losing the documentation on
how to restore files from the tape; all the necessary information is
included automatically.

The scripts in tape file #2 are written to be processed using /bin/sh and
/bin/csh, so they can be used if PERL is not available (such as when booting
from the miniroot in order to restore /usr/local or all of /usr).  Also
included in this 'tar' save is a directory called 'du' which has the output
from the 'du' command for each partition.  This data can be used to determine
which partition a give directory was on at the time of the dump.

Files 3 though N are 'dump' saves.

The last file on the tape is a copy of the Table of Contents, but includes
a log of how many hours it took to process each partition.  The Table of
Contents files are kept in /var/admin/dump/$TapeType/$TapeSet.*.  The
files are overwritten when that particular tapeset is reused.

		--------------------------------------

Sample input files:

  ==> /etc/admin/dump/candidates <==
  seta		alpha beta
  setb		delta gamma
  all		alpha beta delta gamma

This defines aliases for lists of hosts.  Anything not found in the
candidates file is assumed to be the name of a single host.

  ==> /etc/admin/dump/schedule.alpha <==
  localtape	8mm=st0 6250=gamma:mt8			  # schedule.alpha
  # alpha is diskless - this file exists only to define 'localtape'.

  ==> /etc/admin/dump/schedule.gamma <==
  localtape cart=st8 1600=mt0 6250=mt8 1600=mt1 6250=mt9  # schedule.gamma

  #dev	days  level	tape-name	list of partitions
  8mm	.....f.	0	all-tape1	xd0a:root xd0e:var
  8mm	.....f.	0	all-tape1	xd0g:usr xd1g:export xd0h:home/gamma
  8mm	.....f.	0	all-tape2	xd1h:netnews
  8mm   ....... X	no-backup	xd1f:export/swap  # never backed up
  8mm	smtwt.s	0	all-daily	xd0a:root xd0e:var
  8mm	smtwt.s	5	all-daily	xd0g:usr xd1g:export xd0h:home/gamma
  8mm	smtwt.s	5	all-daily	xd1h:netnews
  6250	.....f.	0	gamma-usr-root	xd0g:usr xd0a:root xd0e:var
  6250	.....f.	0	gamma-export	xd1g:export
  6250	.....f.	0	gamma-home	xd0h:home/gamma
  6250	.....f.	0	gamma-news	xd1h:netnews

Workstation "alpha" is a diskless client with an 8mm tape drive addressed as
/dev/rst0 (as opposed to /dev/rst1).  Server "gamma" is shown to have a 60
megabyte 1/4-inch cartridge on /dev/rst8 and two 1/2-inch tape drives.  The
'backup' script will use the first 1/2-inch drive if the TapeType is set to
"1600", "mt0", "6250" or "mt8".  It will use the second one only for "mt1"
or "mt9".

In the schedule file, the first word on each line is checked to see if it
matches the selected TapeType.  Then the second word is checked to see if
it matches the SchedDay (which defaults to the current day of the week).
The appropriate column is checked for a period (which says to ignore the
rest of the line).  Anything else means to process the rest of the line.

In the examples above, if 'backup' is invoked on host alpha, it will ask
host gamma to report which partitions need to be backed up and which tapes
to use.  If it is Friday, gamma will say that it wants to have 6 partitions
backed up using a "level 0" dump onto two 8mm tapes.  On any other day of the
week, gamma will say that it wants to do a "level 0" dump of /var and the
root partition, and do a "level 5" dump of all the other partitions to a
single 8mm tape.  Not shown are the schedule files for hosts delta and beta,
which get included on tapes "all-tape2" and "all-daily".


  ==> /etc/admin/dump/proprietary <==
  +---------------------------------------------------------------------------+
  | Proprietary rights of **THIS COMPANY** are included in information stored |
  | on this tape.  The contents of this tape are to be used for backup and    |
  | recovery purposes only.  Any other use is a violation of XXXX guidelines. |
  +---------------------------------------------------------------------------+

This file, if it exists, will be included in the Table of Contents file that
is put on the beginning and end of the tape.  It should be customized to
reflect the department's policy on computer access.

		--------------------------------------

Sample output files:

  ==> /var/admin/dump/8mm/set1.all-tape1 <==
  Set "set1" Tape "all-tape1" written Fri Jan 24 07:30:25 PST 1992
  Device "st0" (8mm) blocked 126 at 54000 bpi for 6000 feet.

  01	Table of Contents
  02	Restore Scripts
  03	gamma	lvl-0	xd0a	/root 
  04	gamma	lvl-0	xd0e	/var 
  05	gamma	lvl-0	xd0g	/usr 
  06	gamma	lvl-0	xd1g	/export 
  07	gamma	lvl-0	xd0h	/home/gamma 
  12	Table of Contents (copy)

  [End of Tape]

  +---------------------------------------------------------------------------+
  | Proprietary rights of **THIS COMPANY** are included in information stored |
  | on this tape.  The contents of this tape are to be used for backup and    |
  | recovery purposes only.  Any other use is a violation of XXXX guidelines. |
  +---------------------------------------------------------------------------+

  Tape set1.all-tape1          started  at Fri Jan 24 07:32:58 PST 1992 (hours)
  Disk gamma:xd0a              finished at Fri Jan 24 07:34:42 PST 1992 ( 0.03)
  Disk gamma:xd0e              finished at Fri Jan 24 07:37:16 PST 1992 ( 0.04)
  Disk gamma:xd0g              finished at Fri Jan 24 07:56:13 PST 1992 ( 0.31)
  Disk gamma:xd1g              finished at Fri Jan 24 08:30:55 PST 1992 ( 0.58)
  Disk gamma:xd0h              finished at Fri Jan 24 09:27:28 PST 1992 ( 0.94)
  Tape set1.all-tape1          finished at Fri Jan 24 11:39:51 PST 1992 ( 1.90)

The last line is the total amount of time it took to process all the
partitions that were stored on this tape.


  ==> /var/adm/dumplog/920124 <==
  TOC written to /var/admin/dump/8mm/set1.all-tape1
  starting gamma:/dev/rxd0a (root) level 0 dump on set1.all-tape1 03
  rsh gamma  /usr/etc/dump u0bdsf 126 54000 6000 alpha:/dev/nrst0 /dev/rxd0a
    DUMP: Date of this level 0 dump: Fri Jan 24 07:33:14 1992
    DUMP: Date of last level 0 dump: the epoch
    DUMP: Dumping /dev/rxd0a (/) to /dev/nrst0 on host alpha
    DUMP: mapping (Pass I) [regular files]
    DUMP: mapping (Pass II) [directories]
    DUMP: estimated 12544 blocks (6.12MB) on 0.00 tape(s).
    DUMP: dumping (Pass III) [directories]
    DUMP: dumping (Pass IV) [regular files]
    DUMP: level 0 dump on Fri Jan 24 07:33:14 1992
    DUMP: Tape rewinding
    DUMP: 12544 blocks (6.12MB) on 1 volume
    DUMP: DUMP IS DONE

  starting gamma:/dev/rxd0e (var) level 0 dump on set1.all-tape1 04
  rsh gamma  /usr/etc/dump u0bdsf 126 54000 6000 alpha:/dev/nrst0 /dev/rxd0e
    DUMP: Date of this level 0 dump: Fri Jan 24 07:34:56 1992
	...			[several lines of output deleted here]
    DUMP: DUMP IS DONE
  Tape set1.all-tape1          finished at Fri Jan 24 11:39:51 PST 1992 ( 1.90)
  TOC written to /var/admin/dump/8mm/set1.all-tape1

  TOC written to /var/admin/dump/8mm/set1.all-tape2
  starting gamma:/dev/rxd1h (netnews) level 0 dump on set1.all-tape2 03
  rsh gamma  /usr/etc/dump u0bdsf 126 54000 6000 alpha:/dev/nrst0 /dev/rxd1h
    DUMP: Date of this level 0 dump: Fri Jan 24 11:46:12 1992
	...			[several lines of output deleted here]
    DUMP: DUMP IS DONE
  Tape set1.all-tape2          finished at Fri Jan 24 14:45:21 PST 1992 ( 3.02)
  TOC written to /var/admin/dump/8mm/set1.all-tape2

The name of the directory for these log files, /var/adm/dumplog, was chosen
to match the one used by Sun's "Backup CoPilot" utility.  The name of the
the log file is today's date in YYMMDD form.  If the backup has to be
restarted, the output will be appended to the existing log file.

  ==> /etc/dumptapes <==
  8mm.day-01.incremental           6 Wed Apr  1 18:57:17 PST 1992
  8mm.wed.incremental             52 Wed Apr  1 17:38:54 PST 1992
  8mm.day-31.incremental           6 Tue Mar 31 19:13:47 PST 1992
  8mm.tue.incremental             52 Tue Mar 31 17:45:14 PST 1992
  8mm.day-30.incremental           6 Mon Mar 30 20:51:20 PST 1992
  8mm.mon.incremental             52 Mon Mar 30 18:14:31 PST 1992
  8mm.set8.all-tape2               2 Sun Mar 29 04:19:41 PST 1992
  8mm.set8.all-tape1               2 Sun Mar 29 02:40:30 PST 1992
  6250.set1.gamma-boot             8 Fri Feb  7 20:00:34 PST 1992

This file is sorted with the most recently used tape first.  The first
column is the TapeType.TapeSet.TapeName, the second is the number of
times that this tape was used.  The date/time is when the dump finished
on this tape.

		--------------------------------------

New features (since January 1992):

o  Added /etc/dumptapes to keep track of tapes used.

o  Added an explicit "mt -f /dev/r$TAPE rewind" to 'retrieve' script.
   This is to avoid crashing if running SunOS-4.1.1 without patch 100280-02
   installed.  (The symptom was "panic: psig action" when 'restore s N'
   tried to skip forward N savesets.)

o  Changed blocking factor from 126 to 112 so that the buffer size (56K)
   is the largest multiple of 8K less than 64K (since SunOS uses 8K pages).

o  Eliminated blocking factor from the 'retrieve' script since 'restore'
   detects the blocking factor automatically.

o  If /usr/local/admin/dump/disk-usage is excuted daily, then the output from
   /usr/bin/du for each partition is stored on the tape.  This is very handy
   when user directories get moved from one /home partition to another.  The
   old location can be determined by using 'grep' on the 'du' file.

o  Use "-8mm" to start an incremental save; the tape will not be rewound
   after the dump.  Use "+8mm" to append to an incremental; the tape is
   not rewound before or after the dump.  Use "=8mm" to finish an
   incremental tape; the tape is rewound after the dump (but not before).
   This allows a full week's worth of incrementals to be saved on a single
   tape, as long as you dedicate one 8mm drive for doing backups only.

Things to do:

o  Read the first line off the tape to make sure the correct tape is mounted.

o  Do more with the output from 'estimate.8mm', which estimates what fraction
   of an Exabyte tape will be required to backup a given partition.

o  Replace "candidates" file with /etc/host.aliases.

o  Calculate the number of tapes each dump is going to take and verify that
   multiple saves to a single tape won't hit end-of-tape unexpectedly.

o  Handle schedules that do not repeat every 7 days.

o  Provide enough defaults so that 'backup' can be run with no arguments.

o  Update /usr/local/admin/dump/retrieve.  (It has not had as much attention
   as the other scripts.)  Make prompt for missing command line arguments.

o  Rewrite 'backup' so that can prompt for missing command line arguments
   and display reasonable default values. (Much work needed here.)

[End of backup.doc]

---------------- cut here ----------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  usr/local/admin usr/local/admin/dump
#   usr/local/admin/restore usr/local/admin/dump/autobackup
#   usr/local/admin/dump/backup usr/local/admin/dump/df-i
#   usr/local/admin/dump/disk-usage usr/local/admin/dump/estimate.8mm
#   usr/local/admin/dump/make-autoback usr/local/admin/dump/make-shar
#   usr/local/admin/dump/retrieve
#   usr/local/admin/restore/install_unbundled
#   usr/local/admin/restore/read_contents
#   usr/local/admin/restore/restore_8mm etc/admin etc/admin/dump
#   etc/admin/dump/candidates etc/admin/dump/proprietary
#   etc/admin/dump/schedule.alpha etc/admin/dump/schedule.beta
#   etc/admin/dump/schedule.gamma
# Wrapped by jms@tardis on Mon Aug 23 00:11:13 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test ! -d 'usr/local/admin' ; then
    echo shar: Creating directory \"'usr/local/admin'\"
    mkdir 'usr/local/admin'
fi
if test ! -d 'usr/local/admin/dump' ; then
    echo shar: Creating directory \"'usr/local/admin/dump'\"
    mkdir 'usr/local/admin/dump'
fi
if test ! -d 'usr/local/admin/restore' ; then
    echo shar: Creating directory \"'usr/local/admin/restore'\"
    mkdir 'usr/local/admin/restore'
fi
if test -f 'usr/local/admin/dump/autobackup' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'usr/local/admin/dump/autobackup'\"
else
echo shar: Extracting \"'usr/local/admin/dump/autobackup'\" \(2125 characters\)
sed "s/^X//" >'usr/local/admin/dump/autobackup' <<'END_OF_FILE'
X#!/bin/perl
X# Name: /usr/local/admin/dump/autobackup		Author: Joe Smith
X# Purpose: Invoked by cron to automatically starts the backup dumps.
X
X# This is not a general-purpose script; it works only for a system with
X# two tape drives (one for incrementals, one for full saves).  It assumes
X# that an entire week's worth of incrementals can fit on a single 2.3Gb tape
X# and that the level-0 dump of all disks fits onto a single 5.0Gb tape.
X
X($progdir,$me) = $0 =~ m%(^.*)/(.*)%;	# Directory where program was run
X($progdir,$me) = (".",$0) if $progdir eq "";
X
X$hostset = $ARGV[0];			# Name of hostset (in candidates file)
X$hostset = "all" unless $hostset;
X$log     = $ARGV[1];			# Name of logfile or directory
X$log     = "/var/admin/dump/autobackup" unless $log;
X
X($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime;
X$yymmdd = sprintf("%02d%02d%02d",$year,$mon+1,$mday);
X$autofile = "/etc/admin/dump/autobackup";
X
X# Sample contents of /etc/admin/dump/autobackup:
X# 8mm     week1   921121 921122 921123 921124 921125 921126
X# 8mm2    set01   921127
X
Xif (open(FILE,$autofile)) {
X  while(<FILE>) {
X    chop; s/\s*#.*//; next if /^$/;	# Skip comments and blank lines
X    ($dev,$tape,@dates) = split if /$yymmdd/o;	# Look for today's date
X  }
X  close(FILE);
X} else {
X  die "Cannot read data from $autofile - $!\n";
X}
Xdie "No entry found for $yymmdd\n" unless $dev;
Xprint "$yymmdd: dev=$dev tape=$tape dates=",join(',',@dates),"\n";
X
X$firstdate = $dates[0]; $lastdate = pop(@dates);
X$p = "+"; $type = "incr"; $unload = 0;	# Default is to append to current save
X$p = "-" if $firstdate eq $yymmdd;		# Start a new save, no unload
X$p = "=", $unload++ if $lastdate  eq $yymmdd;	# End of incremental, unload
X$p = "",  $unload++ if $firstdate eq $lastdate;	# Full save and unload
X$type = "full" if $p eq "";
X$logfile = (-d $log) ? "$log/$type" : "$log.$type";
X
X$foo = "$progdir/backup $p$dev $hostset $tape >$logfile";
X$| = 1; print "  $foo\n";	# Display the command about to be executed
Xsystem($foo);
Xprint "  ls -l $logfile\n"; system("ls -l $logfile");
Xprint "Be sure to insert next tape in $dev before 5:00pm\n" if $unload;
END_OF_FILE
if test 2125 -ne `wc -c <'usr/local/admin/dump/autobackup'`; then
    echo shar: \"'usr/local/admin/dump/autobackup'\" unpacked with wrong size!
fi
chmod +x 'usr/local/admin/dump/autobackup'
# end of 'usr/local/admin/dump/autobackup'
fi
if test -f 'usr/local/admin/dump/backup' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'usr/local/admin/dump/backup'\"
else
echo shar: Extracting \"'usr/local/admin/dump/backup'\" \(21850 characters\)
sed "s/^X//" >'usr/local/admin/dump/backup' <<'END_OF_FILE'
X#!/bin/perl
X# Name: /usr/local/admin/dump/backup		Author: DH,CB,CF, Joe Smith
X# Purpose: Dumps several diskfull workstations to a single 8mm tape.
X# (Also handles 1/2 and 1/4 inch tapes.)  Automatically determines when
X# to do level-0 dumps and when to do incremental saves.
X# Assumes that /usr/local/admin/dump/disk-usage is run once a day.
X#
X# See /usr/local/admin/dump/backup.doc for more details.
X
X$TapeType = $ARGV[0];	# Type of tape device: "8mm", "6250", etc
X$HostSet  = $ARGV[1];	# Keyword describing which hosts to back up
X$TapeSet  = $ARGV[2];	# Tape set name (such as "set-1", "inc-31", etc)
X$SchedDay = $ARGV[3];	# Optional day (to re-do Friday's save on Saturday)
X
Xif ($TapeSet eq "") {
X    print "Usage: $0 tape-type host-set tape-set [ schedule-day ]\n" .
X	  "   eg. $0 8mm all set-a fri\n" .
X	  "use '-8mm' to start a multi-day save (no rewind), '+8mm' to\n" .
X	  "append to multi-day save, '=8mm' to finish a multi-day save.\n";
X    exit 1;
X}
X
X# Configuration parameters - change these to match your site's conventions.
X# Directories in /var will be created as needed. 
X
X$ETCDIR  = "/etc/admin/dump";		# Dir for parameter files
X$MYDIR   = "/usr/local/admin/dump";	# Dir for scripts to create dump tapes
X$RESTORE = "/usr/local/admin/restore";	# Dir for scripts to read dump tapes
X$VARDIR  = "/var/admin/dump";		# Dir for data (tape list, file list)
X$debug   = 0;
X
X# Names of files and directories based on the above parameters
X
X$candidates = "$ETCDIR/candidates";	# List of diskfull workstations
X$schedule   = "$ETCDIR/schedule";	# List of disks and their schedule
X$proprietary= "$ETCDIR/proprietary";	# Copyright notice and/or warning
X$readtape   = "$RESTORE/read_contents";	# Program to verify the tape
X$tocdir     = "$VARDIR/toc";		# Written by $RESTORE/read_contents
X$dudir      = "$VARDIR/du";		# Output from 'du' = dir summary
X$logdir     = "$VARDIR/log";		# Messages from 'dump' go here
X$vartapes   = "$VARDIR/dumptapes";	# Where tape list is stored
X$dumptapes  = "/etc/dumptapes";		# Where we say it is (symlink name)
X# $dumpdir = "$VARDIR/8mm" or "$VARDIR/6250" depending on what drive is used.
X# $logfile = "$logdir/$yymmdd.$ThisHost" to match current year, month, day.
X
X# Use block 112 instead of 126 to make block size a multiple of 8Kbytes.
X%DumpParams = (	# Parameters for /usr/etc/dump (as of SunOS-4.1.2)
X    "8mm",  "bdsf   112  54000 6000   : 2.3G",	# Exabyte 8200
X    "8mm2", "bdsf   112 108000 6000   : 5.2G",	# Exabyte 8500 (double density)
X    "8mm4", "bdsf   112 216000 6000   :10.4G",	# Exabyte 8500-Compression
X    "6250", "bdsf    64   6250 2300   : 180M",	# 1/2-inch GCR
X    "1600", "bdsf    20   1600 2300   :  44M",	# 1/2-inch PE
X    "cart", "cbdsf  112   1000  425   :  60M",	# 1/4-inch QIC-24
X    "c150", "cbdstf 112   1000  700 18: 150M"	# 1/4-inch QIC-150
X);  #key     opts blocking density feet tracks:size
X
X%WeekDays = (
X    "sun",0, "Sun",0, "Sunday",   0,    "mon",1, "Mon",1, "Monday",   1,
X    "tue",2, "Tue",2, "Tuesday",  2,    "wed",3, "Wed",3, "Wednesday",3,
X    "thu",4, "Thu",4, "Thursday", 4,    "fri",5, "Fri",5, "Friday",   5,
X    "sat",6, "Sat",6, "Saturday", 6
X);
X
X@WeekDays = ("Sunday", "Monday", "Tuesday",
X "Wednesday", "Thursday", "Friday", "Saturday");
X
X#############################################################################
X
X# Start of main program
X
X$StartSec = time;			# For calculating elapsed time
Xchop($ThisHost = `hostname`);
X# The time from midnight to 6:00am is considered to be the previous day.
X($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time-6*60*60);
X$yymmdd=sprintf("%02d%02d%02d",$year,$mon+1,$mday);
X
X# Determine what tape drives are attached to the local host.
X
Xopen(SCHEDULE,"$schedule.$ThisHost") ||
X	die "Can't find 'localtape' in $schedule.$ThisHost: $!\n";
Xwhile(<SCHEDULE>) {
X  chop; s/\s*#.*//; next if /^$/;
X  ($keyword,@list) = split;		# Look for "localtape 8mm=st0 6250=mt8"
X  if ( $keyword eq "localtape" ) {	# or "localtape 8mm=alpha:st0"
X    print "Tape drives for $ThisHost:";
X    foreach (@list) {
X      ($tape,$dev) = split('=');
X      if ( $DumpParams{$tape} ) {	# If defined in our list
X        $TapeDev{$tape} = $dev if ! $TapeDev{$tape};	# Remember only 1st one
X	$DevTape{$dev} = $tape;
X        print " $tape=$dev";		# Show which ones we recognize
X      } else {
X	print " $tape+$dev=unknown";
X      }
X    }		# each list
X    print "\n"; last;		# "localtape" should be on 1st line of file
X  }
X}		# end <SCHEDULE>
Xclose(SCHEDULE);
Xdie "'localtape' not defined in $schedule.$ThisHost\n" if ! defined %TapeDev;
X$| = 1;	# Don't buffer STDOUT (so system() works right when output to a file)
X
X#############################################################################
X
X# Verify the 1st argument (TapeType)
X#  "8mm" = rewind before saving TOC and scripts, unload after dump.
X# "-8mm" = rewind before saving TOC and scripts, but not after.
X# "+8mm" = append incremental to tape, don't rewind tape.
X# "=8mm" = append incremental to tape, write trailing TOC, unload tape.
X
Xif ($TapeType =~ /^\-(.*)/) {	# Use "-8mm" to start a new incremental tape
X  $TapeType = $1; $RewindBefore = 1; $RewindAfter = 0;
X  print "\n  Starting a new incremental dump tape (no rewind at end).\n\n";
X} elsif ($TapeType =~ /^\+(.*)/) {	# Use "+8mm" to append to current incremental
X  $TapeType = $1; $RewindBefore = 0; $RewindAfter = 0;
X  print "\n  Appending to incremental dump tape; no rewind.\n\n";
X} elsif ($TapeType =~ /^\=(.*)/) {	# Use "=8mm" to finish off an incremental
X  $TapeType = $1; $RewindBefore = 0; $RewindAfter = 1;
X  print "\n  Finishing an incremental dump tape; will unload.\n\n";
X} else {
X  $RewindBefore = 1; $RewindAfter = 1;	# Default is not long-play mode
X}
X$Interactive = -t;		# 1 if STDIN is a terminal, null if not
X
Xif ($DevTape{$TapeType}) {	# If given "st1" and both 8mm=st0 and 8mm=st1
X  $Dev = $TapeType;		#  are defined, use the specified /dev name
X  $TapeType = $DevTape{$Dev};	#  and set TapeType to 8mm.
X} else {
X  $Dev = $TapeDev{$TapeType};	# Get the /dev name for this type of tape.
X}
X
X$Dev || die "Host $ThisHost does not have '$TapeType' defined as localtape.\n";
X($tpar,$tapesize) = split(":",$DumpParams{$TapeType});
X$tpar =~ s/\s+/ /g;
X($options,$block,$density,$size) = split(" ",$tpar);
X
X				########
X
X# Expand 2nd argument (HostSet) to a list of hosts
X
X@hostlist = ($HostSet);			# This allows single hosts to be done
Xif ( open(CANDIDATES,"<$candidates") ) {
X  while(<CANDIDATES>) {
X    chop; s/\s*#.*//; next if /^$/;
X    ($keyword,@list)=split;		# Look for alias in this file
X    @hostlist = @list if ($keyword eq $HostSet);
X  }
X  close(CANDIDATES);
X} else { warn "Cannot read candidates list $candidates\n$!\n";
X}
X
X				########
X
X# Check that 3rd argument (TapeSet) is defined in /etc/dumptapes.  Format is:
X# type set tapename usecount date_of_last_use
X# 8mm.set1.tso-tape1	3  Fri Feb  7 17:30:41 PST 1992
X
Xsymlink($vartapes,$dumptapes) if ! -f $dumptapes;
Xprint "Checking $dumptapes for tape set '$TapeSet'\n";
Xif ( open(DUMPTAPES,"<$dumptapes") ) {
X  while(<DUMPTAPES>) {
X    ($type,$set,$rest)=split('\.');
X    ($tape,$usecount,$date)=split('[ \t]+',$rest,3);
X    if ("$type.$set" eq "$TapeType.$TapeSet") {
X      $TAPE="$set.$tape";
X      printf("  %-25s used %3d times as of %s",$TAPE,$usecount,$date);
X      $foundset++;
X    }
X    $sets{$set}++ if $type eq $TapeType;
X  }
X  close(DUMPTAPES);
X  if (! $foundset && $TapeSet =~ /(mon|tue|wed|thu|fri|sat|sun)-\d+/ ) {
X    print "\07	Using '$1' instead of '$TapeSet'\n";
X    $TapeSet = $1;	# Use "mon" instead of "mon-31" for Monday the 31st
X    $foundset++;
X  }
X  if (! $foundset) {
X    print "TapeSet '$TapeSet' not found in $dumptapes.";
X    print "  Current sets for $TapeType are:\n";
X    if ($_ =&MakeCols("  ",79,"",sort short keys %sets)) {
X      if ($Interactive) {
X        print "$_\nIs '$TapeSet' the correct name of the tape set? ";
X        $_ = <STDIN>;
X        die "Please try again.\n" if ! /[Yy]/;
X      }
X    } else {
X      print "   (none currently defined)\n";
X    }
X  }
X} else { warn "Could not read $dumptapes: $!\n";
X}
X
X				########
X
X# The 4th argument is optional and defaults to the current day of the week.
X
X$SchedDay = $WeekDays[$wday] if ($SchedDay eq "");	# Sunday-Saturday
Xdefined $WeekDays{$SchedDay} || die "Invalid schedule day '$SchedDay'\n";
X
X#############################################################################
X
X# All command line arguments have been verified.  Now go to work.
X# Create the needed directories, clean up files from last night's run.
X
X$dumpdir = "$VARDIR/$TapeType";	# Typically "/var/admin/dump/8mm"
X$logfile = "$logdir/$yymmdd.$ThisHost";	# Messages from 'dump' go here
Xsystem("mkdir -p $dumpdir")	if ! -d $dumpdir;
Xsystem("mkdir -p $logdir")	if ! -d $logdir;
Xsystem("mkdir -p $dudir")	if ! -d $dudir;
X
X# Ping each host in the list.  If up, append its 'schedule' file to list.
X
Xprint "Looking for $TapeType:$SchedDay in $schedule.`hostname`\n";
Xprint "               Directory_Summary_File Level Tape_Name\n";
Xforeach $rHost (@hostlist) {		# Try each host in list
X  next if $partitions{$rHost};		# Skip if duplicate host name
X  if (!system("/usr/etc/ping $rHost 5 > /dev/null")) {
X    push(@candidates,$rHost);		# Record Rhost in list
X    open(DUMPME,"rsh $rHost cat $schedule.$rHost |") || die "rsh $rHost $!";
X    while (<DUMPME>) {
X      chop; s/\s*#.*//; next if /^$/;
X      ($tapetype,$when,$level,$tape,@filesystems)=split;
X      if ( $tapetype eq $TapeType ) {	# If first token on line matches
X        next if &NotToday($when);	# Check schedule info
X        foreach (@filesystems) {	# Add each target to tape list
X	  $partitions{$rHost}++;
X          ($target,$text) = split(':');
X          $tapes{$tape} .= join(":",$rHost,$level,$target,$text) . " ";
X	  $du = "$dudir/$rHost.$target";
X	  print("$rHost:$du\t$level   $tape\n"); # Show name of summary file
X	  if ($rHost ne $ThisHost) {
X	    warn "system('rcp -p $rHost:$du $du.tmp')\n" if $debug;
X	    system("rcp -p $rHost:$du $du.tmp");
X	    warn "system('rsh $rHost mv $du.tmp $du')\n" if $debug;
X	    system("rsh $rHost mv $du.tmp $du");
X	  }
X        }	# each target
X      }		# if tapetype
X    }		# while <DUMPME>
X  } else {	# if ping failed
X    print "Host $rHost did not respond...will  not be dumped\n";
X  }
X}		# end foreach (@hostlist)
X
X@tapes = sort keys(%tapes);
X$TapeCount = @tapes;			# Number of different tapes
Xprint "$TapeCount tapes required: ", join(" ",@tapes), "\n\n";
X$Interactive = 0 if $TapeCount == 1;	# Don't prompt if only one tape
Xif ($TapeCount > 1 && ! $Interactive) {
X  die "Must be run from a terminal to handle multiple tapes.\n";
X}
X
X#############################################################################
X
X# Do all hosts that fit on a single 8mm tape
X
X$TapeHost = $ThisHost;			# Assume tape is on this host
X($TapeHost,$Dev) = split(':',$Dev) if $Dev =~ /:/;	# If remote tape
X
Xforeach $tape (@tapes) {
X  chop;					# Remove space at end of string
X  $TAPE="$TapeSet.$tape";		# Something like "set1.incremental"
X  @parts = split(" ",$tapes{$tape});	# All parts for a single tape
X  $TapeSec = time;			# For this tape's elapsed time
X
X  $header = qq|Set "$TapeSet" Tape "$tape" started | . `date`
X	  . qq|Device "$Dev" ($TapeType) blocked $block at $density bpi |
X	  . qq|for $size feet.\n\n|;
X
X  if ($Interactive) {
X    # Tell operator which tape to mount and wait for it.
X    print qq|Please insert $TapeType tape "$TAPE" on $TapeHost:/dev/r$Dev.\n|;
X    print "\07Type Y when ready or N to skip this tape.  Waiting...\07";
X    $_ = <STDIN>;
X    next if /^[NnQqAa]/;	# Skip to next tape if No, Abort, or Quit
X  }
X
X  $tocname = "$dumpdir/$TAPE.toc";	# Filename matches tape name
X  $dufile  = "$TAPE.du";		# List of directories on this tape
X  $duname  = "$dumpdir/$dufile";
X
X  $LastFile = "00";
X  if ($RewindBefore) {
X    @dump_toc = ($header)
X  } else {
X    if (open(TOC,$tocname)) {
X      @dump_toc = <TOC>;
X      close(TOC);
X      foreach (@dump_toc) {
X        $LastFile = $1 if /^(\d+)\t/;	# Find last line with digits-tab
X      }
X      push(@dump_toc,"\n\t\t(last save file was $LastFile)\n\n");
X    } else {
X      warn "Could not find previous Table of Contents $tocname\n";
X    }
X  }
X  $FileNumber = $LastFile;
X  push(@dump_toc, ++$FileNumber,"\tTable of Contents\n");
X  push(@dump_toc, ++$FileNumber,"\tRestore Scripts + 'du' lists\n");
X
X  foreach (@parts) {
X    ($rHost,$level,$target,$text)=split(/:/, $_);
X    push(@dump_toc,++$FileNumber,"\t$rHost\tlvl-$level\t$target\t/$text\n");
X  }
X
X  if ($RewindAfter) {
X    push(@dump_toc,++$FileNumber,"\tTable of Contents (summary)\n");
X    push(@dump_toc,"\n[End of Tape]\n\n");
X  } else {
X    push(@dump_toc, "$FileNumber+ ...\t(additional saves to be appended later)\n\n");
X  }
X
X  if (-f $proprietary && $RewindBefore) {	# If warning file exists
X    open(TOC,"$proprietary");
X    push(@dump_toc,<TOC>);		# Read in the entire file
X    close(TOC);
X  }
X
X				########
X
X  # Write Table Of Contents to $dumpdir directory to disk and maybe to tape
X
X  open(TOC,">$tocname") || die "can't open $tocname: $!";
X  print TOC @dump_toc;
X  close (TOC);
X
X  print "\nWriting Table of Contents to tape...\n  file = $tocname\n";
X  $rsh="";  $rsh="rsh $TapeHost" if $TapeHost ne $ThisHost;
X  if ($RewindBefore) {
X    system("$rsh mt -f /dev/nr$Dev rewind");
X    $tocdev="/dev/r$Dev";		# This will rewind after
X    $FileNumber = "00";
X  } else {
X    $tocdev="/dev/nr$Dev";		# Don't rewind after writing TOC
X    print @dump_toc;
X    $FileNumber = $LastFile;
X  }
X  $FileNumber++;			# The TOC is file 01 if RewindBefore
X  system("<$tocname $rsh dd of=$tocdev conv=sync 2>&1");
X  print("Table of Contents written.  ");
X
X  # Set up the directory summary while waiting for tape to rewind
X
X  print("Creating directory summary file.\n");
X  unlink $duname;			# In case tape being overwritten
X  foreach (@parts) {
X    ($rHost,$level,$target,$text)=split(/:/, $_);
X    $foo="awk '{print \"$rHost:$target\t\"\$0}' $dudir/$rHost.$target";
X    system("$foo >>$duname");
X  }
X  system("ls -l $duname | cut -c23-");		# Show name of summary file
X
X  # Now read the TOC to prove that the tape is readable.  Tape will be
X  # left positioned after the TOC.
X
X  system("$rsh cat /dev/nr$Dev") if $RewindBefore;	# Note use of "/dev/nr" here.
X
X				########
X
X  # 2nd file on tape is a tar save to be compatible with 'extract_unbundled'.
X  # This save also has the saved output from 'du' - a list of all directories.
X  # The 'du' files are handy for verifying which save set contains a given
X  # directory.  For this reason they are written even if TOC is not.
X
X  print "\nCreating 'tar' save of the 'restore' files to $rHost:/dev/nr$Dev\n";
X  $FileNumber++;		# The 'tar' save is file 02 if RewindBefore
X  ($duParent,$duSubdir) = $dudir =~ m%(.*)/(.*)%;
X  $foo="tar cvfb - $block -C $RESTORE . -C $duParent ./$duSubdir";
X  $foo="$foo | $rsh dd bs=${block}b of=/dev/nr$Dev";
X  system("($foo)2>&1");
X
X				########
X
X  $format1="%s %-25s started  at %s (hours)\n";	# 1st line of summary
X  $format2="%s %-25s finished at %s (%5.2f)\n";	# all other lines
X
X  chop($date=`date`);
X  $trailer = sprintf($format1,"Tape",$TAPE,$date);
X  open(TOC,">>$tocname");  print TOC $trailer;  close(TOC);
X  open(LOG,">>$logfile");  print LOG "TOC written to $tocname\n";  close(LOG);
X  foreach (@parts) {			# Do all partitions on this tape
X    $FileNumber++;
X    ($rHost,$level,$target,$text)=split(/:/, $_);
X    system("/usr/5bin/banner $rHost");
X    $PartSec=time;
X    open(LOG,">>$logfile");
X    $foo="starting $rHost:/dev/r$target ($text) level $level dump on $TAPE $FileNumber\n";
X    print $foo; print LOG "\n$foo";
X    $rsh="";	$rsh="rsh $rHost"	if $rHost ne $ThisHost;
X    $rmt="";	$rmt="$TapeHost:"	if $rHost ne $TapeHost;
X    $u="u";	$u=""			if $TapeSet =~ /test/;
X    $foo="$rsh /usr/etc/dump $u$level$tpar $rmt/dev/nr$Dev"
X#bug#	   . " $dumpdir.$FileNumber"		# "dump -a" fails on sun3x
X       . " /dev/r$target";
X    system("rsh $rHost mkdir -p $dumpdir $dudir $LOG") if $rHost ne $ThisHost;
X    print "$foo\n"; print LOG "$foo\n";	# Show command to be executed
X    close(LOG);
X    $err=system("$foo 2>&1 | tee -a $logfile");	# Invoke the 'dump' program
X    $foo="finished $rHost:/dev/r$target ($text) level $level dump on $TAPE $FileNumber\n";
X    print $foo;
X    open(LOG,">>$logfile");  print LOG "$foo\n";  close(LOG);
X    if ($err) {				# If dump returned an error code
X      $trailer="Dump failed - error code ".int($err/256)."/".($err&255)."\n";
X      print $trailer;
X      open(TOC,">>$tocname");  print TOC $trailer;  close(TOC);
X      if ($rHost ne $ThisHost) { # Use "mv" in case $dumpdir is NFS mounted
X	warn "system('rcp -p $tocname $rHost:$tocname.tmp')\n" if $debug;
X	system("rcp -p $tocname $rHost:$tocname.tmp");
X	warn "system('rsh $rHost mv $tocname.tmp $tocname')\n" if $debug;
X	system("rsh $rHost mv $tocname.tmp $tocname");
X      }
X      $|=1; print "Type Control-C within 20 seconds to abort everything.\n";
X      sleep 20;
X      $|=0; print "[Continuing]\n";
X    } else {				# If dump did not return an error
X      $hours = (time-$PartSec)/3600;
X      chop($date=`date`); $disk="$rHost:$target";
X      $trailer = sprintf($format2,"Disk",$disk,$date,$hours);
X      open(TOC,">>$tocname");  print TOC $trailer;  close(TOC);
X      system("rcp -p $tocname $rHost:$tocname.tmp") if $rHost ne $ThisHost;
X      system("rsh $rHost mv $tocname.tmp $tocname") if $rHost ne $ThisHost;
X      @HostsDone = (@HostsDone, $rHost);
X    }
X    if ($rHost ne $ThisHost) {
X      warn "system('rcp -p $logfile $rHost:$logfile.tmp')\n" if $debug;
X      system("rcp -p $logfile $rHost:$logfile.tmp");
X      warn "system('rsh $rHost mv $logfile.tmp $logfile')\n" if $debug;
X      system("rsh $rHost mv $logfile.tmp $logfile");
X    }
X  }					# End of foreach (@parts)
X
X  # Put ending time in the TOC, append 2nd copy of TOC to end of tape
X
X  $hours = (time-$TapeSec)/3600;
X  $used = &UpdateDumptapes($TapeType,$TAPE);	# Put in /etc/dumpdates
X  $trailer = sprintf($format2,"Tape",$TAPE,$date,$hours) . $used;
X  print $trailer;
X  open(TOC,">>$tocname");  print TOC $trailer;  close(TOC);
X  open(LOG,">>$logfile");
X  print LOG $trailer, "TOC written to $tocname\n\n";
X  close(LOG);
X  $rsh="";  $rsh="rsh $TapeHost" if $TapeHost ne $ThisHost;
X  system("<$tocname $rsh dd of=/dev/r$Dev conv=sync") if $RewindAfter;
X  $FileNumber++					      if $RewindAfter;
X  print "Verifying that tape is readable\n\n";
X  open(LOG,">>$logfile"); print LOG "Verifying tape"; close(LOG);
X  $foo="</dev/null $rsh $readtape /dev/nr$Dev $tocdir $FileNumber";
X  system("$foo 2>&1 | tee -a $logfile");
X
X  foreach (@HostsDone) { # Make sure earlier hosts have a complete copy of log
X    next if $_ eq $ThisHost;
X    system("rcp -p $tocname $_:$tocname.tmp");
X    system("rsh $_ mv $tocname.tmp $tocname");	# In case NFS mounted
X    warn "system('rcp -p $logfile $_:$logfile.tmp')\n" if $debug;
X    system("rcp -p $logfile $_:$logfile.tmp");
X    system("rsh $_ mv $logfile.tmp $logfile");	# In case NFS mounted
X  }
X
X  system("/usr/5bin/banner 'Tape Done'") if --$TapeCount; # Not on last tape
X  system("$rsh mt -f /dev/r$Dev offline") if $RewindAfter;
X  print "Tape $Dev unloaded\n"		  if $RewindAfter;
X  printf("Tape %s took %5.2f hours to complete\n",$TAPE,$hours);
X}					# End of foreach (@tapes)
X
Xsystem("/usr/5bin/banner Finished");
X$hours=(time-$StartSec)/3600;
Xprintf("Total time %5.2f hours\n",$hours);
Xexit 0;					# End of program
X
X############################################################################
X
Xsub NotToday {			# Check if this line should be processed today
X  local ($checkday) = @_;
X  return( substr( $checkday, $WeekDays{$SchedDay}, 1 ) eq "." );
X}
X
Xsub UpdateDumptapes {		# Rewrites /etc/dumptapes for each tape done
X  local ($TapeType,$TAPE) = @_;
X  local (@text,$type,$set,$rest,$use,$date);
X  $MyUseCount = 1;		# If not already in file
X  if ( open(DUMPTAPES,"<$dumptapes") ) {
X    while(<DUMPTAPES>) {
X      ($type,$set,$rest)=split('\.');
X      ($tape,$use,$date)=split('[ \t]+',$rest,3);
X      if ("$type.$set.$tape" eq "$TapeType.$TAPE") {
X        $MyUseCount = $use + $RewindBefore;	# Increment if at BOT
X      } else {
X        push(@text,$_);
X      }
X    }
X    close(DUMPTAPES);
X  }
X  $rest="$TapeType.$TAPE";
X  $use=sprintf("%-30s %3d %s",$rest,$MyUseCount,`date`);
X  unshift(@text,$use);		# Put this line at beginning of file
X  open(DUMPTAPES,">$dumptapes"); print DUMPTAPES @text; close(DUMPTAPES);
X  return $use;
X}
X
X 
Xsub MakeCols {	# Create lines of specified width (with prefix and suffix)
X  local($pre,$width,$suf,@data) = @_;
X  local($result,$line,$rightj,$space,$ncols);
X
X  local($max) = 0;
X  foreach (@data) { $max = length($_) if length($_) > $max; }
X  return "" if $max eq 0;
X
X  if ($width > 0) {
X    $rightj = 0;		# Left justified columns
X  } else {
X    $rightj = 1;		# Right justified columns
X    $width = -$width;
X  }
X
X  $width = $width - length($pre) - length($suf);
X  $ncols = int(($width+1)/($max+1));		# Number of columns on a line
X  $space = " " x int(($width - $ncols * $max) / ($ncols - 1));
X
X  $result = ""; $line = "";
X  foreach (@data) {
X    if ((length($_)+length($line)) > $width) {	# If line is full
X      $result .= $pre . $line . " " x ($width - length($line)) . "$suf\n";
X      if ($rightj) {
X        $line = " " x ($max - length($_)) . $_ . $space;
X      } else {
X        $line = $_ . " " x ($max - length($_)) . $space;
X      }
X    } else {					# If line is not full
X      if ($rightj) {
X        $line .= " " x ($max - length($_)) . $_ . $space;
X      } else {
X        $line .= $_ . " " x ($max - length($_)) . $space;
X      }
X    }
X  }
X  $result .= $pre . $line . " " x ($width - length($line)) . "$suf\n";
X  return $result;
X}
X
X# Subroutine to make short names (such as "mon","tue","wed") sort before
X# before medium names ("set09","set10") and long names ("day-29","day-30").
X
Xsub short {
X  length($a) == length($b) ? $a cmp $b : length($a) - length($b);
X}
END_OF_FILE
if test 21850 -ne `wc -c <'usr/local/admin/dump/backup'`; then
    echo shar: \"'usr/local/admin/dump/backup'\" unpacked with wrong size!
fi
chmod +x 'usr/local/admin/dump/backup'
# end of 'usr/local/admin/dump/backup'
fi
if test -f 'usr/local/admin/dump/df-i' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'usr/local/admin/dump/df-i'\"
else
echo shar: Extracting \"'usr/local/admin/dump/df-i'\" \(1185 characters\)
sed "s/^X//" >'usr/local/admin/dump/df-i' <<'END_OF_FILE'
X#!/bin/sh
X# Name: /usr/local/bin/df-i		Author: Joe Smith
X# Purpose: Combines the output of "df" and "df -i" so show number of blocks
X#          and number of inodes used on the same line.
X
Xhost=`hostname`
Xdev="/dev/"
Xif [ "x$1" = "x-h" ]; then
X  dev="$host:"				# -h to include hostname in output
X  shift
Xfi
Xif [ "x$1" = "x-H" ]; then
X  dev="$host:"				# -H same as -h but without header
X  shift
X  noheader=1
Xfi
X
Xmounts="$*"				# List of mountpoints
Xif [ "$mounts" = "" ]; then
X  mounts=`awk '/^\/dev\//{print $2}' /etc/mtab`
Xfi
X
Xdate=`date "+%y%m%d_%H:%M"`		# Date and time as yymmdd_hh:mm
X
X# Ignore nfs mounts by searching for lines that start with "/dev"
Xdf    $mounts | sed -n "/^\/dev/s%/dev/%$dev%p" | sort >/tmp/df.a$$
Xdf -i $mounts | sed -n "/^\/dev/s%/dev/%$dev%p" | sort >/tmp/df.b$$
X
X# Join on first field, don't print mount point twice, make columns line up
X(if [ "$noheader" = "" ]; then
X  echo "Filesystem iused ifree i% Mount kbytes used avail use As_of_$date"
X fi
Xjoin /tmp/df.b$$ /tmp/df.a$$ | sort +9) | awk \
X'{printf "%-12s%6s%7s %3s%8s%8s%8s%5s  %s\n",$1,$2,$3,$4,$6,$7,$8,$9,$10}'
X# Output is sorted alphabetically by mount point name
X
Xrm /tmp/df.a$$ /tmp/df.b$$
END_OF_FILE
if test 1185 -ne `wc -c <'usr/local/admin/dump/df-i'`; then
    echo shar: \"'usr/local/admin/dump/df-i'\" unpacked with wrong size!
fi
chmod +x 'usr/local/admin/dump/df-i'
# end of 'usr/local/admin/dump/df-i'
fi
if test -f 'usr/local/admin/dump/disk-usage' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'usr/local/admin/dump/disk-usage'\"
else
echo shar: Extracting \"'usr/local/admin/dump/disk-usage'\" \(4643 characters\)
sed "s/^X//" >'usr/local/admin/dump/disk-usage' <<'END_OF_FILE'
X#!/bin/sh
X# Name: /usr/local/admin/dump/disk-usage		Author: Joe Smith
X# Purpose: Creates a summary of disk usage on locally mounted disks.
X# These summary files are included at the beginning of each 'dump' tape
X# to make it easier to determine which tape contains a given directory.
X
X# This script is run daily around midnight and does the following:
X# 1) Runs 'du' on each mounted disk and creates three files:
X#    "/var/admin/dump/du/$host.$device" lists all directories on the partition,
X#    "/mountpoint/.etc/du.$host" has the same information sorted with biggest
X#    users first, and "/mountpoint/.etc/du.$weekday" has summary of top-level
X#    directories.
X# 2) Creates a file "/mountpoint/+$host+$device+" which includes the output
X#    from 'df' and the top 20 users.  Note: The presence of this file
X#    in the top level directory of a partition means that it will be
X#    visible when doing a "restore i"; this makes it easy to verify
X#    that the dump tape you mounted is really the one you think it is.
X#    Since the file is 22 lines long, "cat /home/`hostname`/+*" works nicely.
X#
X# To run 'du' on the root parition and not have it go into any other
X# partition, put the following into your /etc/fstab file:
X#	localhost:/ /mnt/root nfs rw,nosuid,hard,bg,intr 0 0 # for 'du'
X# The "bg" is needed because the standard /etc/rc.local file does not
X# start up rpc.mounted until much after "mount -vat nfs".
X#
X# See also: /usr/local/bin/df-i which combines "df" with "df -i" and "date".
X
XPATH=/usr/ucb:/usr/bin:/usr/etc; export PATH
X
Xadmindump=/var/admin/dump	# Where to put "tapes.$host" report
Xdudir=/var/admin/dump/du	# Where to store output from 'du'
Xdfi=/usr/local/bin/df-i		# To list % inodes and timestamp
Xlsf=/usr/local/bin/lsf		# Program to create filename database
Xestimate=/usr/local/admin/dump/estimate.8mm	# Reports tapes to do a dump
X
Xif [ -x $dfi ]; then DF=$dfi; else DF="df"; fi	# Use 'df-i' if it exists
Xif [ -x $estimate ]; then EST="$estimate 0"; else EST=$df; fi
Xhost=`hostname`			# Files are stored as /mountdir/.etc/du.$host
Xweekday=`date +%a`		# Sun though Sat
Xtmp=/tmp/disk-usage.$$
X
Xdate				# Send timestamp to stdout
Xmkdir -p $dudir			# This does nothing if directory already exists
X$DF >$dudir/$host.all		# List % disk space used and % inodes used
X
X# Format of /etc/mtab: "/dev/xd0e /var 4.2 rw,grpid,dev=0a04 1 3"
X# Don't process any disk that is mounted read-only (such as the CD-ROM).
X
Xegrep '4\.2|localhost|vbfs' /etc/mtab | grep -v 'ro,' | \
Xwhile read dev mount other
Xdo	# The 'egrep' filters out everything but local disks.
X  device=`basename $dev`		# xd0a, sd0a, id000a, etc
X  if [ $mount = / ]; then
X    rootdev=$device			# Remember for later
X    continue				# root is handled as "localhost:/"
X  else
X    outdir=$mount/.etc
X  fi
X  case $dev in
X    localhost:/) outdir=/.etc device=$rootdev ;;
X    localhost:*) continue	;;	# Ignore loopback file systems
X  esac
X
X  [ -d $outdir ] ||  mkdir -p $outdir	# Create the .etc directory if needed
X  out=${outdir}/du.$host
X  summary=$dudir/$host.$device
X  plusfile="+$host+$device+"		# Recognizable name for "restore -ivs"
X  $DF $outdir				# Show name of partition to stdout
X
X  # Create a 'du' (disk usage) report.  This can take a while.
X
X  if [ $mount = /var ]; then a="-a"; else a=""; fi	# List all /var files
X  cd $mount
X  du $a . >$summary 2>/dev/null		# Summarize all subdirectories
X
X  # Create a list of all files on the partition, if wanted.  The 'lsf'
X  # program will remove 'core' and '.nfs*' files more than a week old.
X  # It replaces both of the usual crontab entries:
X  # 0 0 * * * find / -type nfs -prune -o -name core   -mtime +7 -exec rm {} \;
X  # 0 2 * * * find / -type nfs -prune -o -name .nfs\* -mtime +7 -exec rm {} \;
X  # (Use /usr/local/admin/updatedb.lsf to eliminate yet another "find /" job.)
X
X  if [ -x $lsf ]; then			# If /usr/local/bin/lsf exists
X    if [ -f $mount/.etc/$host.lsf ]; then
X      $lsf -xdev -rm_core -rm_nfs -output $mount/.etc/$host.lsf .
X    else
X      $lsf -xdev -rm_core -rm_nfs -brief . >/dev/null
X    fi
X  fi
X
X  # Create the sorted summary of usage by directory.
X
X  sort -n -r $summary -o $out		# Numeric sort, biggest first
X  head -10 $out				# List top 10 directories to stdout
X  $DF $outdir >$plusfile		# Includes inodes and datestamp
X  head -20 $out >>$plusfile		# List top 20 directorys to +host+dev+
X  # Search for <tab><period><slash><anything_but_a_slash><end_of_line>
X  grep '	\./[^/]*$' $summary | grep -v 'lost+found' | sort +1 | \
X    sed "s%\.%$mount%" >$outdir/du.$weekday	# List top-level directories
X  echo ""
Xdone
X
X$EST | tee $admindump/tapes.$host	# Number of tapes to do a dump
X
Xdate
END_OF_FILE
if test 4643 -ne `wc -c <'usr/local/admin/dump/disk-usage'`; then
    echo shar: \"'usr/local/admin/dump/disk-usage'\" unpacked with wrong size!
fi
chmod +x 'usr/local/admin/dump/disk-usage'
# end of 'usr/local/admin/dump/disk-usage'
fi
if test -f 'usr/local/admin/dump/estimate.8mm' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'usr/local/admin/dump/estimate.8mm'\"
else
echo shar: Extracting \"'usr/local/admin/dump/estimate.8mm'\" \(1592 characters\)
sed "s/^X//" >'usr/local/admin/dump/estimate.8mm' <<'END_OF_FILE'
X#!/bin/sh
X# Name: /usr/local/admin/dump/estimate.8mm		Author: Joe Smith
X# Purpose: Determines how many tapes are required for today's dump
X# Usage: "estimate 0" to calculate number of tapes for a level 0 dump.
X
Xif [ "$1" = "" ]; then
X  level=9		# Default is for an incremental save
Xelse
X  level=$1; shift
Xfi
Xdisks="$*"		# Default is all 4.2 partitions in /etc/mtab
X
Xif [ "$disks" = "" ]; then	# Find 4.2 disks, excluding /dev/sr0 (/cdrom)
X  disks=`grep '4\.2' /etc/mtab | awk '!/dev\/sr[0-9]/ {print $1}'`
Xfi
X
Xalldisks=`echo $disks | tr ' ' ','`	# Comma separated list
Xecho "# ($alldisks) 0% .00$level"	# Show which partitions will be checked
X
X# Typical output from "dump bdsf9 112 54000 6000 /dev/null /usr"
X#  DUMP: Date of this level 0 dump: Fri Aug  7 01:21:41 1992
X#  DUMP: Date of last level 0 dump: the epoch
X#  DUMP: Dumping /dev/rsd0g (/usr) to /dev/null
X#  DUMP: mapping (Pass I) [regular files]
X#  DUMP: mapping (Pass II) [directories]
X#  DUMP: mapping (Pass II) [directories]
X#  DUMP: estimated 333448 blocks (162.82MB) on 0.09 tape(s).
X#** 'awk' will exit and stop the dump here
X#  DUMP: dumping (Pass III) [directories]
X#  DUMP: dumping (Pass IV) [regular files]
X#** Pass IV can take up to 30 minutes, that's why dump needs to be stopped
X
Xfor disk in $disks
Xdo			# Break the pipe as soon as "estimated" is seen
X  p=`df $disk | tail -1 | awk '{print $5}`	# Percent full
X  dump bdsf$level 112 54000 6000 /dev/null $disk </dev/null 2>&1 | \
X  awk '/Dumping/{printf "%-12s %-16s %-4s ",$3,$4,"'$p'"}; \
X  /estimated/{print $7;exit}'
Xdone			# This takes about 5 minutes per gigabyte
END_OF_FILE
if test 1592 -ne `wc -c <'usr/local/admin/dump/estimate.8mm'`; then
    echo shar: \"'usr/local/admin/dump/estimate.8mm'\" unpacked with wrong size!
fi
chmod +x 'usr/local/admin/dump/estimate.8mm'
# end of 'usr/local/admin/dump/estimate.8mm'
fi
if test -f 'usr/local/admin/dump/make-autoback' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'usr/local/admin/dump/make-autoback'\"
else
echo shar: Extracting \"'usr/local/admin/dump/make-autoback'\" \(1568 characters\)
sed "s/^X//" >'usr/local/admin/dump/make-autoback' <<'END_OF_FILE'
X#!/bin/perl
X# Name: /usr/local/admin/dump/make-autoback	Author: Joe Smith
X# Purpose: Produces output for /etc/autobackup with the following format:
X#device	tapeset	Fri/Sat Sun    Mon    Tue    Wed    Thu
X#8mm2	set15	930618
X#8mm	week4	930619 930620 930621 930622 930623 930624
X#8mm2	set01	930625
X#8mm	week1	930626 930627 930628 930629 930630 930701
X
X($incrmin,$incrmax,$incrdev) = ("week1","week4","8mm");
X($fullmin,$fullmax,$fulldev) = ("set01","set15","8mm2");
X$fullday = 5;			# 0=Sun,1=Mon,2=Tue,3=Wed,4=Thu,5=Fri,6=Sat
X
X$full = $ARGV[0];	# Name of next full save tape
X$full = $fullmax unless $full;
X$incr = $ARGV[1];	# Name of next incremental save tape
X$incr = $incrmax unless $incr;
X
Xsub yymmdd {
X  local($day) = @_;
X  local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime($day);
X  return (sprintf("%02d%02d%02d",$year,$mon+1,$mday),$wday);
X}
X
X$SecondsPerDay = 24 * 60 * 60;
X$StartDay = int(time/$SecondsPerDay)-1;
Xdo {	# Skip forward to date of next full save
X  ($yymmdd,$wday) = &yymmdd(++$StartDay * $SecondsPerDay);
X} until $wday == $fullday;
X
Xprint "device\tTapeset\tFri/Sat Sun    Mon    Tue    Wed    Thu\n";
Xfor ($i=$StartDay; $i<$StartDay+365; $i++) {
X  ($yymmdd,$wday) = &yymmdd($i*$SecondsPerDay);
X  if ($wday != $fullday) {	# If this is not the day to do a full save
X    push(@days,$yymmdd);	# then save this date for later
X  } else {
X    print "$incrdev\t$incr\t@days\n" if @days;
X    print "$fulldev\t$full\t$yymmdd\n";
X    @days = ();
X    $incr = $incrmin if ++$incr gt $incrmax;
X    $full = $fullmin if ++$full gt $fullmax;
X  }
X}  
END_OF_FILE
if test 1568 -ne `wc -c <'usr/local/admin/dump/make-autoback'`; then
    echo shar: \"'usr/local/admin/dump/make-autoback'\" unpacked with wrong size!
fi
chmod +x 'usr/local/admin/dump/make-autoback'
# end of 'usr/local/admin/dump/make-autoback'
fi
if test -f 'usr/local/admin/dump/make-shar' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'usr/local/admin/dump/make-shar'\"
else
echo shar: Extracting \"'usr/local/admin/dump/make-shar'\" \(937 characters\)
sed "s/^X//" >'usr/local/admin/dump/make-shar' <<'END_OF_FILE'
X#!/bin/csh
X# Name: /usr/local/admin/dump/make-shar		Author: Joe Smith
X# Purpose: Creates a shell-archive of the backup scripts.
X
Xset doc=usr/local/admin/dump/backup.doc
Xset tmp=/tmp/backup.shar
Xcd /					# Use pathnames relative to root
X
Xtouch etc/admin/dump/\#make-shar
Xrm -f usr/local/admin/*/\#* etc/admin/*/\#*	# Get rid of old editor files
Xset files=(usr/local/admin usr/local/admin/dump usr/local/admin/restore \
X  usr/local/admin/{dump,restore}/* etc/admin etc/admin/dump \
X  etc/admin/dump/{candidates,proprietary,schedule.{alpha,beta,gamma}})
Xset files=(`echo $files | sed s:${doc}::`)	# Doc file is outside of shar
X
Xls -lL $doc | tee $tmp
Xecho -n "The shar (shell archive) starts " >>$tmp
Xecho `wc -l <$doc` "lines into this message." >>$tmp
Xcat $doc >>$tmp
Xecho ""  >>$tmp
Xecho "---------------- cut here ----------------" >>$tmp
Xls -ldL $files
Xshar $files >>$tmp
Xecho ""; echo "		SHAR file is now in $tmp"
Xecho ""; ls -l $tmp
END_OF_FILE
if test 937 -ne `wc -c <'usr/local/admin/dump/make-shar'`; then
    echo shar: \"'usr/local/admin/dump/make-shar'\" unpacked with wrong size!
fi
chmod +x 'usr/local/admin/dump/make-shar'
# end of 'usr/local/admin/dump/make-shar'
fi
if test -f 'usr/local/admin/dump/retrieve' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'usr/local/admin/dump/retrieve'\"
else
echo shar: Extracting \"'usr/local/admin/dump/retrieve'\" \(4157 characters\)
sed "s/^X//" >'usr/local/admin/dump/retrieve' <<'END_OF_FILE'
X#!/bin/perl
X# Name: /usr/local/admin/dump/retrieve		Author: Joe Smith
X# Purpose: Reads tapes created by /usr/local/admin/dump/backup
X
X# 08/06/92 Removed blocking factor - 'restore' does the right thing without it.
X# 08/24/92 Added "8mm2" for /dev/rst2.
X
X$myTape   = $ARGV[0];	# Device type, "8mm", "6250", etc
X$tapehost = $ARGV[1];	# Hostname to restore from (optional)
X$mountdir = $ARGV[2];	# Where to restore the files (optional)
X
Xdie "Usage: $0 device [tapehost [mountpoint] ]\n" .
X    "   eg. $0 8mm gemini\n"	if $myTape eq "";
X
X$ETC = "/etc/admin";			# /etc files
X$USR = "/usr/local/admin";		# /usr files
X$VAR = "/var/admin";			# /var files
X$PAGER = "/usr/ucb/more";		# For displaying TOC
X
X$candidates = "$ETC/dump/candidates";	# candidates
X$schedule   = "$ETC/dump/schedule";	# schedule (.$candidate)
X$restore    = "$USR/restore";		# restore scripts
X$toc        = "$VAR/dump";		# save toc files here
X@restoredir = ("/home/restore", "/var/tmp/restore"); # where to restore
X
X
X%Tapes = (
X#    key     dev
X    "st0",  "st0",
X    "cart", "st0",
X    "8mm",  "st0",
X    "8mm1", "st1",
X    "st1",  "st1",
X    "8mm2", "st9",	# Kludge for 'delta' and 'titan'
X    "st2",  "st9",
X    "mt8",  "mt8",
X    "6250", "mt8",
X    "mt0",  "mt0",
X    "1600", "mt0",
X);
X
X# $ENV{"PAGER"} is not used because 'less' does not exit automatically like
X# 'more' does when given a file that fits on a single screen.
X
X$PAGER = "cat" if ! -x $PAGER;	# Make sure that the pager program exists
X
X# Select an appropriate directory to restore the files into.
X# This will avoid overwriting existing files unless explicitly asked to.
X
X$mode = "i";			# Default is interactive restore
Xif ("$mountdir" eq "") {	# If no directory specified,
X  for (@restoredir) {		#  from one of the standard places.
X    $mountdir = $_;
X    last if -d $_;		# Select the first one that exists
X  }
X  if (! -d $mountdir) {		# If none exist, use last one
X    mkdir("$mountdir",0777) && print "Created $mountdir\n";
X  }
X  print "No mount point specified, defaulting to $mountdir\n";
X  $showdir = "du";		# List all subdirectories that get extracted
X} else {
X  $showdir = "ls -lgd";		# List only top level if explicit directory
X  die "No such directory $mountdir\n" if (! -d $mountdir); 
X  print "You have specified $mountdir as the place to restore files.\n";
X  system("df $mountdir");
X  print "Do you wish to restore the entire disk partition? (y/n) ";
X  $_ = <STDIN>;
X  $mode = "r" if /[yY]/;
X}
Xchdir($mountdir) || die "Could not 'cd' to $mountdir";
X$mountdir = `pwd`;		# Resolve symbolic link (if any)
X
X# if illegal tape device die before going on  [MORE WORK NEEDED HERE]
X$TAPE = $Tapes{ $myTape }
X || die "Device must be one of: " . join(" ",keys(%Tapes)) . "\n";
X
Xchop($thishost = `hostname`);
X$tapehost = $thishost if "$tapehost" eq "";
X$rsh = "";	  $rsh = "rsh $tapehost "    if $tapehost ne $thishost;
X$remotetape = ""; $remotetape = "$tapehost:" if $tapehost ne $thishost;
X
X# Read table of contents 
X#
X# Be sure tape is rewound
Xprint "Please insert the desired backup tape in /dev/r$TAPE on $tapehost.\n";
Xprint "Type <cr> when ready.  Waiting...";
X$foo = <STDIN>;						# Wait for cr
X
Xprint "Reading Table of Contents from tape...\n";
Xsystem("$rsh mt -f /dev/r$TAPE rewind");
X
X# Read first part of Table of Contents from first file on dump tape.
Xsystem("$rsh sed /End.of.Tape/,999d /dev/r$TAPE | $PAGER"); # Rewind tape after
X
X# The following statement should not be necessary, but if you are running
X# SunOS-4.1.1 and have not installed SCSI patch 100280-02, then the system
X# will crash with "panic: psig action".
Xsystem("$rsh mt -f /dev/r$TAPE rewind");	# Force an extra rewind
X
Xprint "\nEnter the number of the desired file system: ";
X$ssn = <STDIN>;						# Get saveset number
X
Xprint "\nSearching tape for requested file system.  This takes some time.\n";
Xprint "Use 'ls', 'add', and 'extract' commands.\n" if "$mode" eq "i";
Xprint "cd $mountdir\n";
X$foo = "/usr/etc/restore $mode"."vfs $remotetape/dev/r$TAPE $ssn";
Xprint $foo; $status=system($foo);
Xprint "Rewinding\n";
Xprint "Files restored to: $showdir $mountdir\n";
Xsystem("$showdir $mountdir");	# Show where files have were restored
Xexit $status;
END_OF_FILE
if test 4157 -ne `wc -c <'usr/local/admin/dump/retrieve'`; then
    echo shar: \"'usr/local/admin/dump/retrieve'\" unpacked with wrong size!
fi
chmod +x 'usr/local/admin/dump/retrieve'
# end of 'usr/local/admin/dump/retrieve'
fi
if test -f 'usr/local/admin/restore/install_unbundled' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'usr/local/admin/restore/install_unbundled'\"
else
echo shar: Extracting \"'usr/local/admin/restore/install_unbundled'\" \(1088 characters\)
sed "s/^X//" >'usr/local/admin/restore/install_unbundled' <<'END_OF_FILE'
X#! /bin/csh -fb
X# Name: /usr/local/admin/restore/install_unbundled	Author: Joe Smith
X# Purpose: Ombudsman between extract_unbundled and restore_8mm.
X
X# /usr/etc/extract_unbundled will read the first file off the tape, show
X# it to the user, and ask if the user wants to proceed.  If yes, it
X# goes to the /usr/tmp/unbundled directory and invokes 'tar' to extract
X# the scripts from the second file on the tape (which should include
X# the file "./install_unbundled").  Assuming that operation was a success,
X# extract_unbundled then calls ./install_unbundled (this file).  This
X# file converts the command line arguments to what ./restore_8mm expects.
X
Xset remotehost=""
Xset tapedevice=/dev/nrst0
Xwhile ("x$1" =~ x-*)
X   if ("x$1" =~ x-r*) set remotehost=`expr x$1 : 'x-r\(.*\)'`
X   if ("x$1" =~ x-d*) set tapedevice=/dev/nr`expr x$1 : 'x-d\(.*\)'`
X   if ("x$1" =~ x-f*) set forced=-f
X   shift
Xend
Xecho ./restore_8mm $forced $tapedevice $remotehost
X./restore_8mm $forced $tapedevice $remotehost
Xif ($cwd =~ */tmp/*) then
X  rm $0; exit 0	# Delete /var/tmp/unbundled/install_unbundled
Xendif
END_OF_FILE
if test 1088 -ne `wc -c <'usr/local/admin/restore/install_unbundled'`; then
    echo shar: \"'usr/local/admin/restore/install_unbundled'\" unpacked with wrong size!
fi
chmod +x 'usr/local/admin/restore/install_unbundled'
# end of 'usr/local/admin/restore/install_unbundled'
fi
if test -f 'usr/local/admin/restore/read_contents' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'usr/local/admin/restore/read_contents'\"
else
echo shar: Extracting \"'usr/local/admin/restore/read_contents'\" \(4994 characters\)
sed "s/^X//" >'usr/local/admin/restore/read_contents' <<'END_OF_FILE'
X#!/bin/csh
X# Name: /usr/local/admin/restore/read_contents		Author: Joe Smith
X# Purpose: Creates a list of all files on a dump tape using "restore tv".
X
X# Each day's save has a table-of-contents file, a 'tar' save, and N 'dump'
X# saves.  The table-of-contents file is parsed to determine the value for N.
X# The saves for several days may be appended on the tape.  After the
X# contents have been read, the tape is positioned such that additional
X# saves may be appended.
X
X# Usage: read_contents -v $TAPE /var/admin/dump/toc N
X
Xset listfiles=0			# Default is to list only directories
Xif ("x$1" == "x-v") then
X  set listfiles=1; shift	# Use "-v" to list all the saved files
Xendif
Xif ("$1" != "") setenv TAPE "$1"
Xif ($?TAPE == 0) setenv TAPE /dev/nrst0		# Default tape device
Xset dir=/var/admin/dump/toc			# Change this if needed
Xif ("$2" != "") set dir=$2
Xset maxfile=9999				# Read to end of tape
Xif ("$3" != "") then
X  set maxfile=$3	# File number where to stop reading
X  if ($maxfile =~ ?) set maxfile=0$maxfile
X  echo "Highest tape file number expected = $maxfile"
Xendif
X
Xif (! -d $dir) mkdir $dir
Xcd $dir && echo "Changing current directory to $dir"
X
Xset first=""
Xset retries=0
Xwhile ("$first" == "")
X  @ retries++
X  if ($retries > 7) then
X    echo "$0: unable to read contents from tape - aborting"
X    exit 1
X  endif
X  echo "Rewinding tape $TAPE"
X  mt -f $TAPE rewind
X  sleep ${retries}0		# Sleep 10 seconds, then 20 seconds, etc
X  set first=`head -1 $TAPE`	# Set "week1" Tape "gnsmp-daily" written <date>
Xend
X
Xecho ""
Xset tapename=`echo $first[2].$first[4] | sed 's/"//g'`
Xmkdir -p $tapename
Xset summary=$tapename/00
Xecho "Contents of $TAPE as of `date`" >$summary
Xecho "$first" | tee -a $summary; echo "" >>$summary
Xmt -f $TAPE rewind		# Go back to beginning of tape
Xset i=0
Xecho "$summary date     level   host:disk   mount   directories/files" | tee -a $summary
X
Xalias tapefile 'echo $tapestat | sed -e "s/.*file no= \([0-9]*\).*/\1/"'
Xalias set_i 'set tf=`tapefile`; @ i = $tf + 1; if ($i < 10) set i=0$i'
X
Xwhile($i <= $maxfile)			# Loop through each day on tape
X  set tapestat=`mt -f $TAPE status`
X  if ("$tapestat" =~ *EOT*) goto eot
X  set reason="Interrupt:"
X  onintr quit
X  set_i					# Set $i to dump save number
X
X  set file=$tapename/$i; echo -n "$file "
X  cp $TAPE $file			# Table of contents
X  set last=`grep '^[0-9].*lvl' $file | tail -1 | sed 's/\([0-9]*\).*/\1/' `
X  if ($last > $i) then
X    @ first = $i + 2			# i+0 = contents, i+1 = tar save
X    if ($first < 10) set first="0$first"
X  else
X    set first=`grep '^[0-9].*lvl' $file | head -1 | sed 's/\([0-9]*\).*/\1/' `
X  endif
X  echo "     Contents for savesets $first-$last"
X  echo "$file      Contents for savesets $first-$last" >>$summary
X
X  set tapestat=`mt -f $TAPE status`
X  if ("$tapestat" =~ *EOT*) goto eot
X  set_i
X  if ($i > $maxfile) break
X  set file=$tapename/$i; echo -n "$file "
X  tar tvifb $TAPE 112 >& $file		# "install_unbundled" restore scripts
X  if ($status != 0) then
X    set tapestat=`mt -f $TAPE status | tee -a $file`
X    if ("$tapestat" =~ *EOT* || "$tapestat" =~ *blank*) rm $file
X    echo "End of tape $TAPE as of `date`" >>$summary
X    goto eot
X  endif
X  set wc=`wc -l <$file`
X  echo "     'tar' save with $wc files (scripts for restore)"
X  echo "$file      'tar' save with $wc files (scripts for restore)" >>$summary
X  set_i
X  mt -f $TAPE asf $i			# Skip to end of tar file
X  
X  set dumpfiles=1
X  while ($dumpfiles)			# Loop through all parts of daily save
X    set tapestat=`mt -f $TAPE status`
X    set_i				# Set $tf and $i
X    if ($i > $last) then
X      set dumpfiles=0			# Switch to reading contents again
X      break
X    endif
X    set file=$tapename/$i; echo -n "$file "
X    restore tvf $TAPE >$file
X    if ($status == 0) then
X      set dirs=`grep -c '^dir' $file`	# Number of directories save to tape
X      set files=`grep -c '^leaf' $file`	# Number of nondirectories saved
X      if ($listfiles == 0) then
X        grep -v '^leaf' $file >$file.tmp
X        sed 's/^dir *[0-9]*./dir /' $file.tmp >$file
X	rm -f $file.tmp
X      endif
X      # Look for "Dump date: Day Mon dd hh:mm:ss yyyy"
X      set dd=(`head $file | grep 'Dump *date:'`)	# Date dump was taken
X      if ($#dd > 6) then	# "Level 0 dump of / on tardis:/dev/sd0a"
X        set dl=(`head $file | grep 'Level . dump'` . . . . . . .)
X        #         month  day    year   level host:disk mount
X        set temp="$dd[4] $dd[5] $dd[7] $dl[2] $dl[7] $dl[5]	$dirs/$files"
X      else
X        set temp="`wc -l <$file` lines"		# Should never get here
X      endif
X      echo "$temp"
X      echo "$file $temp" >>$summary
X      mt asf $i				# Skip to start of next file
X    else
X      /usr/5bin/echo '...retrying...\r\c'
X      mt -f $TAPE asf $tf		# Go back to start of current file
X      set dumpfiles=0			# To read TOC next
X    endif
X  end			# End loop through 'dump' files
Xend			# End loop through multi-day save
X
Xeot:
Xmt -f $TAPE asf $tf		# Position tape to where it can be written to
Xset reason="End of tape:"
Xquit:
Xecho "$reason $tapestat"
END_OF_FILE
if test 4994 -ne `wc -c <'usr/local/admin/restore/read_contents'`; then
    echo shar: \"'usr/local/admin/restore/read_contents'\" unpacked with wrong size!
fi
chmod +x 'usr/local/admin/restore/read_contents'
# end of 'usr/local/admin/restore/read_contents'
fi
if test -f 'usr/local/admin/restore/restore_8mm' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'usr/local/admin/restore/restore_8mm'\"
else
echo shar: Extracting \"'usr/local/admin/restore/restore_8mm'\" \(2398 characters\)
sed "s/^X//" >'usr/local/admin/restore/restore_8mm' <<'END_OF_FILE'
X#! /bin/csh -fb
X# Name: /usr/local/admin/restore/restore-8mm		Author: Joe Smith
X# Purpose: Automates restoring files from an 8mm with multiple file systems.
X# Note: This is a stripped-down equivalent of /usr/local/admin/dump/retrieve.
X#       This script does not require /bin/perl or /usr/local/bin/perl,
X#	and therefore is suitable for restoring /usr/local or all of /usr.
X
Xset path=(/usr/ucb /usr/bin /usr/etc)
Xset tape=/dev/nrst0		# Default if not specified on command line
Xset host=""			# 	"	"	"
Xset restoredir=/home/restore	#	"	"	"
Xset pager=/usr/ucb/pager	# This works better than 'less' in this case
Xif (! -x $pager) set pager=cat
Xif (! -d $restoredir) set restoredir=/var/tmp/restore
Xset mounted=no			# Set to "yes" if tape is known to be online
Xset showdir=du
Xif ("x$1" == "x-f") then
X  set mounted=yes;  shift	# If called via install_unbundled
Xendif
Xif ("$1" != "") set tape=$1
Xif ("$2" != "") set host=$2
Xif ("$3" != "") set restoredir=$3 showdir="ls -lgd"
Xif ("$host" != "") then
X  set hosttape=${host}:$tape
X  set host="rsh $host"
Xelse
X  set hosttape=$tape
Xendif
Xif (! -d $restoredir) then
X  if ("$restoredir" =~ /var/tmp/*) then
X    mkdir -p $restoredir && echo "Created $restoredir"
X  else
X    echo "Directory $restoredir does not exist"
X    exit 1
X  endif
Xendif
X
X#
Xif ($mounted == yes) then
X  if (-d du) then
X    echo "The files in $cwd/du may be helpful in locating directories:"
X    ls du
X  else
X    echo "Cannot find the 'du' files in $cwd/du, proceeding"
X  endif
Xelse
X  echo "Please mount the desired backup tape on $hosttape"
X  echo "Type <cr> when ready. Waiting..."
X  set skip = $<
Xendif
X
Xrepeat 4 echo ""
Xecho "The following file systems are available on this dump tape:"
X$host mt -f $tape rewind
Xecho ""
X$host $pager $tape
X$host mt -f $tape rewind
Xecho ""
Xecho -n "Enter the number of the desired file system: "
Xset skip = $<
X#
Xecho "SEARCHING DUMP CARTRIDGE...PLEASE BE PATIENT...THIS TAKES A LONG TIME..."
Xecho "(Type 'ls' at the 'restore>' prompt to verify tape directory.)"; echo ""
Xset echo
Xcd $restoredir
Xset restoredir=`pwd`		# In case of symbolic link
Xrestore ivfs $hosttape $skip
Xunset echo
Xecho ""; echo "The files have been restored to:"
X$showdir $restoredir		# Show disk usage if to default dir
Xecho -n "Rewinding $hosttape ..."
X$host mt -f $tape rewind
Xecho " done"
Xif (-f /usr/5bin/banner) then
X  /usr/5bin/banner Remove Tape
Xelse
X  echo "REMOVE TAPE"
Xendif
END_OF_FILE
if test 2398 -ne `wc -c <'usr/local/admin/restore/restore_8mm'`; then
    echo shar: \"'usr/local/admin/restore/restore_8mm'\" unpacked with wrong size!
fi
chmod +x 'usr/local/admin/restore/restore_8mm'
# end of 'usr/local/admin/restore/restore_8mm'
fi
if test ! -d 'etc/admin' ; then
    echo shar: Creating directory \"'etc/admin'\"
    mkdir 'etc/admin'
fi
if test ! -d 'etc/admin/dump' ; then
    echo shar: Creating directory \"'etc/admin/dump'\"
    mkdir 'etc/admin/dump'
fi
if test -f 'etc/admin/dump/candidates' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'etc/admin/dump/candidates'\"
else
echo shar: Extracting \"'etc/admin/dump/candidates'\" \(535 characters\)
sed "s/^X//" >'etc/admin/dump/candidates' <<'END_OF_FILE'
X# Name: /etc/sysadm/dump/candidates	Author: Carl Baltrunas 
X# Purpose: Used by /usr/sysadm/dump/backup to get a list of hosts to dump.
X# Format: "groupname" <tab> "list of hosts"
X
X# Fremont, CA
Xpublic	delta titan
Xprivate tymload tymgen
Xseta	delta
Xsetb	titan
Xsetc	tymload tymgen
X
X# Temporary HACK to avoid operator error
Xtymload	tymload tymgen
Xtymgen	tymload tymgen
X
X# Norristown, PA
Xbackup1	boomer flyer
Xbackup2	charger
X
X# San Jose, CA
Xtso	tardis doctor romana borusa
Xgnsmp	tardis doctor romana borusa
Xall	tardis doctor romana borusa
X
END_OF_FILE
if test 535 -ne `wc -c <'etc/admin/dump/candidates'`; then
    echo shar: \"'etc/admin/dump/candidates'\" unpacked with wrong size!
fi
# end of 'etc/admin/dump/candidates'
fi
if test -f 'etc/admin/dump/proprietary' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'etc/admin/dump/proprietary'\"
else
echo shar: Extracting \"'etc/admin/dump/proprietary'\" \(401 characters\)
sed "s/^X//" >'etc/admin/dump/proprietary' <<'END_OF_FILE'
X+-----------------------------------------------------------------------------+
X| Proprietary rights of BT North America are included in files stored on this |
X| tape.  The contents of this tape are to be used for backup and recovery     |
X| purposes only.  Any other use is a violation of BTNA guidelines.  (c) 1993  |
X+-----------------------------------------------------------------------------+
X
END_OF_FILE
if test 401 -ne `wc -c <'etc/admin/dump/proprietary'`; then
    echo shar: \"'etc/admin/dump/proprietary'\" unpacked with wrong size!
fi
# end of 'etc/admin/dump/proprietary'
fi
if test -f 'etc/admin/dump/schedule.alpha' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'etc/admin/dump/schedule.alpha'\"
else
echo shar: Extracting \"'etc/admin/dump/schedule.alpha'\" \(106 characters\)
sed "s/^X//" >'etc/admin/dump/schedule.alpha' <<'END_OF_FILE'
Xlocaltape	8mm=st0					# schedule.alpha
X# alpha is diskless - this file exists only to define 'localtape'.
END_OF_FILE
if test 106 -ne `wc -c <'etc/admin/dump/schedule.alpha'`; then
    echo shar: \"'etc/admin/dump/schedule.alpha'\" unpacked with wrong size!
fi
# end of 'etc/admin/dump/schedule.alpha'
fi
if test -f 'etc/admin/dump/schedule.beta' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'etc/admin/dump/schedule.beta'\"
else
echo shar: Extracting \"'etc/admin/dump/schedule.beta'\" \(1039 characters\)
sed "s/^X//" >'etc/admin/dump/schedule.beta' <<'END_OF_FILE'
Xlocaltape	cart=st8 8mm=alpha:st0 8mm2=gamma:st8	# schedule.beta
X
X#dev	days  level	tape-name	list of partitions
X8mm	smtwt.s	0	tso-daily	sd0a:root sd3a:misc3a
X8mm	smtwt.s	5	tso-daily	sd0g:usr sd3g:local sd3h:home/beta
X8mm	.....f.	0	tso-tape2	sd0a:root sd3a:misc3a
X8mm	.....f.	0	tso-tape2	sd0g:usr sd3g:local sd3h:home/beta
X8mm2	smtwt.s	0	tso-daily	sd0a:root sd3a:misc3a
X8mm2	smtwt.s	5	tso-daily	sd0g:usr sd3g:local sd3h:home/beta
X8mm2	.....f.	0	tso-full	sd0a:root sd3a:misc3a
X8mm2	.....f.	0	tso-full	sd0g:usr sd3g:local sd3h:home/beta
X
Xcart	smtwt.s	0	tso-daily	sd0a:root sd3a:misc3a
Xcart	smtwt.s	5	tso-daily	sd0g:usr sd3g:local sd3h:home/beta
Xcart	.....f.	0	beta-0		sd0a:root sd3a:misc3a
Xcart	.....f.	0	beta-usr	sd0g:usr	# 3.10 tapes
Xcart	.....f.	0	beta-local	sd3h:home/beta	# 7.86 tapes
X
Xc150	smtwt.s	0	tso-daily	sd0a:root sd3a:misc3a
Xc150	smtwt.s	5	tso-daily	sd0g:usr sd3g:local sd3h:home/beta
Xc150	.....f.	0	beta-0		sd0a:root sd3a:misc3a
Xc150	.....f.	0	beta-usr	sd0g:usr	# 1.24 tapes
Xc150	.....f.	0	beta-local	sd3h:home/beta	# 3.14 tapes
END_OF_FILE
if test 1039 -ne `wc -c <'etc/admin/dump/schedule.beta'`; then
    echo shar: \"'etc/admin/dump/schedule.beta'\" unpacked with wrong size!
fi
# end of 'etc/admin/dump/schedule.beta'
fi
if test -f 'etc/admin/dump/schedule.gamma' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'etc/admin/dump/schedule.gamma'\"
else
echo shar: Extracting \"'etc/admin/dump/schedule.gamma'\" \(925 characters\)
sed "s/^X//" >'etc/admin/dump/schedule.gamma' <<'END_OF_FILE'
Xlocaltape 8mm2=st10 8mm=alpha:st0 cart=beta:st8 c150=delta:st8 # schedule.gamma
X
X#dev	days  level	tape-name	list of partitions
X8mm	smtwt.s	0	tso-daily	sd0a:root sd0d:var
X8mm	smtwt.s	5	tso-daily	sd0g:usr sd0h:home/gamma
X8mm	smtwt.s	5	tso-daily	sd2a:export sd2h:production
X8mm	smtwt.s	5	tso-daily	sd1a:home/testing sd1h:misc4h
X8mm	.....f.	0	tso-tape1	sd0a:root sd0d:var
X8mm	.....f.	0	tso-tape1	sd0g:usr sd0h:home/gamma
X8mm	.....f.	0	tso-tape1	sd2a:export sd2h:production
X8mm	.....f.	0	tso-tape2	sd1a:home/testing sd1h:misc4h
X
X8mm2	smtwt.s	0	tso-daily	sd0a:root sd0d:var
X8mm2	smtwt.s	5	tso-daily	sd0g:usr sd0h:home/gamma
X8mm2	smtwt.s	5	tso-daily	sd2a:export sd2h:production
X8mm2	smtwt.s	5	tso-daily	sd1a:home/testing sd1h:misc4h
X8mm2	.....f.	0	tso-full	sd0a:root sd0d:var
X8mm2	.....f.	0	tso-full	sd0g:usr sd0h:home/gamma
X8mm2	.....f.	0	tso-full	sd2a:export sd2h:production
X8mm2	.....f.	0	tso-full	sd1a:home/testing sd1h:misc4h
X
END_OF_FILE
if test 925 -ne `wc -c <'etc/admin/dump/schedule.gamma'`; then
    echo shar: \"'etc/admin/dump/schedule.gamma'\" unpacked with wrong size!
fi
# end of 'etc/admin/dump/schedule.gamma'
fi
echo shar: End of shell archive.
exit 0
-- 
Joe Smith (408)922-6220     BTNA GNS Major Programs, TYMNET Global Network
<jms@tardis.tymnet.com>     P.O. Box 49019, MS-C51, San Jose, CA 95161-9019
CA license plate: "POPJ P,"    Married to the LB, Quantum Leap's #1 net.fan
PDP-10, 36-bits forever!    Humorous disclaimer: "My Amiga 3000 speaks for me."