#!/usr/bin/perl # $Revision$ # # This is a script that will copy the contents of one drive to another. # It's intended to be run nightly. It uses rsync to do the copying. # You have to adjust the list of drive partitions to copy. # use strict; use vars qw($opt_d $opt_f $opt_h $opt_n $opt_v); use Getopt::Std; $ENV{PATH} = '/sbin:/bin:/usr/bin'; sub Usage { print < "--exclude '/dev/*'", '/var' => "--exclude '/var/log/*' --exclude '/var/spool/dnews/*' --exclude '/var/run/*'", ); # List of options for fsck based on filesystem type. my %fsck_options = ( 'ext2' => '-f', # force check even if it's "not time yet" 'reiserfs' => '-x', # perform minor fixes ); #------------------------------------------------------------------------ my $mount_point = '/mnt/synchro'; # # Given a device spec as input, return the destination spec. # For example, hda7 returns hdc7 and sdc1 returns sda1. # # You will probably have to change this function for your set up. # You could set up a lookup table here if your set up is more complex. # sub get_dest { my $drive = shift; # print "INPUT = $drive ===> OUTPUT = "; #debug my $first = 'a'; my $second = 'c'; if ($drive =~ /[hs]?d$first/) { $drive =~ s/([hs]?)d$first/$1d$second/; } else { $drive =~ s/([hs]?)d$second/$1d$first/; } # print "$drive\n"; #debug return $drive; } my (%mounts, %fstype); unless (-d $mount_point) { mkdir ($mount_point, 0700); } (-d $mount_point) || die "$mount_point does not exist and could not be created. $!\n"; # Use the 'mount' command to determine current mount points and fs types open(MOUNT, 'mount|') || die; while () { my ($disk,$on,$mp,$type,$fstype) = split; $mounts{$mp} = $disk; $fstype{$mp} = $fstype; } close MOUNT; # Try to unmount first just in case someone left a filesystem mounted. # This typically happens when you mount the filesystem to # manually recover a file and forget to umount when you are done. syscmd("umount $mount_point"); # Loop over the filesystem list, performing each fsck and rsync operation. foreach my $filesystem (@filesystems) { my $extras = $extras{$filesystem}; print STDERR "Working on filesystem '$filesystem'\n"; # Set $disk to be the destination filesystem. my $disk = get_dest($mounts{$filesystem}); if ($opt_f) { # Attempt the fsck, but don't stop backups if there is a warning. # The warning will show up in the email from cron. my $fstype = $fstype{$filesystem}; syscmd("fsck -t $fstype $fsck_options{$fstype} $disk") && warn "Fsck of $disk returned an error code. $!\n"; } # The correct filesystem has to be mounted, so stop if this fails. syscmd("mount -t $fstype{$filesystem} $disk $mount_point") && die "Mount of $disk failed. $!\n"; # Config errors can cause the rsync to fail for one filesystem # so just issue a warning and proceed if it fails. syscmd("rsync $rsync_options $extras ${filesystem}/ $mount_point") && warn "rsync of $filesystem failed. $!\n"; # Filesystem umount failure will also stop the script. syscmd("umount $mount_point") && die "Mount of $disk failed. $!\n"; } # # Accept a command to run as an argument. Print it to STDOUT. # Dryrun mode: That's all. Return 0 (no error) # Normal mode: Execute the command. Return != 0 on error. # sub syscmd { my $cmd = shift; print "$cmd\n"; return 0 if $opt_d; my $rc = system($cmd); if ($rc > 0x80) { return $rc >> 8; } elsif ($rc > 0) { die "Signal $rc received in $cmd\n"; } return 0; } # that's it!