#!/usr/bin/perl -w

use warnings;
use strict;


# Tweak to your liking...

my $rsyncbin = '/usr/local/bin/rsync';
my $backupmount = '/Volumes/BackupDrive';
my $logbase = '/usr/local/webserver_stuff/backup';
my $urlbase = 'http://centralserver/backup';  # can be url or dir or undef.
my $localrsyncopts = '--numeric-ids'; 

# --dry-run is good when testing.
#$localrsyncopts .= ' --dry-run';

# Don't touch anything below here under normal circumstances...

my $somebackup = 0;
my $logplaced = 0;
my $logurl=undef;

sub shell {
    my $cmd = shift;
    return(system($cmd) == 0);
}

sub failout {
    my $err = shift;
    my $date = `date`;
    chomp($date);
    print "$0: $date\n" ;
    print "$0: $err\n";

    if ($somebackup) {
        print "$0: A backup may exist in some form, but is probably incomplete.\n";
    } else {
        print "$0: No backup was made!\n";
    }

    if ((defined $logurl) and ($logplaced)) {
        print "$0: For details, please examine the log at $logurl\n";
    }

    print "$0: Do NOT ignore this problem!\n";

    exit 1;
}

sub dousage {
    failout('USAGE: <backupid> [dir1] [dir2] ...')
}

my $backupid = shift;
my $dirstobackup = '';
foreach (@ARGV) {
    $dirstobackup .= " '$_'";
}
$dirstobackup =~ s/\A (.*)\Z/$1/;  # trim that annoying first space...  :/
dousage() if ((not defined $backupid) or ($dirstobackup eq ''));

shell("mkdir -p '$logbase'") || failout("Couldn't create log dir '$logbase'");

my $logfname="$logbase/$backupid/backup-in-progress-log.txt";
my $logerrorfname="$logbase/$backupid/backup-in-progress-error-log.txt";
my $finallogfname="$logbase/$backupid/last-backup-log.txt";
my $lastsuccesslogfname="$logbase/$backupid/last-successful-backup.txt";
$logurl = "$urlbase/$backupid/last-backup-log.txt" if (defined $urlbase);

failout("Backup disk isn't mounted!") if (not -d $backupmount);

shell("mkdir -p '$logbase/$backupid'") || failout('Failed to create logdir!');
shell("chmod 0755 '$logbase/$backupid'");

my $olddir = `ls -td "$backupmount/$backupid"/backup* 2>/dev/null |tail -n 1`;
chomp($olddir);
failout("No backup dirs seen at '$backupmount/$backupid'.") if ($olddir eq '');
failout("'$olddir' is not a directory!") if (not -d $olddir);

my $datestr = `date "+%b-%d-%Y--%H.%M.%S"`;
chomp($datestr);
my $backupdir = "$backupmount/$backupid/backup-$datestr";

failout("Can't open logfile '$logfname'!") if not open(LOGH,'>',$logfname);

shell("mv '$olddir' '$backupdir'") || failout("Failed to rename '$olddir'");

my $rsyncopts = '-av' .
                ' --delete' .
                ' --relative' .
                ' --no-implied-dirs' .
                ' --stats' .
                '';

if ((defined $localrsyncopts) and ($localrsyncopts ne '')) {
    $rsyncopts .= " $localrsyncopts";
}

my $cmd = "cd / &&" .
          " $rsyncbin $rsyncopts $dirstobackup '$backupdir'/" .
          " 2>>'$logerrorfname' 1>>'$logfname'";

print LOGH `date`;
print LOGH "Backup ID: $backupid\n";
print LOGH "Backup location: $backupdir\n";
print LOGH "Dirs to backup: $dirstobackup\n";
print LOGH "rsync command line: $cmd\n";
print LOGH "\n";
print LOGH "\n";
print LOGH "rsync stdout output follows:\n";
print LOGH "\n";
close(LOGH);

$somebackup = 1;

my $rsyncsucceeded = shell($cmd);

my $errfilesize = (stat($logerrorfname))[7];
if ($errfilesize > 0) {
    `echo >>'$logfname'`;
    `echo >>'$logfname'`;
    `echo 'rsync stderr output follows:' >>'$logfname'`;
    `echo >>'$logfname'`;
    `cat '$logerrorfname' >>'$logfname'`;
}

`echo >>'$logfname'`;
`echo >>'$logfname'`;
`echo -n "rsync process ended at " >>'$logfname'`;
`date >>'$logfname'`;
`echo >>'$logfname'`;
`echo >>'$logfname'`;

$logplaced = (shell("mv '$logfname' '$finallogfname'"));
system("cat '$logerrorfname'") if (not $rsyncsucceeded);
unlink $logerrorfname;
unlink $logfname if (not $logplaced);
failout('rsync had errors!') if (not $rsyncsucceeded);

`touch "$backupdir"`;  # make sure it's the newest dir.
`echo "$backupdir" > "$lastsuccesslogfname"`;
`chmod 0444 "$finallogfname" "$lastsuccesslogfname"`;

exit 0;  # success!

