Platform-Independent Backup Script
Some time ago, I was working in an environment with multiple operating system versions, including Digital, Solaris, RedHat Linux, SCO OpenServer, and HP-UX. The backup scripts in use on these servers were written to conform to the specifics of the operating system on which the script was running. This resulted in several different versions of backup scripts, increasing the difficulty in maintaining them properly. To remedy that situation, I was tasked with writing a backup script that would be standardized across all platforms. The approach I took was to write a common script that read in the platform-specific details from a configuration file. This article discusses the resulting script and configuration files.
The script and configuration files are installed in /backup. The log files are written to /usr/spool/logs/backup. A backup of important system files is made to a local filesystem. /etc/passwd, /etc/shadow, /etc/inittab, and /etc/hosts are copied to /usr/spool/logs/sysfiles. This facilitates quick recovery in the event the source files become corrupted. Other directories backed up are specified in the configuration file. Make sure that backup is the last directory specified in the configuration file, or the backup verification routine will fail.
The first portion of the script contains two function declarations. The first function, Report_Status, is called to record the status of the backup. It records the contents of the STATUS variable in four separate files. The first file, /usr/spool/logs/backup/Backup.Status, is a current status file. It always contains a single line that is the current state of the backup. You can quickly determine the state of the backup by checking the contents of this file. The second file, /usr/spool/logs/backup/Backup.Log, is a historical record of current and previous backups. The third file, /backup/TapeLog, is a record of all backups done using the current tape. It is essentially the same as /usr/spool/logs/Backup.Log, except that it only contains the information that applies to the tape in use. It is written to the tape at the end of the backup. The fourth file, /usr/spool/logs/backup/Verify.Log, is only written to when the script verifies the state of the backup, whether successful or not. It can be checked to see whether or not a successful backup occurred on a specific date.
The second function, Abort_Backup, is called when the backup needs to be aborted. There are several conditions upon which the backup should be aborted. These will be covered as they occur within the script. When this function is called, it sends mail to the specified recipients, calls the Report_Status function, and exits the script with a return code of 1.
Following the function declarations are the variable declarations. These variables do not change, regardless of the operating system upon which the script is executed. They specify the location of the various directories and log files, and several variables related to reporting backup status.
Next, we determine whether the script should use the default configuration file, /backup/backup.cfg. This file is used if the script is executed with no command-line arguments. If anything is specified on the command line, it is assumed to be the location of an alternate configuration file. This can be used to create a test configuration file without actually altering the tested configuration file. Just supply the test configuration file location on the command line when executing the script. Whichever file is used, its contents are read into the current environment. If the file does not exist, the Abort_Backup function is called, causing the script to exit.
Another check that is done before starting the backup is verifying that the specified tape device is a character-based device. This prevents a backup from creating and writing to a file on disk rather than a tape. If the specified tape device is not a character-based device, the Abort_Backup function is called, causing the script to exit.
The next part of the script makes a backup of important system files, as indicated previously. Rather than being written to tape, these files are copied to a local disk. A 31-day backup is maintained by appending the current day of the month to the filename. For instance, on the fifth day of the month, /etc/passwd is copied to /usr/spool/logs/sysfiles/passwd.05. This provides a readily accessible backup in the event the file in use becomes corrupted. Prior to copying the files, the directory structure is created if necessary.
The script allows you to specify one set of directories that are backed up Monday through Saturday, and a separate set of directories that are backed up on Sunday. Generally, a full backup is performed on Sundays, although any set of directories can be specified. Setting the WEEKLY variable to 0 in the configuration file will disable this feature, causing the same directories to be backed up every day, including Sunday. The type of backup to be performed is determined, and the BTYPE variable is set accordingly.
The initial portion of the verification routine is next. Initially, two files are created. The first file, /backup/verify.data, is the result of a ps -ef command. A sum -r command is executed on this file, and the result is stored in the second file, /backup/verify.sum. These files are written to tape at the end of the backup. They are restored from tape as part of the verification process. At that time, a second sum -r command is executed on the restored /backup/verify.data file, and the result is stored in a third file, /backup/verify.test. Since the restore command must read the entire tape before restoring the initial two files, if they are restored successfully, it can be assumed that any other file can be restored successfully. The results of the two sum -r commands are compared. If they are the same, the two files were written and restored successfully, and the backup has been verified.
The tape is rewound before performing the initial read/write operations. It is then advanced to the first file and its contents are read. This step should be skipped for the first month the script is implemented, forcing a new serial number to be assigned to the tape. This is accomplished by editing the script, and changing the SKIP2 variable to the Julian date that is 31 days from the date the script was first implemented. This is the only editing of the script that is necessary. The actual read commands performed are sourced from the configuration file. The first file on tape, /backup/SerialNumber, contains the serial number for this tape. The serial number has the format hostname-dayofmonth. For instance, on the fifth day of the month on the host, foobar, the serial number created would be foobar-05.
If the restore of the serial number file fails (or if it was skipped), it can be assumed that this tape doesn't yet have a serial number assigned to it. In that case, a new serial number is created and assigned to this tape. If, however, a serial number file was found and restored, it can be assumed that there should also be a log file stored on this tape, so it is restored as well. The restore of the tape log file requires that the tape be advanced to the third file on the tape. The commands to advance to the third file and restore it are also sourced from the configuration file. Both these files must exist in order to have a successful backup. If either one does not exist, the backup is aborted by calling the Abort_Backup function.
To verify the tape has been changed since the previous backup, its serial number is compared to that of the tape used for the previous backup. A list of every file backed up is written to the /usr/spool/logs/backup directory in a file called backup.'dayofmonth'. For instance, a list of every file backed up on the fifth of the month would be stored in a file called backup.05 in the /usr/spool/logs/backup directory. After performing the backup, the tape serial number is appended to this file. This information is obtained from the file and compared to the serial number of the current tape. If they match, the backup is aborted by calling the Abort_Backup function.
If the serial number is different from the previous backup's tape, the tape serial number file is written to tape. The commands used to rewind the tape and write this file are sourced from the configuration file.
The second file written to tape is the actual backup data file. In some instances, however, it is necessary to perform some actions prior to beginning the backup. An example would be to shutdown Oracle during the backup. The commands that need to be executed before the backup are stored in the script /backup/backup.pre. This file is executed before the backup command if the PRE variable is set to 1 within the configuration file.
Next, the BTYPE variable is checked to determine the type of backup to perform, and the appropriate backup command is executed. The actual command is sourced from the configuration file.
If commands need to be executed after the backup, they are stored in the script /backup/backup.post. An example would be to restart Oracle after the backup. This file is executed at this time if the POST variable is set to 1 within the configuration file.
After the backup completes, the verification process is continued. The tape is rewound, and the two previously mentioned files are restored and compared. The result of the verification is recorded in the previously mentioned log files. If the backup was verified successful, the contents of /usr/spool/logs/backup/LastGoodBackup are replaced with the current date. This allows for easy identification of the last time that this host had a successful backup. If the verification fails, some diagnostic information is obtained to facilitate troubleshooting efforts.
The last file written to tape is the tape log file, /backup/TapeLog. The commands used to accomplish this are sourced from the configuration file. The last operation performed on the tape is to rewind it. This ensures the tape will be at the beginning the next time it is used. The last action taken by the script is to create an at job. The at job executes just before midnight. It resets the contents of the backup status file to Backup did not start. This sets the file up to report an accurate status of the next day's backup.
Now that I've thoroughly explained the script, I will discuss the contents of the configuration file. There are 18 variables set within the configuration file. This is where the differences in operating system commands are accounted for. All of the tape positioning, reading, and writing commands are specified in the configuration file. Also specified here are the directories that will be backed up. Again, make sure that backup is specified as the last directory. Also, make sure that the directories are listed relative to the root directory. A few other variables are specified in the configuration file. The comments within the configuration file are sufficient to explain setting these variables.
To begin using this script, copy the backup.sh script and the configuration files to the /backup directory. Next, edit the script and change the SKIP2 variable to be the Julian date 31 days from the date the script is first implemented. The format of the SKIP2 variable is YYYYJJJ. For example, the SKIP2 variable would be 2001032 for February 1, 2001.
Next, copy the sample configuration file for your operating system to /backup/backup.cfg, and edit /backup/backup.cfg to reflect the specifics of your installation. Run the script a few times using backup as the only directory just to prove the configuration file is properly configured. Delete the /usr/spool/logs/backup/backup.date file between test runs to prevent the script from thinking the same tape is being used on consecutive days.
After testing, edit the DAILY_DIRS variable to reflect the directories you want backed up. Lastly, edit root's crontab file to automate the backup process. A sample entry would be:
05 01 * * * /backup/backup.sh > \
This sets the script to be executed using the default /backup/backup.cfg configuration file every day at 0105, with STDOUT and STDERR redirected to /backup/errlog.
I've now explained the backup script and associated configuration file, and I hope you will find the script to be useful in your own environment.
About the Author
Jeff has been a UNIX systems administrator since 1997. He became Sun Certified on Solaris 7 in April of 2000. He is currently working as a contractor for Tmp Worldwide. Jeff can be reached at firstname.lastname@example.org.