Alwanza Home Extraordin-Air Team Final Project Linux Course Home
#!/usr/bin/perl
#
# Projects 20 and 21
# UW Extension UNIX/Linux Summer Intensive Program
#
# Jesse Snyder
# July 29th, 2002
#
# The purpose of the program is to create a compressed .tar file
# composed of all files listed in the output of another Perl program.
# Additional conditions include:
# -The name of the file should include the date and the machine name
#
# -The program should estimate the disk space required to hold the
# .tar file, compare it to available disk space, and proceed with the
# backup only if there is ample room.
#
use strict;
# We never want to run backup if there are 100 kb or less on disk
use constant MIN_FREE_SPACE => 100 * 1000;
use constant MIN_TAR_FILES => 1;
use constant TRUE => 1;
use constant FALSE => 0;

my $archiveDir = "/root/bin/archive/";
my $archiveList = "/root/bin/changes.ls";
my $fileSystem = "/dev/hda2";

# if we've deleted all but one of our old backup files
# and we still don't have room, this will be set to 1
my $jammed = 0;
my $tars_remaining;
my $enough_space = 0; # assume there's no room to run backup until proven otherwise

open (WORKTODO, "<$archiveList") or die "Can\'t open $archiveList: $!";

my @files_to_tar;
my @lines;

chomp(@lines = <WORKTODO>);
my $item;
my $count = 0; # apparently there is a limit to how many files tar
# can accept but I don't know what that limit is.

foreach $item(@lines) {
  next if -d $item; # ignore if item is directory
next unless -s $item; # ignore if file doesn't exist or has zero size
next if $item =~ /linux-2.5.9/; # don't archive kernels

$item =~ s|^\/||; # remove leading "/" for tar
# print "item = $item\n";
push(@files_to_tar, $item);
$count++;
# last if $count == 1000;
}

opendir (ARCHIVES, $archiveDir);
my @archive_list = grep !/^\./, (readdir(ARCHIVES));

# print "archive_list = @archive_list" . "\n";

#### Make initial check of space required for backup and available disk space
($tars_remaining, $jammed) = &Check_Jam(@archive_list);
# print "jammed = $jammed\n";
$enough_space = &Check_Space($fileSystem, @files_to_tar);

#### If there isn't enough space, try deleting old backup files until there is enough space

until(($enough_space) || ($jammed) || ($tars_remaining == 1)) {
  &Delete_Oldest_Tar(@archive_list);
$enough_space = &Check_Space($archiveList);
($tars_remaining, $jammed) = &Check_Jam(@archive_list);
}


#### If we're down to one file and there still isn't room, report the situation and we're done
if ($jammed) {
  &Report_Jam;
} elsif ($enough_space) {
  #### If there is enough room, we can proceed with backup
&Do_Backup($archiveDir, @files_to_tar);
} else {
  &Report_Error($enough_space);
#### Error condition
}

closedir ARCHIVES;
close WORKTODO;

#### Function Definitions #####
#*********************
sub Check_Space {
  my ($fileSystem, @files_to_tar) = @_;
my $section;
my $total;
my $used;
my $unused;
my @usage = `df -kl`;
# print "usage =\n@usage" . "\n";
my $use;
foreach $use(@usage) {
   next if $use !~ /^\W*$fileSystem/;
# print "use line 97 = $use\n";
($section, $total, $used, $unused) = split (" ", $use);
  }

my $free_space = $unused; # total kilobytes free on disk
print "space available on disk = $free_space\n";

my $tar;
my $size;
my $totalsize;
foreach $tar(@files_to_tar){
   $tar = "/" . $tar; # restore beginning / to files to check size
$size = ((stat($tar))[7]) * 2;
$totalsize += $size;
# print "file = $tar\n total size = $totalsize\n";
  }
# 65% of total file size in kilobytes
my $backup_requires = ($totalsize) * (65/100);
print "back-up size estimate = $backup_requires kilobytes\n";

if ($free_space - $backup_requires < MIN_FREE_SPACE){
   return FALSE;
  } else {
   return TRUE;
  }
}

#*********************

sub Check_Jam {
  my @archive_list = @_; # listing of the whole archive directory

# number of .tar files we've got in archive
my $tars_remaining = $#archive_list + 1;
# print "tars remaining = $tars_remaining\n";

my $jammed = ($tars_remaining < MIN_TAR_FILES)? 1 : 0;
return $tars_remaining, $jammed;
}

#*********************
sub Delete_Oldest_Tar {
  my @archive_list = @_; # listing of the whole archive directory
my $oldest; # name of oldest tar in archive

#open ARCHV, "/root/bin/changes.ls"
#or die "Cant open changes.ls: $!";

#@archive_list = ARCHV;

$oldest = @archive_list;
if ($oldest > 1) {
   sort(@archive_list);
$oldest = pop(@archive_list); # get the oldest entry
my $success = (0 == system "rm -f $oldest");

return $success;
  } else { return 1; }
}

#*********************
sub Do_Backup {
  my ($archiveDir, @files_to_tar) = @_;
# we must start in / directory, because tar uses relative paths

chdir "/" or die "cannot chdir to /: $!";
# chdir($archiveDir) or die "cannot chdir to $archiveDir: $!";

chomp (my $date = `date +%Y%m%d`);
chomp (my $machine = `uname -n`);
my $tar_name = $archiveDir . $date . $machine . ".tar.gz";
my $tar_log = $archiveDir . $date . $machine . ".log";

print "This process takes about 2 to 5 minutes\n";

my $files_to_tar = join (" ", @files_to_tar);
# print "files to tar = $files_to_tar\n";
# the ORDER of the switches is important
# must begin with "c" and end in "f"
my $success = `tar -cvzf $tar_name $files_to_tar`;

open (TARLOG, "> $tar_log");
if ($success) {
   foreach $_ (@files_to_tar) {
    print TARLOG "$_";
print TARLOG "\n";
   }
print "tar file is in $tar_name\n";
  } else {
   print "tar failed\n";
print TARLOG "tar failed\n";
  }
close TARLOG;
return;
}

#*********************
sub Report_Jam {
  print "There's a problem - 'Report_Jam'.\n";
}

#*********************
sub Report_Error {
  $enough_space = shift;
print "Not enough space to do backup\n";
}