#!/usr/local/bin/perl


# Usage: backup [-<option>] [userfile]
# backup v0.2 - backup fileareas using tar
# last updated: 29/o8 1995 audun
# options: 	-t tapebackup (flag)
#               -s scan userdir (and backup all users)
#		-f destination dir
#               -d recursive backup of this directory
#               -x exclude file (default = /local/mutils/bin/backup.exclude)
#               -a add directory to default (or userfile)
#               -p fix protection bits (flag)
#               -e emulate tar (no backup)
#               --help display help

# example:      backup -f /spare/backup -d /iu/nexus/u1 -d /iu/nexus/u2
#               backup -s /iu/nexus/u1

# todo: check filnavn, check hdplass->mail drift
# tar: tar -cvX ./exclude -f hei qwk

# defaults
$backupgroup = "iu";
$exclude = "/local/gnu/lib/cfengine/bin/backup.exclude";
$destination = "/iu/nexus/backup";
$sourcedir = "/iu/nexus/u1/ /iu/nexus/u2/";
$gnutar = "/local/gnu/bin/tar --atime-preserve -czvpX $exclude -f ";
$chown = "/local/gnu/bin/chown";
$chgrp = "/local/gnu/bin/chgrp";
$chmod = "/local/gnu/bin/chmod";

# exlude these users (-s option)
$excludeusers = 'ftp ide lost+found sdt';
@excludeusers = split(" ", $excludeusers);

# options and subprocedures
%optionlist =
(
 '-t', 'tape_option',
 '-f', 'file_option',
 '-d', 'dirs_option',
 '-x', 'excl_option',
 '-a', 'addd_option',
 '-s', 'scan_option',
 '-p', 'prot_option',
 '-e', 'emul_option',
 '--help', 'help_option',
);

# misc
$syntax = "syntax: backup [-<options>] [userfile]";
$options = "options: [-f dir] [-x file] [-d dir] [-a dir] [-s dir] [--help]";


&parse;
&backup;


sub parse
{
    # check for arguments
    if ($#ARGV >= 0)
    {
	undef $userfile;
	undef $newdir;
	undef $prot_enable;
	undef $emul_enable;
	# parse all supplied arguments
	for ($arg = 0; $arg <= $#ARGV; $arg++)
	{
	    if (substr($ARGV[$arg], 0, 1) ne "-")
	    {
		&userfile;
	    }
	    else
	    {
		&options;
	    }
	}
    }
}


sub backup
{
    # add datestamp to backupfile
    ($sec, $min, $hour, $mday, $mon, $year) = localtime(time);
    $mon++;
    $destdate = "backup.$mday.$mon.$year";

    # check for existing file (not bloody likely)
#    die "error: backup file already exists!\n" if (-e "$destination");

    # check for directory override (-d option)
    $sourcedir = $newdir if ($newdir);

    # for every defined dir
    @sourcedir = split(" ", $sourcedir);
    foreach $sourcedir (@sourcedir)
    {
	# replace "/" with "."
        ($destpostfix = $sourcedir) =~ tr/\//./;
	if (substr($destpostfix, 0, 1) eq ".")
	{
	    $destpostfix = substr($destpostfix, 1, length($destpostfix));
	}
	if (substr($destpostfix, -1, 1) eq ".")
	{
	    chop($destpostfix);
	}
	if (!$emul_enable)
	{
	    system "$gnutar $destination/$destdate.$destpostfix $sourcedir >/dev/null 2>&1";
	}
	else
	{
	    print "$gnutar $destination/$destdate.$destpostfix $sourcedir\n";
	}
    }

    # do protection bits
    &fixprotection if ($prot_enable);
}


sub userfile
{
    # check for excessive use of arguments!
    die "too many arguments!\n$syntax\n" if ($userfile);
    $userfile = $ARGV[$arg];
    # throw away default dirs
    undef $sourcedir;

    # load list of userdirs
    open (IN, "$userfile");
    while ($line = <IN>)
    {
	if ($line && substr($line, 0, 1) ne "\n")
	{
	    # check for leading / in absolute pathname
	    die "userfile error: no leading / in absolute pathname\n" if (substr($line, 0, 1) ne "/");
	    chop($line) if (substr($line, -1) eq "\n");
	    $sourcedir .= $line;
	    $sourcedir .= " ";
	}
    }
    close(IN);
}


sub options
{
    # check supplied options and sub to command if defined
    die "option not defined!\n$options\n" if (!$optionlist{$ARGV[$arg]});
    $sub = $optionlist{$ARGV[$arg]};
    &$sub;
}


sub prot_option
{
    $prot_enable = 1;
}


sub emul_option
{
    $emul_enable = 1;
}


sub fixprotection
{
    opendir(SDIR, "$destination/");
    
    # reading the directory, scanning for backup
    @backupfiles = grep(/^backup./, readdir(SDIR));
    foreach $file (@backupfiles)
    {
	# can't split on "." (won't work)
	for ($i = length($file); $i > 0; $i--)
	{
	    last if (substr($file, $i, 1) eq ".");
	}
	$owner = substr($file, $i + 1, (length($file) - $i));
        $bfile = $defsource;
        $bfile .= $file;
        $file = $bfile;

	system "$chown $owner $destination/$file";
	system "$chmod 600 $destination/$file";
	system "$chgrp $backupgroup $destination/$file";
    }
    closedir(SDIR);
}


sub scan_option
{
    # scan userdirs
    $arg++;

    # check for syntax error
    $next = substr($ARGV[$arg], 0, 1);
    die "directory name missing!\n$options\n" if ($next eq "-") || ($next eq ""); 

   # read directory entries
    opendir(SDIR, $ARGV[$arg]);
    
    # reading the userdirectory, avoding . and .*
    @allusers = grep(!/^\.\.*/, readdir(SDIR));
    closedir(SDIR);

    undef $sourcedir if (!$scan);
    $scan = 1;
    # checking the userdirectory for users to exclude
    foreach $user (@allusers)
    {
	$found = 0;
	foreach $xuser (@excludeusers)
	{
	    if ($user eq $xuser)
	    {
		# entry will be excluded
		$found = 1;
		last;
	    }
	}
	if ($found == 0)
	{
	    # add this entry to the sourcedir list
	    $newuser = $ARGV[$arg];
	    chop($newuser) if (substr($newuser, -1, 1) eq "\n");
	    $newuser .= "/" if (substr($newuser, -1, 1) ne "/");
	    $newuser .= $user;
	    $newuser .= " ";
	    $sourcedir .= $newuser;      
	}
    }
}


sub tape_option
{
    # backup to tape
    die "function not yet implemented, sorry!\n$options\n";
}


sub file_option
{
    # set destination
    $arg++;

    # check for syntax error
    die "filename missing!\n$options\n" if (substr($ARGV[$arg], 0, 1) eq "-");

    $destination = $ARGV[$arg];
}


sub dirs_option
{
    $arg++;

    # check for syntax error
    die "directory name missing!\n$options\n" if (substr($ARGV[$arg], 0, 1) eq "-");

    # add this directory to multiple directory list
    $newdir .= $ARGV[$arg];
    $newdir .= " ";
}


sub excl_option
{
    $arg++;

    # check for syntax error
    die "exclude name missing!\n$options\n" if (substr($ARGV[$arg], 0, 1) eq "-");

    # use this as exclude file for tar
    $exclude = $ARGV[$arg];
}


sub addd_option
{
    $arg++;

    # add a directory to backup in addition to default (or userfile) dirs
    # check for syntax error
    die "directory name missing!\n$options\n" if (substr($ARGV[$arg], 0, 1) eq "-"); 

   # add this directory to multiple directory list
    $sourcedir .= $ARGV[$arg];         
}


sub help_option
{
    print "Usage: backup [-<options>] [userfile]\n";
    print "backup v0.2 - backup fileareas using tar\n";
    print "last updated: 29/o8 1995 audun\n";
    print "options:      -t tapebackup (flag)\n";
    print "              -f destination dir\n";
    print "              -d recursive backup of this directory\n";
    print "              -x exclude file (default = /local/mutils/bin/backup.exclude)\n";
    print "              -a add directory to default (or userfile)\n";
    print "              -s userdirectory\n";
    print "              -p fix protection bits (flag)";
    print "              -e emulate tar (no backup)";
    print "              --help display help\n";
    print "example:      backup -f /spare/backup -d /iu/nexus/u1 -d /iu/nexus/u2\n";
    print "              backup -s /iu/nexus/u1\n";
    exit;
}


# only amiga makes it possible!

