Backups Blow - BackupsBlow/Util.pm
#!/usr/bin/perl -w
# Backups Blow by Brandon Low 
#
# Copyright 2007 Brandon Low 
# Released under the terms of the GPL v2
#
# http://lostlogicx.com/backupsblow/

package BackupsBlow::Util;

use strict;
use Exporter;
our (@EXPORT_OK, %EXPORT_TAGS, @ISA);
@ISA = qw(Exporter);
@EXPORT_OK = qw(&buildTarCommand &printTime &performMounts &performUnmounts);
%EXPORT_TAGS = ("all" => [@EXPORT_OK], "transport" => [qw(&buildTarCommand)]);

use BackupsBlow::Config qw(:read);
use BackupsBlow::Programs qw(:all);

use Log::Log4perl;
my $logger=Log::Log4perl->get_logger();

# Globals, needed to improve the chances of an error leaving
# the system in a predictable state.
my @ejects;
my @unmounts;

sub performMounts() {
    if (my @inserts=configArray("EJECTS")) {
        my $eject=needProgram("eject");
        foreach my $insert(@inserts) {
            system(my $command="$eject -t $insert");
            die("Command failed: $command: $?") unless ($? == 0);
            push @ejects,$insert;
        }
    }
    if (my @mounts=configArray("MOUNTS")) {
        my $mount=needProgram("mount");
        foreach my $mountPoint(@mounts) {
            system(my $command="$mount $mountPoint");
            die("Command failed: $command: $?") unless ($? == 0);
            push @unmounts,$mountPoint;
        }
    }
}

sub performUnmounts() {
    if (@unmounts) {
        if (my $umount=program("umount")) {
            while (my $mountPoint=pop @unmounts) {
                system(my $command="$umount $mountPoint");
                unless ($? == 0) {
                    # Consider these non-fatal, but warn the sysadmin
                    $logger->warn("Command failed: $command: $?");
                }
            }
        } else {
            $logger->warn("umount not found in path");
        }
    }
    if (@ejects) {
        if (my $eject=program("eject")) {
            while (my $ejectDev=pop @ejects) {
                system(my $command="$eject $ejectDev");
                unless ($? == 0) {
                    # Consider these non-fatal, but warn the sysadmin
                    $logger->warn("Command failed: $command: $?");
                }
            }
        } else {
            $logger->warn("eject not found in path");
        }
    }
}

sub printTime ($$) {
    my ($name,$time)=@_;
    my $hours=int($time/3600);
    my $minutes=int(($time-3600*$hours)/60);
    my $seconds=$time-3600*$hours-60*$minutes;
    print "\u$name elapsed time: ";
    my $result="";
    $result.=sprintf "%dh",$hours if ($hours != 0);
    $result.=sprintf "%02dm",$minutes if ($hours != 0 || $minutes != 0);
    $result.=sprintf "%02ds\n",$seconds;
    $result=~s/^0([0-9])/$1/;
    print $result;
}

# Build an incremental tar command
sub buildTarCommand ($$) {
    my ($incFile,$errFile)=@_;

    my @dirs=needConfigArray("DIRS");
    foreach my $dir(@dirs) {
        die("A specified directory is not a directory") unless ( -d $dir );
    }

    my $tar=needProgram("tar");
    my $compression=needProgram(config("COMPRESSION_PROGRAM","gzip"));

    my @tarCommand;
    push @tarCommand,$tar;
    push @tarCommand,"-g $incFile";
    push @tarCommand,"--use-compress-program $compression";
    push @tarCommand,"-c";
    my @excludes=configArray("EXCLUDES");
    foreach my $exclude(@excludes) {
        push @tarCommand,"--exclude=\"$exclude\"";
    }
    push @tarCommand,"-f -";
    push @tarCommand,@dirs;
    push @tarCommand,"2>";
    push @tarCommand,$errFile;

    return join(" ", @tarCommand);
}

sub handler {
    my $sig = $_[0];
    die("Caught signal: $sig");
}

sub show_call_stack($) {
    my $logFunc = $_[0];
    my ($path, $line, $subr);
    my $max_depth = 30;
    my $i = 1;
    &$logFunc("--- Begin stack trace ---");
    while ( (my @call_details = (caller($i++))) && ($i<$max_depth) ) {
        &$logFunc($call_details[1].
            " line ".$call_details[2].
            " in function ".$call_details[3]);
    }
    &$logFunc("--- End stack trace ---");
}


sub cleanDeath {
    # Don't change die behavior in the parser
    if (defined $^S) {
        performUnmounts();
        $logger->error(@_);
        show_call_stack(sub {$logger->debug(@_)});
        exit(1);
    }
}

$SIG{__DIE__} = \&cleanDeath;
$SIG{'INT'} = \&handler;
$SIG{'TERM'} = \&handler;
$SIG{'QUIT'} = \&handler;

1;
"Sell not virtue to purchase wealth, nor liberty to purchase power." --Fortune Cookie
Google
 
© 2002-2010 Brandon Low 49 hits since September 7, 2008