LAI has asked for the wisdom of the Perl Monks concerning the following question:

I've got a script that runs on several servers, FTPing tarballs to one central one. The central server then tars up all the stuff in the FTP dropbox and puts it on tape.

Thing is, tar and mt don't report errors as they ought. I tried letting the script run without a tape in the drive, and the script ran fine. The logs reported success and return codes of 0 all around. So what I want to know is, is there a better way to do what I am trying to that will yield proper error processing? Ideally, I'd like as perlish a solution as possible, but I haven't found anything useful on CPAN. The Mt module is just a wrapper around the mt command, and if mt doesn't return errors...

By the way: I use a bleeding-edge, not-yet-updated-on-CPAN version of Parse::PlainConfig, but there's nothing in there to do with anything. If you want to take a look anyway, here's a copy of what I use. The (trimmed) script in question follows:

#!/usr/bin/perl use warnings; use strict; # OMIT: initialize some useful variables... # Here everything gets called. These subroutines are defined below. _log _begin; $settings = read_config("/etc/backup.conf"); create_archive($settings->{archive}); upload_archive($settings->{FTP}); tape_archive($settings->{tape}); delete_temp_files(); _log _end; # # send the files to tape. We use the rewinding device, because we # don't really care about putting several archives on the same tape. # We also eject the tape because we want a different tape for each # day of the week. sub tape_archive { my $conf = shift or return; # are we configured to tape stuff? my ($rdev, @tapeables) = ($conf->{'rdev'}, @{$conf->{'tapeables'}}); push @tapeables, $tarball if ($settings->{'archive'}); # With the tape out, the following ought to _barf. But it doesn't. undef $!; system("tar --ignore-failed-read -cf $rdev @tapeables") and _barf "couldn't write to tape. Error $? : $! "; # Even if the previous line doesn't _barf, surely this one must, # right? Wrong. undef $!; system("mt -f $rdev offline") and _barf "couldn't eject tape. Error $? : $! "; push @deleteables, @tapeables; } # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Below this point are housekeeping and logging subs, so # # feel free to skip to the bottom # # logging subs sub _begin { chomp (my $now = `date`); return "-----\nstarting backup on $hostname at $now \n"; } sub _log { # OMIT: log stuff to file and return what was logged } sub _barf { my $msg = _log shift() .$/. _end(); _mail( $settings->{mail}, $msg); die $msg; } sub _mail { my $conf = shift or return; # are we configured to mail stuff? use Net::SMTP; # OMIT: mail errors to the admin } sub _end { chomp (my $now = `date`); return "ended at $now \n-----\n"; } # Read in the config file using Parse::PlainConfig sub read_config { use Parse::PlainConfig; # OMIT: read settings from file and return a hashref } sub is_true($) { # used by read_config return defined $_[0] && $_[0] !~ /^(false|no|0)$/; } sub create_archive { # The first step is to create a temporary archive + in /tmp/. # OMIT: we're writing to file. No problem here. } sub dump_into_file { # OMIT: turn the list of sources into an array we can send to tar } sub upload_archive { # OMIT: irrelevant } sub delete_temp_files { # clean up our temp directory. # OMIT: housekeeping code } __END__

LAI

__END__

Replies are listed 'Best First'.
Re: Backup script: how can I force this to report errors?
by robartes (Priest) on Mar 20, 2003 at 17:01 UTC
    I'm not sure whether I'm doing something wrong, or you are doing something wrong, but when I do this:
    perl -e 'system ("tar cf /home/yup/yup.tar .") and die "Oops: $?\n";'
    I get:
    tar: /home/yup/yup.tar: Cannot open: No such file or directory tar: Error is not recoverable: exiting now Oops: 512
    So $? is definitely set, and tar's exit code was 512 >> 8 = 2. Are you sure _barf does not get called?

    As an aside, I assume you predeclare _barf in the omitted initialisation section, as the way the script is written the call to _barf will not work.

    CU
    Robartes-

      Oh, _barf works as expected. If you like I can show you the full code. The difficulty is with (presumably) either mt or with /dev/st0. I'm looking for a perlish way to figure out if there is a tape in the drive.

      If you have access to a machine with a tape drive (no idea if this will only apply to SCSI tapes), make sure there is no tape in the drive and try the following:

      [root@mag /]# mt -f /dev/st0 stat SCSI 2 tape drive: File number=0, block number=0, partition=0. Tape block size 0 bytes. Density code 0x25 (DDS-3). Soft error count since last status=0 General status bits on (41010000): BOT ONLINE IM_REP_EN [root@mag /]# mt -f /dev/st0 load [root@mag /]# mt -f /dev/st0 seek [root@mag /]# mt -f /dev/st0 fsf [root@mag /]# touch testfile ; tar -cvf /dev/st0 testfile testfile [root@mag /]# tar -tf /dev/st0 tar: This does not look like a tar archive tar: Skipping to next header tar: Error exit delayed from previous errors [root@mag /]#

      See, all the seeking, writing, and so on should return errors (or at least warnings) but doesn't.

      LAI

      __END__