#!/bin/sh ############################################################################### ## (c) 2003 Samuel Abels ## This script will backup a list of all files to a tape device. ## The tape will be deleted before. ## ## Requires: mt, mt-dds (=dds2tar), tar. ## ## Changelog: 2003-04-05 S. Abels ## Initial. ## 2003-04-06 S. Abels ## Error detection fix. ## Faster backup list creation. ## Multiple files fix. ## 2003-04-06 S. Abels ## Optional tape deletion. ## 2003-04-07 S. Abels ## File size calculation fix. ## Added an extra verbosity level. ## 2003-11-08 S. Abels ## Date evaluation fix. ## Some small cleanups. ############################################################################### ## TIMESTAMP='date +%s%N' # Change this if you don't use GNU-date. DATE='date "+%F %R"' # Change this if you don't use GNU-date. ITEMPFILE="/tmp/includelist`eval "$TIMESTAMP"`" XTEMPFILE="/tmp/excludelist`eval "$TIMESTAMP"`" ############################################################################### # Function to display the correct usage if the user tries to use an # unsupported option. ############################################################################### printUsage() { echo "Syntax: $0 [-y] [-e excludes] files" 1>&2 echo >&2 echo -e "\tfiles\t\tA list of files/directories to backup." >&2 echo -e "\t-d device\tYour backup device. Default is /dev/nst0." >&2 echo -e "\t-l kilobytes\tTape length in kilobytes. Default is 4 000 000 (4 GB)." >&2 echo -e "\t-e excludes\tFiles/directories to exclude from the backup." >&2 echo -e "\t-D\t\tDelete the tape before writing." >&2 echo -e "\t-y\t\tAssume YES to all questions." >&2 echo -e "\t-v\t\tVerbose mode." >&2 echo -e "\t-V\t\tMore verbose mode." >&2 echo -e "\t-vv\t\tExcessive verbose mode." >&2 } ############################################################################### # Use getopt to determine the allowed options. ############################################################################### getopt "d:l:e:DVyvv" $* 1>/dev/null 2>&1 if [ $? != 0 ]; then printUsage exit 1 fi ############################################################################### # This for-loop parses the command line for options and sets a variable # accordingly. ############################################################################### # Default options. DELTAPE=0 CONFIRMED=0 VERBOSE=0 DEVICE="/dev/nst0" TAPELEN=4000000 for i in "$@"; do case $i in "-e") EXCLUDEFILES="$2" shift 2;; "-d") DEVICE="$2" shift 2;; "-l") TAPELEN="$2" shift 2;; "-D") DELTAPE=1 shift;; "-y") CONFIRMED=1 shift;; "-v") VERBOSE=1 shift;; "-V") VERBOSE=2 shift;; "-vv") VERBOSE=3 shift;; # End of options, just command arguments left. "--") shift break;; esac done FILES=$* ############################################################################### # Let the user know what will be done. ############################################################################### # Verbosity level [ $VERBOSE -eq 1 ] && echo "Using verbose mode." [ $VERBOSE -eq 2 ] && echo "Using more verbose mode." [ $VERBOSE -eq 3 ] && echo "Using excessive verbose mode." # List files. echo "Backing up:" echo "$FILES" | sed 's/ /\\ /g' | sed 's/\\ /\n/g' | while read CURFILE; do echo " $CURFILE" done echo echo "Excluding: " echo "$EXCLUDEFILES" | sed 's/ /\\ /g' | sed 's/\\ /\n/g' | while read CURFILE; do echo " $CURFILE" done echo echo -n "Backup device is $DEVICE." [ $DELTAPE -ne 1 ] && echo -ne "\nThe tape will be erased before writing." if [ $CONFIRMED -ne 1 ]; then echo -n " Continue (y/N)? " read -n1 CONFIRMATION if [ "$CONFIRMATION" != "y" ]; then echo -e "\nAborted." >&2 exit 0 fi fi echo ############################################################################### # Create a full list of files to backup. ############################################################################### echo -n "`eval "$DATE"`: Writing backuplist to $ITEMPFILE... " # 1. Create a list of files to include. # 2. Append a list of excludefiles to THE SAME FILE. # 3. Remove double lines completely. That means, the excludes are gone. if [ $VERBOSE -eq 0 ]; then du -ab $FILES | cut -f2- > "$XTEMPFILE" 2>/dev/null \ && du -ab $EXCLUDEFILES | cut -f2- >> "$XTEMPFILE" 2>/dev/null \ && cat "$XTEMPFILE" | sort | uniq -u > "$ITEMPFILE" 2>/dev/null ERR=$? fi if [ $VERBOSE -eq 1 -o $VERBOSE -eq 2 ]; then du -ab $FILES | cut -f2- > "$XTEMPFILE" \ && du -ab $EXCLUDEFILES | cut -f2- >> "$XTEMPFILE" \ && cat "$XTEMPFILE" | sort | uniq -u > "$ITEMPFILE" ERR=$? fi if [ $VERBOSE -eq 3 ]; then echo du -ab $FILES | cut -f2- > "$XTEMPFILE" \ && du -ab $EXCLUDEFILES | cut -f2- >> "$XTEMPFILE" \ && cat "$XTEMPFILE" | sort | uniq -u | tee "$ITEMPFILE" ERR=$? fi rm "$XTEMPFILE" >/dev/null 2>&1 # Fetch errors. [ $ERR -ne 0 ] && echo -e "Failed!\nError: Failed to create backuplist '$ITEMPFILE'." >&2 && exit 1 echo "done." # Warning on empty files. [ ! -s "$ITEMPFILE" ] && echo "Warning: Backuplist is empty. '$ITEMPFILE'" >&2 # Count filesizes. SUM=0 echo -n "`eval "$DATE"`: Precalculating sizes... " for SIZE in `cat "$ITEMPFILE" | while read FILE; do echo \`ls -la "$FILE" | awk '{print $5}'\`; done`; do SUM=`expr $SUM + $SIZE` done echo "done." # Let the user decide if this is ok. SUM=`expr $SUM / 1024` echo -n "Size is $SUM kilobytes." if [ $CONFIRMED -ne 1 ]; then echo -n " Continue (y/N)? " read -n1 CONFIRMATION if [ "$CONFIRMATION" != "y" ]; then echo -e "\nAborted." >&2 exit 0 fi fi echo ############################################################################### # Rewind the tape using mt. ############################################################################### echo -n "`eval "$DATE"`: Rewinding tape... " if [ $VERBOSE -eq 0 ]; then mt -f "$DEVICE" rewind >/dev/null 2>&1 ERR=$? fi if [ $VERBOSE -eq 1 ]; then mt -f "$DEVICE" rewind >/dev/null ERR=$? fi if [ $VERBOSE -eq 2 -o $VERBOSE -eq 3 ]; then mt -f "$DEVICE" rewind ERR=$? fi # Fetch errors. [ $ERR -ne 0 ] && echo -e "Failed!\n`eval "$DATE"`: Error: Failed to rewind the tape." >&2 && exit 1 echo "done." ############################################################################### # Delete the tape using mt. ############################################################################### if [ $DELTAPE -eq 1 ]; then # Deletion starts here. echo -n "`eval "$DATE"`: Erasing tape... " if [ $VERBOSE -eq 0 ]; then mt -f "$DEVICE" erase >/dev/null 2>&1 ERR=$? fi if [ $VERBOSE -eq 1 ]; then mt -f "$DEVICE" erase >/dev/null ERR=$? fi if [ $VERBOSE -eq 2 -o $VERBOSE -eq 3 ]; then mt -f "$DEVICE" erase ERR=$? fi # Fetch errors. [ $ERR -ne 0 ] && echo -e "Failed!\n`eval "$DATE"`: Error: Failed to erase the tape." >&2 && exit 1 echo "done." # Re-rewind the tape echo -n "`eval "$DATE"`: Rewinding tape... " if [ $VERBOSE -eq 0 ]; then mt -f "$DEVICE" rewind >/dev/null 2>&1 ERR=$? fi if [ $VERBOSE -eq 1 ]; then mt -f "$DEVICE" rewind >/dev/null ERR=$? fi if [ $VERBOSE -eq 2 -o $VERBOSE -eq 3 ]; then mt -f "$DEVICE" rewind ERR=$? fi # Fetch errors. [ $ERR -ne 0 ] && echo -e "Failed!\n`eval "$DATE"`: Error: Failed to rewind the tape." >&2 && exit 1 echo "done." fi ############################################################################### # Enable the tape's hardware compression. ############################################################################### echo -n "`eval "$DATE"`: Enabling tape hardware compression... " if [ $VERBOSE -eq 0 ]; then mt-dds -f "$DEVICE" comp-on >/dev/null 2>&1 ERR=$? fi if [ $VERBOSE -eq 1 ]; then mt-dds -f "$DEVICE" comp-on >/dev/null ERR=$? fi if [ $VERBOSE -eq 2 -o $VERBOSE -eq 3 ]; then mt-dds -f "$DEVICE" comp-on ERR=$? fi # Fetch errors. [ $ERR -ne 0 ] && echo -e "Failed!\n`eval "$DATE"`: Error: Enabling tape hardware compression didn't work." >&2 && exit 1 echo "done." ############################################################################### # Write the backup to the device. ############################################################################### echo "`eval "$DATE"`: Writing files from $ITEMPFILE to $DEVICE..." if [ $VERBOSE -eq 0 ]; then tar --tape-length $TAPELEN --no-recursion --totals -vcf "$DEVICE" -T "$ITEMPFILE" >/dev/null 2>&1 ERR=$? fi if [ $VERBOSE -eq 1 ]; then tar --tape-length $TAPELEN --no-recursion --totals -vcf "$DEVICE" -T "$ITEMPFILE" >/dev/null ERR=$? fi if [ $VERBOSE -eq 2 -o $VERBOSE -eq 3 ]; then tar --tape-length $TAPELEN --no-recursion --totals -vcf "$DEVICE" -T "$ITEMPFILE" ERR=$? fi # Fetch errors. [ $ERR -ne 0 ] && echo "`eval "$DATE"`: Error: Writing the backup failed!" >&2 && exit 1 echo "`eval "$DATE"`: Backup finished successfully!" ############################################################################### # Delete the tempfile. ############################################################################### echo -n "`eval "$DATE"`: Deleting tempfile... " rm "$ITEMPFILE" >/dev/null 2>&1 if [ $? -ne 0 ]; then echo "Failed!" exit 1 fi echo "done."