Linux-Misc Digest #764, Volume #20 Thu, 24 Jun 99 01:13:09 EDT
Contents:
Free dump scripts (Scott Simpson)
Re: first/second/third world (Donovan Rebbechi)
----------------------------------------------------------------------------
From: Scott Simpson <[EMAIL PROTECTED]>
Subject: Free dump scripts
Date: Wed, 23 Jun 1999 20:43:19 -0700
This is a multi-part message in MIME format.
==============A8C7810554CD835BB2FAD7AF
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Here are some free dump scripts I wrote. They're short, so I'm posting
them here. These are useful if
- You have a SCSI tape drive and
- You want to put all your partitions on a single tape and have that
tape updated every day.
To install, unpack the shar and put "init_tape", "get_tape_set",
"dump_files" and "restore_files" in /opt/local/bin. Put "helpers.pl" in
/opt/local/dump/lib. Also, create the directory /opt/local/dump/log. You
can edit these path names as you wish.
One other thing. the mt(1) command on many Linux's are broken. I'm
running version 0.5b. Version 0.5 is broken. You can see which version
you have by typing "mt -v".
[EMAIL PROTECTED]
==============A8C7810554CD835BB2FAD7AF
Content-Type: application/x-shar; name="dump.shar"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="dump.shar"
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 8641 -rwxr-xr-x dump_files
# 608 -rwxr-xr-x get_tape_set
# 2143 -rw-r--r-- helpers.pl
# 912 -rwxr-xr-x init_tape
# 6595 -rwxr-xr-x restore_files
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
if test "$gettext_dir" = FAILED && test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
set `$dir/gettext --version 2>&1`
if test "$3" = GNU
then
gettext_dir=$dir
fi
fi
if test "$locale_dir" = FAILED && test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
echo=echo
else
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
shar_touch=touch
else
shar_touch=:
echo
$echo 'WARNING: not restoring timestamps. Consider getting and'
$echo "installing GNU \`touch', distributed in GNU File Utilities..."
echo
fi
rm -f 1231235999 $$.touch
#
if mkdir _sh06099; then
$echo 'x -' 'creating lock directory'
else
$echo 'failed to create lock directory'
exit 1
fi
# ============= dump_files ==============
if test -f 'dump_files' && test "$first_param" != -c; then
$echo 'x -' SKIPPING 'dump_files' '(file already exists)'
else
$echo 'x -' extracting 'dump_files' '(text)'
sed 's/^X//' << 'SHAR_EOF' > 'dump_files' &&
#! /opt/perl/bin/perl
#### Dump files to tape.
####
#### $Id: dump_files,v 1.1.1.1 1999/06/24 03:27:25 scott Exp $
#### Scott Simpson, [EMAIL PROTECTED]
####
#### Usage: dump_files [--device device] [--set set_name] [--full set_name]
#### [--level level] [filesystem]...
####
#### --device device Use "device" instead of /dev/tape.
#### --set set Make sure the set name of the tape is
#### "set_name". If not, abort.
#### --full set Reset tape and do a full backup of all
#### the filesystems on the system. Write the
#### tape as set "set_name". This is not the
#### same as doing a --level 0 dump because
#### doing a --level 0 dump won't figure out
#### which filesystems to dump and won't reset
#### the tape. If you give this option, you
#### cannot give the --level option. You can
#### give filesystems though in which case only
#### those filesystems will be dumped after
#### a tape reset (admittedly, not very useful).
#### This option resets all the logs for the tape.
#### Usually you manually do a --full dump
#### at the beginning of the month and simply
#### run this script from cron every day on the
#### the other days.
#### --level level Do a dump of all the filesystems (or the
#### filesystems given) at "level". The tape
#### is not reset. This option is mutually
#### exclusive with the --full option.
####
#### If --full and --level are not given, then dump(8) is queried to see
#### which filesystems to dump. The level to dump each filesystem
#### is currently determined by the day of the week of the dump, but
#### it can be changed to be Tower of Hanoi, etc. Right now, a level 2
#### dump is done on Sunday, a level 3 on Monday, etc. This continues
#### throughout the week. On Sunday, a level 2 is done again. If no
#### filesystems are given without --full and --level, then all the
#### filesystems that dump(8) says need dumping are dumped.
#### Every Sunday, the tape is retensioned after dumping. It is good to
#### retension a tape every once in a while.
####
#### The files that are written by this script are:
####
#### <set>.txt dumps done on tape. Format is
####
#### <seq#> <level> <filesystem> <start_block> success/failure <date/time>
####
#### <seq#>_<set>.txt file list for <set> and <seq#>
####
#### <seq#>_<set>_log.txt log msgs for <set> and <seq#>
X
require "/opt/local/dump/lib/helpers.pl";
use Getopt::Long;
X
$result = GetOptions("device=s" => \$device,
X "set=s" => \$check_set,
X "full=s" => \$new_set,
X "level=i" => \$level_arg);
if ($result == 0) {
X die "Usage: $0 [--device device] [--set_name set_name] " .
X "[--full set_name] [--level level] [filesystem]\n";
}
die "Invalid level number $level_arg\n" if (defined $level_arg &&
X ($level_arg < 0 || 9 < $level_arg));
die "Invalid set name '$check_set'\n" if (defined $check_set &&
X !&valid_set_name($check_set));
die "Invalid set name '$new_set'\n" if (defined $new_set &&
X !&valid_set_name($new_set));
die "Cannot give both --full and --level\n"
X if defined $new_set && defined $level_arg;
X
$device = "/dev/tape" if ! defined $device;
X
## This stores the starting block locations on the tape of the
## filesystems we are dumping.
@start_blocks = ();
X
## The number of previous dumps on the tape before we started.
$prev_dump_num = 0;
X
### Dumps a filesystem. Takes: device, set name, relative dump number,
### filesystem to dump, level.
###
### Algorithm:
### Note what block number we are at on the tape
### Add block # to @start_blocks at end
### Dump tape redirecting log output to log file.
### Add entry to <set> file.
sub dump_filesystem {
X local($device,$set,$rel_num,$fs,$level) = @_;
X local($block_num);
X
X $block_num = &tell_tape($device);
X
X push(@start_blocks,$block_num);
X
X $result = 0xffff & system "sh", "-c",
X "dump ${level}usf 1000000 $device $fs > $log_dir/${rel_num}_${set}_log.txt 2>&1";
X if ($result == 0) {
X $result = "success";
X } else {
X $result = "failure";
X }
X
X open(F, ">>$log_dir/$set.txt") ||
X die "Cannot write to $log_dir/$set.txt.\n";
X $time = localtime;
X printf F "$rel_num $level $fs $block_num $result $time\n";
X close(F);
}
X
### List a previously dumped filesystem on the tape. Take arguments:
### device, set, relative dump number, block location of dump
###
### Algorithm:
### Seek to block number given.
### List dump to file
sub list_filesystem {
X local($device,$set,$rel_num,$block_num) = @_;
X
X &seek_tape($block_num,$device);
X
X system "sh", "-c",
X "restore tf $device > $log_dir/${rel_num}_${set}.txt 2>&1";
}
X
### Returns the filesystems available for dumping from /etc/fstab.
sub query_fstab_filesystems {
X local($dev,$fs,$type,$opts,$dump,@filesys);
X
X @filesys = ();
X open(FSTAB, "</etc/fstab") || die "Cannot open /etc/fstab.\n";
X while (<FSTAB>) {
X chop;
X ($dev,$fs,$type,$opts,$dump) = split(' ');
X if ($dump != 0 &&
X ($type eq "ext2" ||
X $type eq "minix" ||
X $type eq "ext" ||
X $type eq "xiafs" ||
X $type eq "msdos" ||
X $type eq "hpfs")) {
X push @filesys, $fs;
X }
X }
X close(FSTAB);
X return @filesys;
}
X
### Query the dump(8) command to see which filesystems need to be dumped.
sub query_dump_filesystems {
X local($filesystems);
X
X open(DUMP, "dump w|") || die "Cannot run 'dump w' command.\n";
X <DUMP>; # Skip header.
X @filesystems = ();
X while (<DUMP>) {
X chop;
X $_ = substr($_,13);
X s/^[ \t]+//;
X s/\) Last.+$//;
X push @filesystems, $_;
X }
X close(DUMP);
X return @filesystems;
}
X
### Algorithm:
### Rewind tape.
### if --set given {
### Check if tape name is the name given. If not abort.
### Rewind tape.
### }
### if --full given {
### set $prev_dump_num to 0
### Write tape set on tape and set $set.
### } else {
### Get dump set off of the tape and set $set.
### Determine $prev_dump_num from tape set file.
### }
### # Tape is positioned after tape set name
### if --full given {
### Trash all set log files with name $new_set.
### Create new A log file as empty.
### $level=0
### } else if --level given {
### $level=<level given on command line>
### Seek to end of tape
### } else {
### $level=<level from day of the week>
### Seek to end of tape
### }
### if filesystems given on command line {
### set @filesystems to file systems on command line.
### } else {
### if --full or --level given {
### set @filesystems to file systems in fstab.
### } else {
### Query dump(8) to see which filesystems to dump
### }
### }
### for (i = 1; i <= length of @filesystem; i++) {
### dump_filesystem $set $prev_dump_num+i $filesystem[i] $level
### }
### for (i = 1; i <= length of @filesystems; i++) {
### list_filesystem $set $prev_dump_num+i $start_blocks[i]
### }
### Rewind tape.
### if --full and --level isn't given and today is Sunday {
### retension tape
### rewind tape
### }
&rewind_tape($device);
X
if (defined $check_set) {
X die "Tape name is not $check_set\n"
X if &get_set_name($device) ne $check_set;
X &rewind_tape($device);
}
X
if (defined $new_set) {
X $set = $new_set;
X $prev_dump_num = 0;
X
X open(TAPE, ">$device") || die "Cannot open tape for writing.\n";
X print TAPE $set;
X close(TAPE);
} else {
X $set = &get_set_name($device);
X
X open(F, "wc -l $log_dir/$set.txt |") || die "Cannot run wc(1) command.\n";
X ($prev_dump_num) = split(' ',<F>);
X close(F);
}
X
if (defined $new_set) {
X opendir DIR, $log_dir || die "Cannot open $log_dir\n";
X @remove_files = eval "grep /^[0-9]+_$new_set(_log)?.txt\$/, readdir DIR";
X closedir DIR;
X grep unlink($log_dir."/".$_), @remove_files;
X
X open(LOG, ">$log_dir/$new_set.txt") ||
X die "Cannot open $log_dir/$new_set.txt.\n";
X close(LOG);
X
X $level = 0;
} elsif (defined $level_arg) {
X $level = $level_arg;
X
X &end_of_tape($device);
} else {
X $level = (2,3,4,5,6,7,8)[(localtime)[6]];
X
X &end_of_tape($device);
}
X
if ($#ARGV != -1) {
X @file_systems = @ARGV;
} else {
X if (defined $new_set || defined $level_arg) {
X @file_systems = &query_fstab_filesystems;
X } else {
X @file_systems = &query_dump_filesystems;
X }
}
X
for ($i = 1; $i < ($#file_systems+2); $i++) {
X &dump_filesystem($device,$set,$prev_dump_num+$i,$file_systems[$i-1],
X $level);
}
for ($i = 1; $i < ($#file_systems+2); $i++) {
X &list_filesystem($device,$set,$prev_dump_num+$i,$start_blocks[$i-1]);
}
X
&rewind_tape($device);
X
$thisday = (Sun,Mon,Tue,Wed,Thu,Fri,Sat)[(localtime)[6]];
if (! defined $new_set && !defined $level_arg && $thisday eq "Sun") {
X &retension($device);
X &rewind_tape($device);
}
X
SHAR_EOF
$shar_touch -am 0623202799 'dump_files' &&
chmod 0755 'dump_files' ||
$echo 'restore of' 'dump_files' 'failed'
if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
&& ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|| $echo 'dump_files:' 'MD5 check failed'
561c0727305df552f967655d8967e4ce dump_files
SHAR_EOF
else
shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'dump_files'`"
test 8641 -eq "$shar_count" ||
$echo 'dump_files:' 'original size' '8641,' 'current size' "$shar_count!"
fi
fi
# ============= get_tape_set ==============
if test -f 'get_tape_set' && test "$first_param" != -c; then
$echo 'x -' SKIPPING 'get_tape_set' '(file already exists)'
else
$echo 'x -' extracting 'get_tape_set' '(text)'
sed 's/^X//' << 'SHAR_EOF' > 'get_tape_set' &&
#! /usr/bin/perl
#### Get the set of the tape currently in the drive.
####
#### $Id: get_tape_set,v 1.1.1.1 1999/06/24 03:27:25 scott Exp $
####
#### Usage: get_tape_set [--device device]
X
require "/opt/local/dump/lib/helpers.pl";
use Getopt::Long;
X
$result = GetOptions("device=s" => \$device);
if ($result == 0 || $#ARGV != -1) {
X die "Usage: $0 [--device]\n";
}
X
$set = $ARGV[0];
X
$device = "/dev/tape" if ! defined $device;
X
&rewind_tape($device);
X
$set = &get_set_name($device);
X
die "Set name invalid or tape not initialized\n" if ! &valid_set_name($set);
X
print $set, "\n";
X
&rewind_tape($device);
SHAR_EOF
$shar_touch -am 0623202799 'get_tape_set' &&
chmod 0755 'get_tape_set' ||
$echo 'restore of' 'get_tape_set' 'failed'
if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
&& ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|| $echo 'get_tape_set:' 'MD5 check failed'
32a26c37153cf76c7967f3911f5ed473 get_tape_set
SHAR_EOF
else
shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'get_tape_set'`"
test 608 -eq "$shar_count" ||
$echo 'get_tape_set:' 'original size' '608,' 'current size' "$shar_count!"
fi
fi
# ============= helpers.pl ==============
if test -f 'helpers.pl' && test "$first_param" != -c; then
$echo 'x -' SKIPPING 'helpers.pl' '(file already exists)'
else
$echo 'x -' extracting 'helpers.pl' '(text)'
sed 's/^X//' << 'SHAR_EOF' > 'helpers.pl' &&
# Routines used by the tape dumping programs.
X
# $Id: helpers.pl,v 1.1.1.1 1999/06/24 03:27:25 scott Exp $
X
sub rewind_tape {
X local($tape) = @_;
X local($rc);
X
X if ($tape eq "") {
X $rc = 0xffff & system "mt", "rewind";
X } else {
X $rc = 0xffff & system "mt", "-t", $tape, "rewind";
X }
X die "Cannot rewind $tape\n" if $rc;
}
X
sub retension {
X local($tape) = @_;
X local($rc);
X
X if ($tape eq "") {
X $rc = 0xffff & system "mt", "retension";
X } else {
X $rc = 0xffff & system "mt", "-t", $tape, "retension";
X }
X die "Cannot retension $tape\n" if $rc;
}
X
sub end_of_tape {
X local($tape) = @_;
X local($rc);
X
X if ($tape eq "") {
X $rc = 0xffff & system "mt", "eod";
X } else {
X $rc = 0xffff & system "mt", "-t", $tape, "eod";
X }
X die "Cannot seek to end of $tape\n" if $rc;
}
X
# Notice device is given last!
sub seek_tape {
X local($position,$tape) = @_;
X local($rc);
X
X if ($tape eq "") {
X $rc = 0xffff & system "mt", "seek", $position;
X } else {
X $rc = 0xffff & system "mt", "-t", $tape, "seek", $position;
X }
X die "Cannot seek on $tape to $position\n" if $rc;
}
X
sub tell_tape {
X local($tape) = @_;
X local($line,$j,$num);
X
X if ($tape eq "") {
X open(T, "mt tell|") || die "Cannot open tape device for 'mt tell'\n";
X } else {
X open(T, "mt -t $tape tell|") ||
X die "Cannot open tape device $tape for 'mt tell'\n";
X }
X $line = <T>;
X close(T);
X
X chomp($line);
X ($j,$j,$num) = split(' ',$line);
X $num =~ s/\.//;
X
X return $num;
}
X
X
### Checks if a tape's set name is valid.
sub valid_set_name {
X local($set) = @_;
X
X return $set =~ /^[a-zA-Z0-9,\/.-]+$/ ? 1 : 0;
}
X
### Returns the tape's set name. Doesn't rewind first.
sub get_set_name {
X local($tape) = @_;
X
X $tape = "/dev/tape" if $tape eq "";
X
X open TAPE, "<$tape" || die "Cannot open $tape for reading set name\n";
X $set = <TAPE>;
X close TAPE;
X
X # Trash any trailing nulls. May have read 512 byte block.
X $set =~ s/\000//g;
X
X return $set;
}
X
### Location of log files.
$log_dir = "/opt/local/dump/log";
X
1;
SHAR_EOF
$shar_touch -am 0623202799 'helpers.pl' &&
chmod 0644 'helpers.pl' ||
$echo 'restore of' 'helpers.pl' 'failed'
if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
&& ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|| $echo 'helpers.pl:' 'MD5 check failed'
7c26d5e808a01f7237be29ba39081b5a helpers.pl
SHAR_EOF
else
shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'helpers.pl'`"
test 2143 -eq "$shar_count" ||
$echo 'helpers.pl:' 'original size' '2143,' 'current size' "$shar_count!"
fi
fi
# ============= init_tape ==============
if test -f 'init_tape' && test "$first_param" != -c; then
$echo 'x -' SKIPPING 'init_tape' '(file already exists)'
else
$echo 'x -' extracting 'init_tape' '(text)'
sed 's/^X//' << 'SHAR_EOF' > 'init_tape' &&
#! /usr/bin/perl
#### Initializes a tape to a new set #.
####
#### $Id: init_tape,v 1.1.1.1 1999/06/24 03:27:25 scott Exp $
####
#### Usage: init_tape [--device device] set_name
X
require "/opt/local/dump/lib/helpers.pl";
use Getopt::Long;
X
$result = GetOptions("device=s" => \$device);
if ($result == 0 || $#ARGV != 0) {
X die "Usage: $0 [--device device] set_name\n";
}
X
$device = "/dev/tape" if ! defined $device;
X
$set = $ARGV[0];
X
&rewind_tape($device);
X
## Write the set name.
open TAPE, ">$device";
# Note: This may write a 512 byte block or bigger, not just the set name.
print TAPE $set;
close TAPE;
X
opendir DIR, $log_dir || die "Cannot open $log_dir\n";
@remove_files = eval "grep /^[0-9]+_$set(_log)?\.txt\$/, readdir DIR";
closedir DIR;
grep unlink($log_dir."/".$_), @remove_files;
X
open(LOG, ">$log_dir/$set.txt") ||
X die "Cannot open $log_dir/$set.txt.\n";
close(LOG);
X
&rewind_tape($device);
SHAR_EOF
$shar_touch -am 0623202799 'init_tape' &&
chmod 0755 'init_tape' ||
$echo 'restore of' 'init_tape' 'failed'
if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
&& ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|| $echo 'init_tape:' 'MD5 check failed'
0a890de29c2f588324cc424851b63003 init_tape
SHAR_EOF
else
shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'init_tape'`"
test 912 -eq "$shar_count" ||
$echo 'init_tape:' 'original size' '912,' 'current size' "$shar_count!"
fi
fi
# ============= restore_files ==============
if test -f 'restore_files' && test "$first_param" != -c; then
$echo 'x -' SKIPPING 'restore_files' '(file already exists)'
else
$echo 'x -' extracting 'restore_files' '(text)'
sed 's/^X//' << 'SHAR_EOF' > 'restore_files' &&
#! /usr/bin/perl
#### Restore files from tape.
####
#### $Id: restore_files,v 1.1.1.1 1999/06/24 03:27:25 scott Exp $
####
#### Usage: restore_files [--device device] [--level level]
#### [--fileset n] [--dir restore_dir] filesystem [file]...
####
#### --device device Use "device" instead of /dev/tape.
#### --level level Restore the given filesystem or files
#### from the filesystem up to the given level.
#### If level 0 is given, then the filesystem/
#### files are restored from the last monthly.
#### If level 9 is given, then this is the same
#### as just restoring to the latest version
#### of the filesystem/files (i.e., it is
#### equivalent to leaving off the --fileset
#### and --level options). When using this flag,
#### the filesystem levels are ordered and the
#### latest dumps for each level are used.
#### For example, for the dump level sequence
#### 0, 5, 9, 3, 9, 3, 9 the restores are:
#### 0, 3 (2nd), 9 (2nd). The others are skipped
#### because they are of a higher level or predate
#### the dump at the same level. If you want
#### to restore these dumps, use the --fileset
#### option.
#### --fileset n Restore only fileset n. The name of this
#### fileset must match the "filesystem" argument.
#### See the set dump log for which filesystems
#### were dumped at what time.
#### --dir restore_dir Restore to the given directory. Normally
#### the current directory is used.
#### --recursive If a directory name is given as a file,
#### then recursively extract the files in the
#### directory. This option has no effect
#### if file names are not given on the command
#### line.
#### --verbose Print out file names as you do the restore.
#### filesystem The filesystem to restore from. Any files
#### given must be in this filesystem or they
#### are not restored. If no files are given,
#### then restore all the files in the filesystem.
####
#### If --level and --fileset are not given, then first a level 0 dump
#### is restored and then successive dumps up to the latest dump are restored.
#### See the --level option for an example of how this works.
#### Note: If filenames are not given and --fileset is not given,
#### then the restore(8) "r" command is used. If filenames are given
#### or we aren't doing a complete restore, then the restore(8) "x"
#### command is used.
X
require "/opt/local/dump/lib/helpers.pl";
use Getopt::Long;
X
$result = GetOptions("device=s" => \$device,
X "level=i" => \$lastlevel,
X "fileset=i" => \$filesetnum,
X "dir=s" => \$restore_dir,
X "recursive" => \$recursive,
X "verbose" => \$verbose);
if ($result == 0 || $#ARGV == -1) {
X die "Usage: $0 [--device device] [--level level] [--fileset n] " .
X "[--dir restore_dir] [--recursive] [--verbose] filesystem [file]...\n";
}
$filesystem = shift;
X
die "Invalid level number $lastlevel\n"
X if (defined $lastlevel && ($lastlevel < 0 || 9 < $lastlevel));
die "Invalid fileset number $filesetnum\n"
X if (defined $filesetnum && $filesetnum <= 0);
die "Cannot give both --level and --fileset\n"
X if (defined $lastlevel && defined $filesetnum);
warn "--recursive ignored when file names not given.\n"
X if (defined $recursive && $#ARGV == -1);
X
$device = "/dev/tape" if ! defined $device;
X
$lastlevel = 9 if ! defined $lastlevel;
$restore_dir = "." if ! defined $restore_dir;
$hflag = ((defined $recursive || $#ARGV == -1) ? "" : "h");
$verbose = (defined $verbose ? "v" : "");
@tape_blocks = (); # Block #s for each dump #.
X
### Restore files from tape at a given set number. Rewinds first and moves
### to the set number. Also prints out what it is doing.
sub restore_files {
X local($device,$num,$fs,$level,$date,$hflag,$verbose,$restore_command,
X @files) = @_;
X
X &seek_tape($tape_blocks[$num], $device);
X
X printf(
X "Restoring level $level dump of $fs on $date (set #$num, %s files).\n",
X $#files == -1 ? "all" : "selected");
X
X print "restore $restore_command$verbose${hflag}yf $device @files\n";
X system "restore", "$restore_command$verbose${hflag}yf", $device,
X @files;
}
X
### Algorithm:
### Rewind tape.
### Get tape set name.
### Read tape set file for dump information.
### Set global variable containing dump #s to tape block #s.
### Change directory to the restore directory.
### if --fileset given {
### Make sure fileset given is within range.
### Make sure filesystem name given matches fileset name in the
### tape set file.
### restore_files(device,file_set_num,filesystem,level,date,hflag,
### verbose,restore_command,files...)
### } else {
### Set $restore_tape_nums to the tape set numbers to restore
### according to the dump order given in the tape set file.
### for each tape set number in $restore_tape_nums {
### restore_files(device,file_set_num,filesystem,level,date,
### hflag,verbose,restore_command,files...)
### }
### Delete "restoresymtable" if it exists.
### }
### Rewind tape.
&rewind_tape($device);
$set = &get_set_name($device);
X
open(F, "<$log_dir/$set.txt") || die "Cannot open $log_dir/$set.txt.\n";
@tape_info = ();
$i = 1;
while (<F>) {
X ($n,$level,$fs,$block,$code,$date) = split(' ',$_,6);
X chomp $date;
X $tape_info[$n-1] = "$fs $level $date";
X $tape_blocks[$i] = $block;
X $i++;
}
close(F);
X
chdir($restore_dir);
X
if (defined $filesetnum) {
X die "File set $filesetnum out of range.\n"
X if ($#tape_info+1 < $filesetnum);
X
X ($fs,$level,$date) = split(' ',$tape_info[$filesetnum-1],3);
X die "Filesystem at archive set #$filesetnum is $fs, not $filesystem.\n"
X if ($filesystem ne $fs);
X
X &restore_files($device,$filesetnum,$filesystem,$level,$date,$hflag,
X $verbose,"x",@ARGV);
} else {
X @list = ();
X # Got through @tape_info and trash all entries after or equal
X # to the current level. Then add current level to list.
X for ($set_num = 1; $set_num <= $#tape_info+1; $set_num++) {
X ($fs,$level) = split(' ',$tape_info[$set_num-1]);
X
X next if ($fs ne $filesystem);
X next if ($lastlevel < $level);
X
X for ($i = 0; $i <= $#list; $i++) {
X ($curlevel) = split(' ',$list[$i]);
X if ($level <= $curlevel) {
X $#list = $i-1;
X break;
X }
X }
X push @list, "$level $set_num";
X }
X
X foreach $rec (@list) {
X ($level,$set_num) = split(' ',$rec);
X ($fs,$level,$date) = split(' ',$tape_info[$set_num-1],3);
X
X $restore_command = ($#ARGV == -1 ? "r" : "x");
X
X &restore_files($device,$set_num,$filesystem,$level,$date,$hflag,
X $verbose,$restore_command,@ARGV);
X }
X unlink "restoresymtable";
}
&rewind_tape($device);
SHAR_EOF
$shar_touch -am 0623202799 'restore_files' &&
chmod 0755 'restore_files' ||
$echo 'restore of' 'restore_files' 'failed'
if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
&& ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|| $echo 'restore_files:' 'MD5 check failed'
bec0d53994f72f5bac28878a604fc3be restore_files
SHAR_EOF
else
shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'restore_files'`"
test 6595 -eq "$shar_count" ||
$echo 'restore_files:' 'original size' '6595,' 'current size' "$shar_count!"
fi
fi
rm -fr _sh06099
exit 0
==============A8C7810554CD835BB2FAD7AF==
------------------------------
From: [EMAIL PROTECTED] (Donovan Rebbechi)
Crossposted-To: comp.os.ms-windows.advocacy,comp.os.linux.advocacy,gnu.misc.discuss
Subject: Re: first/second/third world
Date: 24 Jun 1999 04:41:54 GMT
On Wed, 23 Jun 1999 22:20:22 -0500, Anonymous wrote:
>Oh that was a good argument. And if you ask most any citizen of Iraq,
>they'll tell you the US is populated by satan himself. Yeesh...
He didn't mention Iraq. Besides, people oversees are not considerably
more ignorant than Americans. You really should get out more often.
--
Donovan
------------------------------
** FOR YOUR REFERENCE **
The service address, to which questions about the list itself and requests
to be added to or deleted from it should be directed, is:
Internet: [EMAIL PROTECTED]
You can send mail to the entire list (and comp.os.linux.misc) via:
Internet: [EMAIL PROTECTED]
Linux may be obtained via one of these FTP sites:
ftp.funet.fi pub/Linux
tsx-11.mit.edu pub/linux
sunsite.unc.edu pub/Linux
End of Linux-Misc Digest
******************************