#!/bin/ksh ### # This script is called by an Amanda client to run GNU tar. We look # through the arguments for what is being processed and (optionally) # run extra things before and/or after GNU tar. # # Remember that this script runs as root under the Amanda runtar program. ### # Program name PN=${0##*/} AWK=/usr/bin/awk GREP=/usr/bin/grep SED=/usr/bin/sed FSTAB=/etc/fstab integer argc=1 if [[ -z $DEBUG ]] then # log=/var/lib/amanda/$PN.$$ # <<< change as needed log=/var/lib/amanda/$PN.log # <<< change as needed # rm -f $log # I use this only for $PN.$$, not for PN.log else log=/dev/tty fi GTAR=${GTAR:-/bin/gtar} # <<< change as needed ### # Define functions to be called at various execution points. The name # determines when the function is called: # # pre_estimate_* called before a GNU tar estimate # pre_real_* called before a GNU tar real run # run_estimate_* called to run a GNU tar estimate # run_real_* called to run a GNU tar real run # post_estimate_* called after a GNU tar estimate # post_real_* called after a GNU tar real run # # The rest of the function name comes from the directory being processed # by converting everything other than alphanumerics and the underscore # to an underscore, e.g. /home/abc becomes _home_abc. # # If a function does not exist for a particular execution point, nothing # special is done. ### ### # The following set of functions (*_some_db) show how you might set # up the execution points to shut down and restart a database around # the Amanda steps. ### ### # This function is called before we get the estimate of /some/db. ### function pre_estimate__some_db { print "$PN: shutting down the database" >> $log } ### # This function is called after we get the estimate of /some/db. ### function post_estimate__some_db { print "$PN: starting the database" >> $log } ### # This function is called before we dump /some/db. ### function pre_real__some_db { print "$PN: shutting down the database" >> $log } ### # This function is called after we dump /some/db. ### function post_real__some_db { print "$PN: starting the database" >> $log } ### # The following set of function are called to process groups of home # directories. The Amanda disklist entries are "faked" to indicate # a range of directories to be processed instead of a single item. # For instance, /home/HomeAC (which should not actually exist) would be # converted into all the directories in /home that start with a, b or c. # # This might be used to get around the current limit on the number of # "disks" Amanda can handle on a given client or to make it easier to # set up groups of things to back up without exclusion lists. ### function run_estimate__home_HomeAC { print "$PN: preparing to estimate homes a* through c*" >> $log do_home a c "$@" return $? } function run_real__home_HomeAC { print "$PN: preparing to dump homes a* through c*" >> $log do_home a c "$@" return $? } ### # The first and second args to do_home are the start and end names. # The remaining args are passed to GNU tar pretty much as is, except # --directory which is shortened to the home directory base. ### function do_home { ### # Copy all the args except the last one (which should be ".") and # tweak the --directory value. ### start=$1 shift end=$1 shift integer do_directory=0 new_args= integer first_arg=1 for arg do if ((first_arg == 0)) then a=$last_arg if ((do_directory)) then base_directory=${last_arg%/*} a=$base_directory do_directory=0 elif [[ X"$last_arg" = X"--directory" ]] then do_directory=1 # --directory dir-to-back-up fi new_args="$new_args $a" fi first_arg=0 last_arg=$arg done if [[ X"$base_directory" = X"" ]] then print "$PN: cannot parse args: --directory not found" >> $log print "$PN: cannot parse args: --directory not found" 1>&2 return 1 elif [[ X"$last_arg" != X"." ]] then print "$PN: cannot parse args: . not at end" >> $log print "$PN: cannot parse args: . not at end" 1>&2 return 1 fi \cd $base_directory || return 1 typeset -i26 s e s=26#$start e=26#$end integer found_homes=0 while (($s <= $e)) do for dir in $(ls -1d ${s#26#}* 2>/dev/null) do if [[ -d $dir ]] then new_args="$new_args $dir" found_homes=1 fi done ((s = s + 1)) done \cd - > /dev/null if ((found_homes == 0)) then print "$PN: no homes to process in range $start..$end" >> $log print "$PN: no homes to process in range $start..$end" 1>&2 return 1 fi set -- $new_args print "$PN: running $GTAR" "$@" >> $log $DEBUG $GTAR "$@" } ### # Start of main code. ### ### # Set up a log file. ### print "$PN: start: $(date)" >> $log print "$PN: args:" "$@" >> $log ### # Find the directory Amanda is asking us to back up. Also figure out # if we are doing an estimate or the real thing. ### integer get_directory=0 integer get_file=0 directory_arg= file_arg= for arg do if ((get_directory)) then directory_arg=$arg get_directory=0 elif ((get_file)) then file_arg=$arg get_file=0 elif [[ X"$arg" = X"--directory" ]] then get_directory=1 # --directory dir-to-back-up elif [[ X"$arg" = X"--file" ]] then get_file=1 # --file file-to-write-to fi done print "$PN: directory: $directory_arg" >> $log print "$PN: file: $file_arg" >> $log if [[ X"$file_arg" = X"-" ]] then type=real # real dump if output is stdout elif [[ X"$file_arg" = X"/dev/null" ]] then type=estimate # estimate if output is /dev/null else type=unknown # no idea what is going on fi ### # Make the directory name into something we can use as part of a function # name by converting the slashes to underscores. Hopefully there is # not anything else annoying in the name. ### d=$(print $directory_arg | $SED 's/[^a-zA-Z0-9_]/_/g') ### # See if there is something to be done before we call GNU tar. ### if [[ -n $(whence pre_${type}_$d) ]] then print "$PN: running pre_${type}_$d" >> $log pre_${type}_$d else print "$PN: pre_${type}_$d not found so nothing special run" >> $log fi ### # Run GNU tar or a private function. ### # Determine if the directory is on a vfat filesystem # # Substitute / with \/ in directory_arg s=$(print $directory_arg | $SED 's/\//\\\//g') # s is used as a search string for awk to find the line # in fstab wich contains an entry for directory_arg. # awk will then print the 3rd field, which indicates # the filesystem type of directory_arg. # Of course, you should not have commented lines in # your fstab, which specify a different filesystem type # than an uncommented one for the same partition ;-) if [[ X"$directory_arg" = X"/" ]] then fstype="ext2" else fstype=`$AWK '/'"$s"'/ {print $3}' $FSTAB` fi if [[ -n $(whence run_${type}_$d) ]] then print "$PN: running run_${type}_$d" >> $log run_${type}_$d "$@" exit_code=$? else # We will run gtar # If the filesystem type is vfat, then we delete "--listed-incremental filename" # Otherwise, we delete "--incremental --newer-mtime date". if [[ X"$fstype" = X"vfat" ]] then for arg do if ((argc == 1)) then # clear the arg list set -- fi # The 4th and 5th parameters are --listed-incremental and filename respectively. if ((argc != 4 && argc != 5)) then set -- "$@" "$arg" fi ((argc = argc + 1)) done # If the filesystem type is ext2, or something else, we run gtar with the standard # parameter list. elif [[ X"$fstype" = X"ext2" ]] then for arg do if ((argc == 1)) then # clear the arg list set -- fi # The 6th, 7th and 8th parameters are --incremental, --newer-mtime and date respectively. if ((argc != 6 && argc != 7 && argc != 8)) then set -- "$@" "$arg" fi ((argc = argc + 1)) done else for arg do if ((argc == 1)) then # clear the arg list set -- fi # The 6th, 7th and 8th parameters are --incremental, --newer-mtime and date respectively. if ((argc != 6 && argc != 7 && argc != 8)) then set -- "$@" "$arg" fi ((argc = argc + 1)) done fi print "$PN: running $GTAR $@" >> $log $DEBUG $GTAR "$@" exit_code=$? fi ### # See if there is something to be done after we ran GNU tar. ### print "$PN: looking for post_${type}_$d" >> $log if [[ -n $(whence post_${type}_$d) ]] then print "$PN: running post_${type}_$d" >> $log post_${type}_$d else print "$PN: post_${type}_$d not found so nothing special run" >> $log fi ### # Exit with the GNU tar exit code. ### print "$PN: end: $(date)" >> $log exit $exit_code