chiark / gitweb /
Merge Peter Maydell's changes.
authorianmdlvl <ianmdlvl>
Sun, 7 Oct 2001 17:50:46 +0000 (17:50 +0000)
committerianmdlvl <ianmdlvl>
Sun, 7 Oct 2001 17:50:46 +0000 (17:50 +0000)
14 files changed:
backup/backuplib.pl
backup/bringup
backup/checkallused
backup/driver
backup/full
backup/increm
backup/iwjbackup.txt [new file with mode: 0644]
backup/readbuffer
backup/readbuffer.c
backup/settings.pl
backup/takedown
backup/whatsthis [new file with mode: 0755]
backup/writebuffer
backup/writebuffer.c

index d412c94..9acd7a0 100644 (file)
@@ -1,9 +1,14 @@
 #
 
+# Assorted useful functions used by the backup scripts.
+
 sub printdate () {
     print scalar(localtime),"\n";
 }
 
+# Set status info -- we write the current status to a file 
+# so if we hang or crash the last thing written to the file
+# will tell us where we were when things went pear-shaped.
 sub setstatus ($) {
     open S, ">this-status.new" or die $!;
     print S $_[0],"\n" or die $!;
@@ -11,6 +16,8 @@ sub setstatus ($) {
     rename "this-status.new","this-status" or die $!;
 }
 
+# startprocess, endprocesses, killprocesses are 
+# used to implement the funky pipeline stuff.
 sub startprocess ($$$) {
     my ($i,$o,$c) = @_;
     print LOG "  $c\n" or die $!;
@@ -42,28 +49,39 @@ sub killprocesses {
     undef %processes;
 }
 
+# Read a fsys.foo filesystem group definition file.
+# Syntax is: empty lines and those beginning with '#' are ignored.
+# Trailing whitespace is ignored. Lines of the form 'prefix foo bar'
+# are handled specially, as arex lines 'exclude regexp'; otherwise 
+# we just shove the line into @fsys and let parsefsys deal with it.
 sub readfsys ($) {
     my ($fsnm) = @_;
     open F, "$etc/fsys.$fsnm" or die "Filesystems $fsnm unknown ($!).\n";
     for (;;) {
-       $_= <F> or die; chomp; s/\s*$//;
+       $_= <F> or die "unexpected EOF in $etc/fsys.$fsnm\n"; chomp; s/\s*$//;
        last if m/^end$/;
        next unless m/\S/;
        next if m/^\#/;
        if (m/^prefix\s+(\w+)\s+(\S.*\S)$/) {
            $prefix{$1}= $2;
-           next;
        } elsif (m/^prefix\-df\s+(\w+)\s+(\S.*\S)$/) {
            $prefixdf{$1}= $2;
-           next;
+       } elsif (m/^excludedir\s+(\S.*\S)$/) {
+            push @excldir,$1;
+        } elsif (m/^exclude\s+(\S.*\S)$/) {
+            push @excl,$1;
+        } else {
+           push @fsys,$_;
        }
-       push @fsys,$_;
     }
     close F or die $!;
 }
 
+# Parse a line from a filesystem definition file. We expect the line
+# to be in $tf.
 sub parsefsys () {
     if ($tf =~ m,^(/\S*)\s+(\w+)$,) {
+        # Line of form '/file/system   dumptype'
        $atf= $1;
        $tm= $2;
        $prefix= '<local>';
@@ -71,6 +89,8 @@ sub parsefsys () {
        -d _ or die "not a dir: $atf";
        $rstr= '';
     } elsif ($tf =~ m,^(/\S*)\s+(\w+)\s+(\w+)$,) {
+        # Line of form '/file/system dumptype prefix'
+        # (used for remote backups, I think)
        $atf= $1;
        $tm= $2;
        $prefix= $3;
index 6bcd5d5..ffca871 100755 (executable)
@@ -1,5 +1,8 @@
 #!/bin/sh
+# Very simple: extract the default runlevel from /etc/inittab
+# and change to it with telinit.
 
 runlevel=`sed -ne '/^id:/ s/.*:\([0-9]\):.*/\1/p' /etc/inittab`
 telinit $runlevel
-chvt 11
+# This switches to virtual console 11, but I don't think I want that -- PMM 
+#chvt 11
index fd613f3..8fb4468 100755 (executable)
@@ -1,5 +1,9 @@
 #!/usr/bin/perl
 
+# Read all the configuration files and check that all filesystems
+# are either backed up in both full and incremental dumps or 
+# listed as exceptions.
+
 BEGIN {
     $etc= '/etc/backup';
     require "$etc/settings.pl";
@@ -83,20 +87,34 @@ for $pfx ('', sort keys %prefix) {
        }
     }
     print "\n";
-    $!=0; close(X); $? and die "$cmd $? $!";
+    $!=0; close(X); $? and die "$? $!";
 }
 
 foreach $fsg (keys %usedkb) {
     print "filesystem group $fsg: $usedkb{$fsg} 1K-blocks$unkkb{$fsg}\n";
 }
 
+# We check that all mounted filesystems are dumped and all
+# filesystems to be dumped are mounted. The expected-diffs
+# config file allows us to make exceptions.
+# eg: 
+# #expect disk2 to be mounted but not dumped
+# !/disk2
+# # CD may or may not be mounted but should not be dumped in either case
+# ?/cdrom
+
 open Z,"$etc/expected-diffs" or die $!;
 for (;;) {
     $_= <Z> or die; chomp; s/\s*$//;
     last if m/^end$/;
     next unless m/^\S/;
     next if m/^\#/;
-    if (s/^\!//) {
+    if (s/^\?//) {
+        print "non-permanent filesystem expected not to be dumped: $_\n";
+        if (defined($mounted{$_})) {
+            delete $mounted{$_};
+        }
+    } elsif (s/^\!//) {
        &e("expected not to be dumped, but not a mount point: $_")
            unless defined($mounted{$_});
         print "filesystem expected not to be dumped: $_\n";
index 394b3fb..3cede61 100755 (executable)
@@ -1,4 +1,5 @@
 #!/bin/sh
+# This is the driver script that actually runs backups.
 
 cd /var/local/backup
 PATH=/usr/local/lib/backup:$PATH export PATH
@@ -11,11 +12,18 @@ fi
 rm -f this-status p p2
 echo 'FAILED to start dump script' >this-status
 
+# Here we go : run 'full', which (name notwithstanding) handles
+# both full and incremental backups, according to the ID of the
+# tape in the drive.
 full 2>&1 | tee this-log
 
 status=`cat this-status 2>/dev/null`
 
-cat <<END - this-log | /usr/lib/sendmail -oi -om -odq -t
+# Mail a report to somewhere appropriate; -odq removed (means just 
+# queue message, don't try to deliver) because it just delays the
+# message (you might want that if mail was one of the services turned
+# off for the duration of the backup, though).
+cat <<END - this-log | /usr/lib/sendmail -oi -om -oee -t
 To: dump-reports
 Subject: Dump Report: $status
 
@@ -24,6 +32,7 @@ END
 rm -f /TAPEID
 
 if [ "x$1" != test ]; then
+        # Bring the system up as multiuser again
        bringup
        stty isig
 fi
index 0608e60..5e6d23e 100755 (executable)
@@ -8,11 +8,17 @@ BEGIN {
 
 $|=1;
 
+# Check to see whether the tape.nn and fsys.nn files are sane.
+# checkallused checks that all the filesystems mounted are in fact
+# dumped in both full and incremental dumps.
+setstatus "FAILED configuration check";
 print "Configuration check ...\n" or die $!;
 system 'checkallused'; $? and die $?;
 
 printdate();
 
+setstatus "FAILED reading TAPEID";
+# Try to read the tape ID from the tape into the file TAPEID
 unlink 'TAPEID';
 system "mt -f $tape rewind"; $? and die $?;
 system "mt -f $tape setblk $blocksizebytes"; $? and die $?;
@@ -20,6 +26,9 @@ system "dd if=$tape bs=${blocksize}b count=10 | tar -b$blocksize -vvxf - TAPEID"
 
 setstatus "FAILED during startup";
 
+# We need some ID; if the tape has one already that takes precedence;
+# otherwise the user might have set a tape ID that this should be
+# by creating really-TAPEID.
 if (open T, "TAPEID") {
     unlink 'really-TAPEID';
 } elsif (open T, "really-TAPEID") {
@@ -27,6 +36,7 @@ if (open T, "TAPEID") {
     die "No TAPEID.\n";
 }
 
+# read the ID; it had better be a non-empty string of alphanumeric chars.
 chomp($tapeid= <T>);
 $tapeid =~ m/[^0-9a-zA-Z]/ and die "Bad TAPEID ($&).\n";
 $tapeid =~ m/[0-9a-zA-Z]/ or die "Empty TAPEID.\n";
@@ -34,6 +44,7 @@ close T;
 
 setstatus "FAILED at tape identity check";
 
+# We don't let the user overwrite the tape used for the last backup.
 if (open L, "last-tape") {
     chomp($lasttape= <L>);
     close L;
@@ -43,6 +54,10 @@ if (open L, "last-tape") {
 
 die "Tape $tapeid same as last time.\n" if $tapeid eq $lasttape;
 
+# $tapeid identifies the individual tape; $tapedesc is its current
+# identity and function, for printing in messages.  You can make these
+# namespaces the same if you like, or you can make the tape.<tapeid>
+# files be links to tape.<tapedesc> files.
 if (defined($tapedesc= readlink "$etc/tape.$tapeid")) {
     $tapedesc =~ s/^.*\.//;
     $tapedesc .= "($tapeid)";
@@ -50,6 +65,13 @@ if (defined($tapedesc= readlink "$etc/tape.$tapeid")) {
     $tapedesc = $tapeid;
 }
 
+# Parse the appropriate tape.nn file.
+# Format is: empty lines and lines starting '#' are ignored. Trailing
+# whitespace is ignored. File must end with 'end' on a line by itself.
+# Either there should be a line 'incremental' to indicate that this is
+# a tape for incremental backups, or a pair of lines 'filesystems fsg'
+# and 'next tapeid', indicating that this tape is part of a full 
+# backup, containing the filesystem group fsg. 
 undef $fsys;
 open D, "$etc/tape.$tapeid" or die "Unknown tape $tapeid ($!).\n";
 for (;;) {
@@ -69,6 +91,7 @@ for (;;) {
 }
 close D or die $!;
 
+# Incremental backups are handled by increm, not us.
 if ($incremental) {
     die "incremental tape $tapeid has next or filesystems\n"
        if defined($next) || defined($fsys);
@@ -78,14 +101,17 @@ if ($incremental) {
     die $!;
 }
 
+# Read the filesystem group definition (file fsys.nnn)
 readfsys("$fsys");
 openlog();
 
 $doing= "dump of $fsys to tape $tapedesc in drive $tape";
 print LOG "$doing:\n" or die $!;
 
+setstatus "FAILED writing tape ID";
+# First write the tape ID to this tape.
 open T, ">TAPEID" or die $!;
-print T "$tapeid\n$tapedesc\n" or die $!;
+print T "$tapeid\n" or die $!;
 close T or die $!;
 
 system "tar -b$blocksize -vvcf TAPEID.tar TAPEID"; $? and die $?;
@@ -105,6 +131,17 @@ sub closepipes () {
     close(DUMPOW); close(TEEOW); close(BUFOW); close(FINDOW);
 }
 
+# work out a find option string that will exclude the required files    
+# Note that dump pays no attention to exclude options.
+$exclopt = '';
+foreach $exc (@excldir) {
+    $exclopt .= "-regex $exc -prune -o ";
+}
+foreach $exc (@excl) {
+    $exclopt .= "-regex $exc -o ";
+}
+
+# For each filesystem to be put on this tape:
 for $tf (@fsys) {
     printdate();
     pipe(FINDOR,FINDOW) or die $!;
@@ -112,14 +149,29 @@ for $tf (@fsys) {
     pipe(TEEOR,TEEOW) or die $!;
     pipe(BUFOR,BUFOW) or die $!;
     parsefsys();
+    
+    # We can back up via dump or cpio or zafio
     if ($tm eq 'dump') {
        $dumpcmd= "dump 0bfu $softblocksizekb - $atf";
        $dumpin= '</dev/null';
-    } else {
+    } elsif ($tm eq 'cpio') {
        startprocess '</dev/null','>&FINDOW',$rstr."find $atf -xdev -noleaf -print0";
        $dumpcmd= "cpio -Hustar -o0C$softblocksizebytes";
        $dumpin= '<&FINDOR';
+    } elsif ($tm eq 'zafio') {
+        # compress-each-file-then-archive using afio
+        startprocess '</dev/null','>&FINDOW',$rstr."find $atf -xdev -noleaf $exclopt -print";
+        # don't use verbose flag as this generates 2MB report emails :->
+        $dumpcmd = "afio -b $softblocksizebytes -Zo -";
+        $dumpin = '<&FINDOR';
+    } else {
+       die "unknown method $tm for $prefix:$atf\n";
     }
+    # This is a funky way of doing a pipeline which pays attention
+    # to the exit status of all the commands in the pipeline.
+    # It is roughly equivalent to:
+    #    md5sum <p >>this-md5sums
+    #    dump <$dumpin | tee p | writebuffer | dd >/dev/null
     startprocess '<p','>>this-md5sums','md5sum';
     startprocess $dumpin,'>&DUMPOW',$rstr.$dumpcmd;
     startprocess '<&DUMPOR','>&TEEOW','tee p';
@@ -130,17 +182,21 @@ for $tf (@fsys) {
     endprocesses();
 }
 
+# The backup should now be complete; verify it
+
 setstatus "FAILED during check";
 
+# Rewind the tape and skip the TAPEID record
 system "mt -f $tape rewind"; $? and die $?;
 system "mt -f $ntape fsf 1"; $? and die $?;
 
+# Check the md5sums match for each filesystem on the tape
 open S,"this-md5sums" or die $!;
 for $tf (@fsys) {
     printdate();
     chomp($orgsum= <S>);
     $orgsum =~ m/^[0-9a-fA-F]{32}$/i or die "orgsum \`$orgsum' ?";
-    chomp($csum= `readbuffer <$ntape | md5sum`);
+    chomp($csum= `dd if=$ntape ibs=$blocksizebytes | readbuffer | md5sum`);
     $orgsum eq $csum or die "MISMATCH $tf $csum $orgsum\n";
     print "checksum ok $csum\t$tf\n" or die $!;
     print LOG "checksum ok $csum\t$tf\n" or die $!;
@@ -150,15 +206,21 @@ system "mt -f $tape rewind"; $? and die $?;
 
 setstatus "FAILED during cleanup";
 
+# Write to some status files to indicate what the backup system
+# ought to do when next invoked.
+# reset incremental backup count to 1.
 open IAN,">increm-advance.new" or die $!;
 print IAN "1\n" or die $!;
 close IAN or die $!;
 
+# Next full backup is whatever the next link in the tape description
+# file says it ought to be.
 open TN,">next-full.new" or die $!;
 print TN "$next\n" or die $!;
 close TN or die $!;
 
 unlink 'last-tape','next-full';
+# We are the last tape to have been backed up
 rename 'TAPEID','last-tape' or die $!;
 rename 'this-md5sums',"md5sums.$fsys" or die $!;
 rename 'log',"log.$fsys" or die $!;
index 1d2aaa7..63d56d4 100755 (executable)
@@ -1,5 +1,11 @@
 #!/usr/bin/perl
 
+# Do an incremental backup. We are invoked by full if the tape 
+# description file says that it is for an incremental backup.
+# We expect two commandline argument which is the ID string
+# of the tape to use, and the description (which includes ID
+# and function).
+
 BEGIN {
     $etc= '/etc/backup';
     require "$etc/settings.pl";
@@ -13,21 +19,31 @@ $|=1;
 
 print "Running incremental onto $tapedesc ...\n" or die $!;
 
+# Just check that we weren't passed a bogus ID (the tape description
+# file for incrementals is just 'incremental\nend\n')
 open T,"$etc/tape.$tapeid" or die "Tape $tapeid not found: $!\n";
 close T;
 
+# This is only used for the 'next FULL backup is X' message at the end.
 open NF,"next-full" or die $!;
 chomp($next= <NF>);
 close NF or die $!;
 
 setstatus "FAILED during incremental";
 
+# Read the number of the incremental involved
+# (ie, (how many files are already on the tape) - 1)
 open A,"increm-advance" or die $!;
 chomp($advance= <A>);
 close A or die $!;
 
+# better be a decimal number
 $advance =~ m/^\d+$/ or die "$advance ?";
 
+# Rewind the tape and if we are the first incremental on the tape then
+# write the TAPEID record, otherwise skip forward to the correct point.
+# (full will already have checked that this is the right tape before
+# it invoked us, so no need to read the existing TAPEID record first.)
 system "mt -f $ntape rewind"; $? and die $?;
 if ($advance == 1) {
     open TI,">TAPEID" or die $!;
@@ -40,6 +56,7 @@ if ($advance == 1) {
     system "mt -f $ntape fsf $advance"; $? and die $?;
 }
 
+# Get a list of all filesystems
 readfsys('all');
 openlog();
 
@@ -51,6 +68,7 @@ sub closepipes () {
 setstatus "PROBLEMS during incremental dump";
 
 for $tf (@fsys) {
+
     pipe(DUMPOR,DUMPOW) or die $!;
     pipe(BUFOR,BUFOW) or die $!;
     parsefsys();
@@ -59,15 +77,21 @@ for $tf (@fsys) {
        print LOG "Not dumping $atf ($prefix) - not \`dump'.\n" or die $!;
        next;
     }
+    # Same trick as full uses to do a pipeline whilst keeping track
+    # of all exit statuses:
+    #   dump </dev/null | writebuffer | dd >/dev/null
     startprocess '</dev/null','>&DUMPOW',$rstr."dump 1bfu $softblocksizekb - $atf";
     startprocess '<&DUMPOR','>&BUFOW','writebuffer';
     startprocess '<&BUFOR','>/dev/null'
        ,"dd ibs=$softblocksizebytes obs=$blocksizebytes of=$ntape";
     closepipes();
     endprocesses();
+    # advance is a file counter, so it needs to be updated for each 
+    # dump we do to tape.
     $advance++;
 }
 
+# Rewind the tape, and increment the counter of incremental backups.
 system "mt -f $tape rewind"; $? and die $?;
 open IAN,">increm-advance.new" or die $!;
 print IAN "$advance\n" or die $!;
diff --git a/backup/iwjbackup.txt b/backup/iwjbackup.txt
new file mode 100644 (file)
index 0000000..1424a3a
--- /dev/null
@@ -0,0 +1,145 @@
+This is a quick summary of IWJ's backup scripts and my config files:
+it's a bit patchy and might have the odd ommission. The canonical
+source is the sources, as always :->
+
+
+WARNING - this file is out of date !
+
+
+The three tarfiles in this directory should go in the following 
+places (the paths can probably be configured/hacked, but this is
+where they are on my system and on chiark):
+
+etc.tgz : /etc/backup/
+lib.tgz : /usr/local/lib/backup/
+var.tgz : /var/local/backup/
+
+NOTE: these versions are not those used on chiark; they
+are somewhat modified by me (couple of extra features and
+lots of comments -- all errors in those are mine.)
+
+NB: you'll probably need to delete some of the files from
+var.tgz (in fact, I think you probably don't want any of
+them except maybe last-tape (which you want to change anyway).
+You'll also need to recompile readbuffer and writebuffer unless
+you're using SPARClinux :->
+
+Contents of /etc/backup/:
+warnings.*  : files defining how many warnings you get as the
+system is brought down to do backups. The defaults are fine.
+settings.pl : generic config file: in particular, the name of 
+the tape device is set here.
+tape.*  : each tape you're going to use in the backup cycle
+has a name and a config file. Here the tapes are named 'a'-'e',
+although longer names should be OK. You need at least two 
+tapes defined as the system won't write a backup on the same
+tape it wrote the last one to.
+
+Syntax of the tape.* files:
+filesystems X
+next N
+end
+
+where N is the next tape in the sequence (which should 
+be circular; I have a->b->c->d->e->a...) and X is a 
+filesystem-name (list of filesystems might work?).
+
+Each defined filesystem has a name and a config file
+fsys.<name>. These files define what is backed up and how.
+The filesystem 'all' must exist; it's used for incremental
+backups (and it must exist even if you don't do incrementals).
+I don't have any other filesystems defined as everything fits
+on one tape.
+
+Syntax of these files:
+Empty lines and lines starting '#' are comments and ignored.
+Lines starting 'excludedir' given regexps of things to exclude
+(temp dirs, Netscape's cache, etc). 
+Lines starting 'prefix' give a command prefix necessary to
+run things on a remote machine:
+prefix <prefix-name> <command-part>
+Other lines should be of the form
+<directory name>   <backup-type>
+for local backups, or 
+<directory name>   <backup-type>   <prefix-name>
+for remote backups.
+The file must end with the word 'end' on a line of its own.
+
+Valid values for <backup-type> are 'cpio' (uses cpio to produce
+tar-format backups), 'dump' (uses dump to dump entire filesystems;
+<directory name> should be a mount-point for this), and [if you
+use my version of the scripts] 'zafio' (uses afio to compress
+each file as it is backed up). Only 'dump' type backups permit
+incremental backups.
+
+Finally, expected-diffs is a config file to indicate which 
+filesystems should *not* be backed up. The scripts do a config
+check which involves checking that:
+ * all filesystems to be backed up are present
+ * all filesystems that are present are backed up
+expected-diffs allows you to make exceptions to this; backing 
+up your CDROM drive is a bit pointless, frex.
+The format here is:
+<prefixchar><mountpoint>
+
+where <prefixchar> is ?, ! or nothing, and 
+<mountpoint> is <prefix>:<mountpoint> for a remote fs or
+<mountpoint> for a local one
+(examples: "mnementh:/cdrom", "/cdrom").
+If <prefixchar> is nothing, the scripts will complain if the fs
+is mounted. If it is !, they will complain if it is not mounted.
+If ? they won't complain either way (useful for devices that are
+not always mounted, like /cdrom). '?' is an enhancement only 
+present in my version of the scripts.
+
+Useful scripts: (all in /usr/local/lib/backup)
+checkallused: this only does a check of the configuration files.
+It should give a cryptic summary of the configuration and print
+'configuration ok'. If not, fix your config files :->
+
+loaded: this tells the scripts that a currently unlabelled tape
+should be treated as tape X: eg:
+loaded b
+will cause it to treat it as tape 'b'. [NB: this won't override
+the TAPEID label written on the tape; it's just for use with
+previously unused tapes.]
+
+driver : this is the script to actually run to do a backup.
+If run from the command line, give it the argument 'test'
+[otherwise it will attempt to run bringup to change runlevel,
+on the assumption that it was run from inittab (see below)].
+You'll need to edit this script to send the status report email
+to somewhere right for your system.
+
+takedown : Run this if you want to run a reduced level of system
+services during backups. Usage:
+takedown <freq>
+where <freq> can be 'now', 'soon' or nothing depending on number
+of warning messages desired. [configured via warnings.* files.]
+
+To use this you'll need to configure init:
+ * set up runlevel 5 to provide the level of services you want
+   (by tweaking the symlinks in /etc/rc5.d or equivalent)
+ * Add the following to /etc/inittab (tweak paths and VC number
+   if desired):
+
+# Runlevel 5 is set up to run a reduced level of services during
+# backups. (currently this means: no squid, no webserver, no newsserver)
+# We also run the backup script automatically on entering runlevel 5:
+# (I/O goes to VC 7, which is also the X server, but never mind -- we
+# very seldom run X anyway :->)
+dm:5:once:/usr/local/lib/backup/driver </dev/tty7 >/dev/tty7 2>&1
+
+ * takedown can be run from the command line or via cron.
+
+whatsthis: a simple script I hacked together to display the
+TAPEID of the current tape and optionally list its contents.
+Usage:
+whatsthis [--list [n]]
+
+WARNING: it's currently hardwired to assume 'cpio' type backups
+when listing; it could be trivially hardwired to assume 'zafio' 
+or with slightly more effort it could be done properly :->
+
+That's all I can think of for now -- comments and 
+questions to Peter Maydell <pmaydell@chiark.greenend.org.uk>
index c0078a0..b5ab670 100755 (executable)
Binary files a/backup/readbuffer and b/backup/readbuffer differ
index 4cd31af..b733fd6 100644 (file)
@@ -1,4 +1,23 @@
-/**/
+/*
+ * readbuffer.c
+ *
+ * Copyright (C) 1997,1998 Ian Jackson <ian@chiark.greenend.org.uk>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
 
 #include <sys/time.h>
 #include <sys/types.h>
@@ -7,7 +26,6 @@
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
-#include <sys/mman.h>
 
 #define BUFFER 16*1024*1024
 #define WAITEMPTY ((BUFFER*1)/4)
@@ -31,11 +49,13 @@ int main(int argc, const char *const *argv) {
 
   used=0; wp=rp=buf; reading=1; seeneof=0;
   nonblock(0); nonblock(1);
+
   if (argv[1] && !strcmp(argv[1],"--mlock")) {
     if (mlock(buf,sizeof(buf))) { perror("mlock"); exit(1); }
     argv++; argc--;
   }
   if (argv[1]) { fputs("usage: readbuffer [--mlock]\n",stderr); exit(1); }
+
   while (!seeneof || used) {
     FD_ZERO(&readfds);
     if (reading) {
index 5e9c5d5..a550206 100644 (file)
@@ -1,8 +1,14 @@
 #
 chdir '/var/local/backup' or die $!;
 push(@INC,'/usr/local/lib/backup');
-$ENV{'PATH'}= '/usr/local/lib/backup:/usr/local/bin:'.$ENV{'PATH'};
 $ENV{'PATH'} =~ s,^/usr/local/lib/backup:/usr/local/bin:,,;
+$ENV{'PATH'}= '/usr/local/lib/backup:/usr/local/bin:'.$ENV{'PATH'};
+
+# This sets both blocksizes to 512b. Note that both must be the
+# same if using the zftape floppy tape driver, since that requires
+# blocks to be the right size, but dd with the obs=10k option
+# doesn't pad the final block to the blocksize...
+
 $blocksize= 1;
 $blocksizebytes= 512*$blocksize;
 $softblocksizekb= 1;
index 158347b..e41c783 100755 (executable)
@@ -1,6 +1,18 @@
 #!/bin/sh
 #
 # Take the system down for backups and then bring it back up.
+# Expects a single (possibly empty) argument X which is used to select
+# a file /etc/backup/warnings.X. This file will contain lines like:
+# T 300 "in 10 minutes"
+# T 240 "in 5 minutes"
+# T 45 "in 1 minute"
+# T 15 "in 15 seconds"
+# configuring the frequency of warning messages. If you call the 
+# files 'warnings.soon', 'warnings.now' and 'warnings.' then
+# you can invoke this as:
+#   takedown                     lots of warnings
+#   takedown soon                not so many warnings
+#   takedown now                 no warning at all
 
 set -e
 cd /etc/backup
@@ -30,4 +42,7 @@ END
 ) &
 sleep 1
 
+# We assume that runlevel 5 is set up suitably for doing backups
+# (ie non-essential services turned off in an effort to get the
+# tape to stream.)
 telinit 5
diff --git a/backup/whatsthis b/backup/whatsthis
new file mode 100755 (executable)
index 0000000..00d5dff
--- /dev/null
@@ -0,0 +1,122 @@
+#!/usr/bin/perl
+
+# whatsthis : just read an ID off the tape and display it to the user.
+# Peter Maydell <pmaydell@chiark.greenend.org.uk>
+# First rough hack; mostly just code nabbed from full. 
+# --list assumes the dump type was 'zafio', which is a bit bogus.
+
+# whatsthis   : no args => just print tapeid
+# whatsthis --list [n] : print tapeid then list archive n (if n omitted,
+# 0 is assumed.) Note that archives are numbered from zero!
+
+sub rewind();
+sub stopandsay(@);
+
+$etc='/etc/backup';
+require "$etc/settings.pl";
+require 'backuplib.pl';
+
+$| = 1;
+
+# This isn't intended to be run automatically, so don't bother 
+# with setting status.
+
+# If we are run with the argument --list then list the backup to 
+# stdout. Otherwise just print the tape ID.
+$listing = 0;  # default : don't list
+$listing = 1 if ($ARGV[0] eq '--list');
+$listarchive = 0;
+$listarchive = $ARGV[1] if defined $ARGV[1];
+
+print "Trying to read tape ID from currently inserted tape...\n";
+
+unlink 'TAPEID';
+system "mt -f $ntape setblk $blocksizebytes"; $? and die $?;
+system "dd if=$ntape bs=${blocksize}b count=10 | tar -b$blocksize -vvxf - TAPEID";
+$? and stopandsay "Failed to read TAPEID.\n";
+
+if (!open(T, "TAPEID"))
+{
+  stopandsay "Tape has no ID label.\n";
+}
+
+# OK, there's a TAPEID file, read the ID and check for sanity.
+chomp($tapeid= <T>);
+if ($tapeid =~ m/[^0-9a-zA-Z]/)
+{
+   stopandsay "Tape has a bad (non-alphanumeric) TAPEID ($&).\n";
+}
+elsif (! $tapeid =~ m/[0-9a-zA-Z]/)
+{
+   stopandsay "Empty TAPEID.\n";
+}
+
+print "TAPEID is $tapeid.\n";
+close T;
+
+# If we aren't listing the tape contents, we can just rewind the tape
+# and exit.
+if (!$listing)
+{
+   rewind();
+   exit;
+}
+
+# List the contents of archive $listarchive on the tape.
+# We are already at the right place for the first archive
+# (after the TAPEID). 
+# For any other archive, we skip forwards to the start of that archive.
+if ($listarchive)
+{
+   system "mt -f $ntape fsf $listarchive";
+   $? and stopandsay "Couldn't skip forward to archive $listarchive.";
+}
+
+# Use file to figure out what the archive type is
+# This doesn't seem to work too well, so I'm disabling it -- PMM 
+#$ftype = `dd if=$ntape ibs=$blocksizebytes | file -`;
+#$? and stopandsay "couldn't determine file type: $?";
+$ftype = 'POSIX tar';
+
+# What we want to do here is roughly:
+# dd if=$ntape ibs=$blocksizebytes | readbuffer | afio ???
+#
+# where the afio options are such as to list an archive created with
+# afio -b $softblocksizebytes -Zvo
+
+if ($ftype =~ /POSIX tar/) {
+   # POSIX tar archive; we read it with cpio
+   $reader = "cpio -it -C$softblocksizebytes -Hustar";
+} elsif ($ftype =~ /ASCII cpio/) {
+   $reader = "afio -b $softblocksizebytes -Zt -";
+} elsif ($ftype =~ /dump file/) {
+   stopandsay "sorry: can't list dump files yet";
+} else {
+   stopandsay "listing failed: unknown archive type";
+}
+
+# Now back up so we can read the file again properly
+#system "mt -f $ntape bsf 1"; $? and stopandsay "couldn't backspace tape: $?";
+
+system "dd if=$ntape ibs=$blocksizebytes | /usr/local/lib/backup/readbuffer | $reader";
+$? and stopandsay "listing failed: $?";
+
+# All's well, stop here.
+print "Listing complete.\n";
+rewind();
+exit;
+
+
+# Rewind the tape.
+sub rewind ()
+{
+   system "mt -f $tape rewind"; $? and die $?;
+}
+
+# Print the given message, rewind the tape and exit failure.
+sub stopandsay(@)
+{
+   print @_;
+   rewind();
+   exit(1);
+}
index 533cdb4..67db196 100755 (executable)
Binary files a/backup/writebuffer and b/backup/writebuffer differ
index c4fa9e7..02254dc 100644 (file)
@@ -1,4 +1,23 @@
-/**/
+/*
+ * writebuffer.c
+ *
+ * Copyright (C) 1997,1998 Ian Jackson <ian@chiark.greenend.org.uk>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
 
 #include <sys/time.h>
 #include <sys/types.h>
@@ -19,9 +38,14 @@ static void nonblock(int fd) {
   if (fcntl(fd,F_SETFL,r) == -1) { perror("fcntl setfl"); exit(1); }
 }
 
-int main(void) {
+int main(int argc, const char *const *argv) {
   static unsigned char buf[BUFFER];
   
+  if (argv[1]) {
+    fputs("readbuffer: no arguments allowed\n", stderr);
+    exit(-1);
+  }
+
   unsigned char *wp, *rp;
   int used,r,writing,seeneof;
   fd_set readfds;