#!/usr/bin/perl # # 2001 (c) 1U Ring Inc, All Rights Reserved # # - You may do anything you like with it...except sell the script # # Latest Version # -------------- # http://www.Linux-Backup.net/scripts/Backup.pl # # # To Implement this Backup Strategy # --------------------------------- # - create a backup group ( chmod 770 for directories ) # - create a remote backup server ( BackupServer:/Backup.$Host ) # - create a local backup mount point ( mount BackupServer:/Backup.$Host /Backup ) # - check paths for binaries and exludes # - automate it with cron # - test your backups regularly for discrepencies and proper backup performance # # # Incremental Backup the System # ============================= # # make sure the /Backup/$Host directory exists BEFORE running this script # /usr/sbin/groupadd -g 200 backup # # Remote Backup Server # BackupServer: mkdir /Raid/Backup.$HOST # BackupServer: chown root.backup /Raid/Backup.$HOST # BackupServer: chmod 750 /Raid/Backup.$HOST # # LocalHost to be backed up into Remote backup server # HOST: mkdir /Backup # HOST: mount BackupServer:/Backup.$Host /Backup # HOST: vi BackupServer:/Backup.$Host/.Backup.cfg # # # To Test it: # ---------- # ./Backup.pl -skipWeb -back /Backup.NFS [ -test ] # # crontab -e # ---------- # # # Daily Incremental Backups # 5 00 * * 1-5 /usr/scripts/Backup.pl -back /Backup.Daily # # # Weekly Incremental Backups # # Sat at 01:01 am - 30 days of Incremental backups -- span multiple weekly backup # 1 01 * * 6 /usr/scripts/Backup.pl -back /Backup.32 -inc32 # # # Sun at 02:01 am - Full Backups # 1 02 * * 0 /usr/scripts/Backup.pl -back /Backup.Full -full # # # Monthly # # 1:01 on the 1st of every month - do 90 day incremental backup - span multiple full backup # 1 01 1 * * /usr2/local2/scripts/Backup.pl -skipWeb -day 95 # # # manually mount backups - to prevent "rm -rf" of automountable /Backup dirs # # Backup.Daily is server#1, Backup.32 is a different server#2, ... # # Rotating Backups w/ fstab: ( assumes this host can write into those hosts' dirs ) # ------------------------- # Backup_Host:/Backup_Dir /Backup # Backup_Week:/Backup_WeekDir /Backup_Week # Backup_Full:/Backup_FullDir /Backup_Full # # Mirror:/Mirror_Dir /Mirror # # -------------------------------------------------------------------------------------------- # # HISTORY # ======= # 26-Nov-98 amo Modified for Chipmunk # 28-Dec-01 amo Cleanup # # # -------------------------------------------------------------------------------------------- # local ( $NM ) = "Backup.pl"; # # # Some default dir to backup # my ( $Dir ) = "/root /etc /opt/Scripts"; # # # Do NOT backup these files, do NOT backup these dirs # =================================================== # - prints wrong but tars correctly # # 05-Nov-01 amo Exclude /foo and /core files # my ( $Exclude ) = ".netscape/cache\|/foo$|/core$\|-\$\|~\$" ; # # # Commands used # ------------- # my ( $DATE ) = "/bin/date"; my ( $DF ) = "/bin/df"; my ( $EGREP ) = "/bin/egrep"; my ( $FIND ) = "/usr/bin/find"; my ( $GREP ) = "/bin/grep"; my ( $HOSTNAME ) = "/bin/hostname"; my ( $MOUNT ) = "/bin/mount"; my ( $TAR ) = "/bin/tar "; # different tar filename my ( $UMOUNT ) = "/bin/umount"; # # my ( $Host ) = ` $HOSTNAME -s`; my ( $Domain ) = ` $HOSTNAME -d`; chomp ( $Host ); chomp ( $Domain ); # # # Top level Backup Directory on LocalHost # --------------------------------------- # my ( $TOP ) = "/Backup"; # # # Local mount point for remote:/Raid_Backup # my ( $Top_Host ) = "$TOP/$Host"; # Might get redefined by "-back foo" # # # Top level Mirror Directory ( for rsync equivalent ) # my ( $MIRROR ) = "/Mirror"; my ( $MakeMirror ) = 0; # # # ---------------------------------------------------- # This Host will backup into a remote backup server == BackupServer:/Raid_Backup/Backup.$Host # ---------------------------------------------------- # my ( $GID ) = 200; # backup group # my ( $BackupServer ) = "Backup.$Domain"; # my ( $Backup ) = "/Raid_Backup"; # large backup disk space on Backup.foo.com my ( $BackupDir ) = "$Backup/Backup.$Host"; # # # End of User Config Options # =========================== # # my ( $find_inc ) = "daily:"; # Daily, Weekly or Monthly my ( $Period ) = ""; my ( $FullInc ) = "0"; my ( $Cnt ) = 0; # # # Need to Pass this variable around # # View Backup Logs on by default since web cannot turn it on, use command line to turn it off local ( $Back_Web ) = 1; # local ( $Back_Mon ) = ""; local ( $Back_Day ) = ""; # local ( $Back_Srch ) = ""; # Search in Backup Logs # my ( $Back_Test ) = 0; # Default to go ahead and run the actual backup # # # Time Stamp Info # --------------- my ( @date ) = split ( /\s+/, ` $DATE ` ); # Mon Nov 23 00:55:58 PST 1998 # my ( $Mon ) = $date[1]; my ( $Date ) = sprintf "%02d", $date[2]; my ( $Year_Mon ) = "$date[5]" . "_$Mon"; # # # Process command line args # ------------------------- # &cmd_args; # if ( ! -d $TOP ) { printf "\n"; printf "${NM}: ERROR: No such backup dir=$TOP..\n"; printf "\n"; exit ( 1 ); } # # # # 04-Feb-00 amo Change to user defined dir if needed # $Top_Host = "$TOP/$Host"; # # # # 31-Mar-99 amo View the Backups from the browser # 03-Jul-99 amo Skip this due to from backup_ww.pl # if ( $Back_Web == 1 ) { # require "Backup_www.pl"; # # Process the web page forms # &Proc_Form ; # &Backup_View ( $TOP, $Host ); # if ( "$Back_Srch" ne "" ); # Search data # exit 1; # make sure we exit # } # web-based view # # # Manually Mount the Backup directory to prevent accidental erasure of backup dirs # unmount it first, just in case of stale NFS mounts # # # =========================== # Mount the Backup directory # =========================== # my ( $mnt ) = "$MOUNT $BackupServer:$BackupDir $TOP"; # # Check that it mounted properly my ( @status ) = ` $mnt ; $DF | $GREP $BackupDir | $GREP $Host `; # printf "..$mnt..\n"; # # something went wrong... didnt mount # if ( $#status != 0 ) { printf "..$NM: ERROR: $Host: stat[$#status]=$status[0]..\n"; exit 1; } # # # 02-Jun-00 amo Prevent Unmounting when *.7 and *.32 is running # `cd $TOP `; # # # # Make sure we have Monthly Backup Directory # ------------------------------------------ # - not need since using no_root_squash .. but use backup group for it's intention # if ( ! -d "$TOP/$Host" ) { mkdir "$TOP/$Host", 0770 ; # this script cannot CREATE a new directory for host chown 0, $GID, "$TOP/$Host" ; chmod 0770, "$TOP/$Host" ; } # Host # if ( ! -d "$TOP/$Host/$Year_Mon" ) { mkdir "$TOP/$Host/$Year_Mon", 0770 ; chown 0, $GID, "$TOP/$Host/$Year_Mon" ; chmod 0770, "$TOP/$Host/$Year_Mon" ; } # month # # # Now see if we have some info about what files to backup # ------------------------------------------------------- # if ( -f "$Top_Host/.Backup.cfg" ) { # # allow only a single line # chomp ( $str = `grep -i ^$find_inc $Top_Host/.Backup.cfg ` ); # ( $junk, $dir ) = split ( /:/, $str ); $dir =~ s/^\s+//; # snip off leading spaces # $Dir = $dir if ( length ($dir) > 0 ); # # # 28-Jun-99 Exclude these dir from Backups # chomp ( $str = `grep -i ^Exclude: $Top_Host/.Backup.cfg ` ); # ( $junk, $dir ) = split ( /:/, $str ); $dir =~ s/^\s+//; # snip off leading spaces # $Exclude = $dir if ( length ($dir) > 0 ); # # } # backup config file # # # Keep n-days worth of backup from Last FULL backup # ----------- # if ( $FullInc eq "0" ) { if ( -f "$Top_Host/.Backup.Inc" ) { $FullInc = `cat $Top_Host/.Backup.Inc`; chomp ( $FullInc ); } $FullInc = 1 if ( $FullInc eq 0 ); $Cnt = $FullInc +1; # increment for next day # } else { # Reset for -inc8, -inc32, -full $Cnt = 1; } $Period = "-mtime -$FullInc" if ( $FullInc ne "Full" ); # # # # Prepare to do the Backup # ------------------------ # my ( $TGZ ) = "$Top_Host/$Year_Mon/$Date.$FullInc.tgz"; my ( $LOG ) = "$Top_Host/$Year_Mon/$Date.$FullInc.log"; my ( $MSG ) = "$Top_Host/$Year_Mon/$Date.$FullInc.msg"; # # # 28-Jun-99 Exclude these dir from Backups # my ( $cmd ) = "$FIND $Dir $Period -type f -print | $EGREP -v \"$Exclude\" | $TAR zcvf $TGZ -T - "; # # Reset the user feedback log file # `echo "" > $MSG`; # # printf "$cmd\n"; # print it explicitly due to escapes ` $cmd `; # do the backup # # # Show the contents of the *.tgz file # ------------------------------------ ` $TAR ztvf $TGZ > $LOG `; # # # Change the permission to "backup" # --------------------------------- # chown 0, $GID, $TGZ,$MSG,$LOG ; chmod 0640, $TGZ,$MSG,$LOG ; # # # Lets show some feedback # ----------------------- # $cmd = "ls -la $Top_Host/$Year_Mon/$Date.$FullInc.* " ; &pr_cmd ( $cmd ); # # $cmd = "df" ; &pr_cmd ( $cmd ); # # # Now Extract the changes to update the Mirror # -------------------------------------------- # &mirror ( $TGZ ) if ( $MakeMirror ); # # # Increment Day Counter since full backup # --------------------------------------- # # dont increment if testing ` echo $Cnt > $Top_Host/.Backup.Inc ` if ( $Back_Test == 0 ); # # Unmount backup dirctory # printf "umount $TOP\n"; ` $UMOUNT $TOP`; # exit ( 0 ); # # =========================================================================================== # # Exctract the changes into the mirror ( assumes this host cn write into it ) # sub mirror { my ( $tgz ) = $_[0]; # Changes to mirror # my ( $cmd ) = "cd $MIRROR/$Host ; $TAR zxvfp $tgz" ; # printf "\n"; printf "mount $MIRROR\n"; ` $MOUNT $MIRROR`; # # Make sure the Host dir exists # mkdir "$MIRROR/$Host", 0770 if ( ! -d "$MIRROR/$Host" ) ; # `echo "$cmd" >> $MSG`; `echo "" >> $MSG`; printf "$cmd \n"; ` $cmd `; # printf "umount $MIRROR\n"; ` $UMOUNT $MIRROR`; # } # mirror # # # Print command and execute # ------------------------- # sub pr_cmd { my ( $cmd ) = @_[0]; my ( @res ) = ""; # ` echo "#" >> $MSG `; # feeback via email ` echo "# $Host# $cmd" >> $MSG `; ` echo "#" >> $MSG `; # printf "#\n"; # feedback on screen printf "# $Host# $cmd\n"; printf "#\n"; # @res = ` $cmd `; # execute the command # $rez = sprintf "%s", join ( " ", @res ); # ` echo "" >> $MSG ` ; # feeback via email ` echo "$rez" >> $MSG `; # printf "\n"; # feedback on screen printf "$rez\n"; # } # pr_msg # # # Print error mesg # ---------------- # sub pr_error { my ( $exit ) = @_[0]; my ( $msg ) = @_[1]; # printf "ERROR: $msg\n"; # # exit ( 1 ) if ( $exit ); # } # pr_error # # Generic help stuff # ------------------ # sub usage { my ( $exit ) = @_[0]; # printf "\n"; printf "${NM}: Usage\n"; printf "\t -h\tthis help file\n\n"; # printf "\t -test\tShow what we would have done\n\n"; # printf "\t -view View the Backup logs\n\n"; printf "\t -back xxx TopLevel Backup dir ( /Backup is default )\n"; printf "\t -mirror xxx TopLevel Mirror dir ( /Mirror is default )\n"; printf "\n"; printf "\t -days N\tIncremental backups ( -mtime -N )\n"; printf "\t -inc8\tIncremental backups ( -mtime -8 )\n"; printf "\t -inc32\tIncremental backups ( -mtime -32 )\n"; printf "\n"; printf "\t -full\tFull backups\n"; printf "\n"; # exit ( 1 ) if ( $exit ); # } # usage # # # Process the command line args # ----------------------------- # sub cmd_args { my ( $id ) = 0; # my ( $arg ) = ""; # while ( $id <= $#ARGV ) { # $arg = $ARGV[$id]; # if ( $arg eq "-h" ) { &usage ; exit 0; # } elsif ( $arg eq "-test" ) { $Back_Test = 1; # pretend to do backups # } elsif ( $arg eq "-skip" || $arg eq "-skipWeb" ) { $Back_Web = 0; # Skip using HTML browser to view backup logs # } elsif ( $arg eq "-search" ) { $id += 1; $Back_Srch = "$ARGV[$id]"; # Seearch for this in Backup Logs # } elsif ( $arg eq "-back" ) { $id += 1; $TOP = "$ARGV[$id]"; # Top level Backup dir # &pr_error ( 1, "No such dir=$TOP" ) if ( ! -d "$TOP" ); # } elsif ( $arg eq "-mirror" ) { $id += 1; $MIRROR = "$ARGV[$id]"; # Top level Mirror dir # &usage ( 1 ) if ( $MIRROR eq "" ); # if ( ! -d "$MIRROR" && ! -l "$MIRROR" ) { &pr_error ( 0, "Skipping mirror, No such dir=$MIRROR\n----------------------" ) ; } else { $MakeMirror = 1; # okay to attempt to mount mirror dir and copy it over } # } elsif ( $arg eq "-days" ) { $id += 1; $FullInc = "$ARGV[$id]"; # Number of Days to backup # } elsif ( $arg eq "-inc8" ) { $FullInc = "8"; } elsif ( $arg eq "-inc32" ) { $FullInc = "32"; } elsif ( $arg eq "-full" ) { $FullInc = "Full"; } # $id += 1; # } # check cmdline args # } # cmd_args # # end of file