This fixes some test failures recently introduced by gnulib updates prompted by recent changes to the GNU coding standards, which now advise to use quotes 'like this' or "like this" rather than `like this'. * NEWS: Document this. * README, README-hacking, doc/Makefile.am, scripts/backup.in: * scripts/backup.sh.in, scripts/dump-remind.in: * src/buffer.c, src/checkpoint.c, src/create.c, src/incremen.c: * src/misc.c, src/names.c, src/sparse.c, src/transform.c: * tests/incr02.at, tests/incremental.at, tests/multiv08.at: * tests/sparse04.at, tests/star/README, tests/update01.at: Quote 'like this' in comments. * src/tar.h: Quote "like this" in comments, when quoting English phrases rather than code. * configure.ac: * scripts/xsparse.c (get_var, read_xheader, main): * src/compare.c (diff_archive): * src/extract.c (prepare_to_extract): * src/tar.c (request_stdin, tar_set_quoting_style, doc, options) (set_subcommand_option, report_textual_dates, parse_opt) (decode_options, main): * src/xheader.c (decx): Quote 'like this' in diagnostics. * doc/tar.texi (list, warnings, override) (Selecting Archive Members, quoting styles, after, hard links) (Sparse Recovery, Multi-Volume Archives, label): Adjust documentation to match new output. * tests/backup01.at, tests/incr01.at, tests/incr04.at: * tests/label04.at, tests/label05.at, tests/link03.at: * tests/listed02.at, tests/multiv03.at, tests/multiv05.at: * tests/rename01.at, tests/rename02.at, tests/rename03.at: * tests/volume.at: Adjust tests to match new quoting behavior.
348 lines
8.6 KiB
Bash
348 lines
8.6 KiB
Bash
#! /bin/sh
|
|
# This program is part of GNU tar
|
|
# Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 1, or (at your option)
|
|
# any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
# 02110-1301, USA.
|
|
|
|
PROGNAME=`basename $0`
|
|
CONFIGPATH="$SYSCONFDIR/backup"
|
|
REMOTEBACKUPDIR="$SYSCONFDIR/tar-backup"
|
|
CONFIGFILE=${CONFIGPATH}/backup-specs
|
|
DIRLIST=${CONFIGPATH}/dirs
|
|
FILELIST=${CONFIGPATH}/files
|
|
LOGPATH=${CONFIGPATH}/log
|
|
|
|
# Default functions for running various magnetic tape commands
|
|
mt_begin() {
|
|
$MT -f "$1" retension
|
|
}
|
|
|
|
mt_rewind() {
|
|
$MT -f "$1" rewind
|
|
}
|
|
|
|
mt_offline() {
|
|
$MT -f "$1" offl
|
|
}
|
|
|
|
mt_status() {
|
|
$MT -f "$1" status
|
|
}
|
|
|
|
# The main configuration file may override any of these variables
|
|
MT_BEGIN=mt_begin
|
|
MT_REWIND=mt_rewind
|
|
MT_OFFLINE=mt_offline
|
|
MT_STATUS=mt_status
|
|
|
|
# Insure 'mail' is in PATH.
|
|
PATH="/usr/ucb:${PATH}"
|
|
export PATH
|
|
# Put startdate in the subject line of mailed report, since if it happens
|
|
# to run longer than 24 hours (as may be the case if someone forgets to put
|
|
# in the next volume of the tape in adequate time), the backup date won't
|
|
# appear too misleading.
|
|
startdate="`date`"
|
|
here="`pwd`"
|
|
# Save local hostname
|
|
localhost="`hostname | sed -e 's/\..*//' | tr A-Z a-z`"
|
|
|
|
# Produce a diagnostic output
|
|
message() {
|
|
if [ "$VERBOSE" != "" ]; then
|
|
if [ $VERBOSE -ge $1 ]; then
|
|
shift
|
|
echo "$@" >&2
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Bail out and exit.
|
|
bailout() {
|
|
echo "$PROGNAME: $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
# Return current date
|
|
now() {
|
|
#IF_DATE_FORMAT_OK
|
|
date +%Y-%m-%d
|
|
#ELSE_DATE_FORMAT_OK
|
|
LC_ALL=C date | \
|
|
sed 's/[^ ]* *\([^ ]*\) *\([^ ]*\).* \([^ ]*\)$/\3-\1-\2/
|
|
/-[0-9]$/s/\([0-9]\)$/0\1/
|
|
/Jan/{s/Jan/01/p;q;}
|
|
/Feb/{s/Feb/02/p;q;}
|
|
/Mar/{s/Mar/03/p;q;}
|
|
/Apr/{s/Apr/04/p;q;}
|
|
/May/{s/May/05/p;q;}
|
|
/Jun/{s/Jun/06/p;q;}
|
|
/Jul/{s/Jul/07/p;q;}
|
|
/Aug/{s/Aug/08/p;q;}
|
|
/Sep/{s/Sep/09/p;q;}
|
|
/Oct/{s/Oct/10/p;q;}
|
|
/Nov/{s/Nov/11/p;q;}
|
|
/Dec/{s/Dec/12/p;q;}'
|
|
#ENDIF_DATE_FORMAT_OK
|
|
}
|
|
|
|
# Bail out if we don't have root privileges.
|
|
test_root() {
|
|
if [ ! -w ${ROOT_FS-/} ]; then
|
|
bailout "The backup must be run as root or else some files will fail to be dumped."
|
|
fi
|
|
}
|
|
|
|
root_fs() {
|
|
echo "${ROOT_FS}$1" | tr -s /
|
|
}
|
|
|
|
advice() {
|
|
echo "Directory $1 is not found." >&2
|
|
cat >&2 <<EOF
|
|
The following directories and files are needed for the backup to function:
|
|
|
|
1. Directory with configuration files and file lists:
|
|
$CONFIGPATH
|
|
2. Directory for backup log files
|
|
$LOGPATH
|
|
3. Main configuration file
|
|
$CONFIGFILE
|
|
|
|
Please, create these and invoke the script again.
|
|
EOF
|
|
}
|
|
|
|
init_common() {
|
|
# Check if the necessary directories exist
|
|
if [ ! -d $CONFIGPATH ]; then
|
|
advice $CONFIGPATH
|
|
exit 1
|
|
fi
|
|
if [ ! -d $LOGPATH ]; then
|
|
if mkdir $LOGPATH; then
|
|
:
|
|
else
|
|
advice $LOGPATH
|
|
exit 1
|
|
fi
|
|
fi
|
|
# Get the values of BACKUP_DIRS, BACKUP_FILES, and other variables.
|
|
if [ ! -r $CONFIGFILE ]; then
|
|
echo "$PROGNAME: cannot read $CONFIGFILE. Stop." >&2
|
|
exit 1
|
|
fi
|
|
. $CONFIGFILE
|
|
|
|
# Environment sanity check
|
|
|
|
test_root
|
|
|
|
if [ x"${ADMINISTRATOR}" = x ]; then
|
|
bailout "ADMINISTRATOR not defined"
|
|
fi
|
|
|
|
[ x"$TAR" = x ] && TAR=tar
|
|
[ x"$SLEEP_TIME" = x ] && SLEEP_TIME=60
|
|
|
|
if [ x$VOLNO_FILE = x ]; then
|
|
bailout "VOLNO_FILE not specified"
|
|
fi
|
|
|
|
if [ -r $DIRLIST ]; then
|
|
BACKUP_DIRS="$BACKUP_DIRS `cat $DIRLIST`"
|
|
fi
|
|
if [ -r $FILELIST ]; then
|
|
BACKUP_FILES="$BACKUP_FILES `cat $FILELIST`"
|
|
fi
|
|
|
|
if [ \( x"$BACKUP_DIRS" = x \) -a \( x"$BACKUP_FILES" = x \) ]; then
|
|
bailout "Neither BACKUP_DIRS nor BACKUP_FILES specified"
|
|
fi
|
|
if [ -z "$RSH" ]; then
|
|
RSH=rsh
|
|
MT_RSH_OPTION=
|
|
else
|
|
MT_RSH_OPTION="--rsh-command=$RSH"
|
|
fi
|
|
if [ -z "$TAPE_FILE" ]; then
|
|
TAPE_FILE=/dev/tape
|
|
fi
|
|
|
|
# If TAPE_FILE is a remote device, update mt invocation accordingly
|
|
: ${MT:=mt}
|
|
case $TAPE_FILE in
|
|
*:*) MT="$MT $MT_RSH_OPTION";;
|
|
*) ;;
|
|
esac
|
|
|
|
POSIXLY_CORRECT=1
|
|
export POSIXLY_CORRECT
|
|
}
|
|
|
|
init_backup() {
|
|
init_common
|
|
TAR_PART1="${TAR} -c --format=gnu --multi-volume --one-file-system --sparse --volno-file=${VOLNO_FILE}"
|
|
if [ "x$XLIST" != x ]; then
|
|
TAR_PART1="${TAR_PART1} \`test -r $REMOTEBACKUPDIR/$XLIST && echo \"--exclude-from $REMOTEBACKUPDIR/$XLIST\"\`"
|
|
fi
|
|
if [ "$RSH_COMMAND" != "" ]; then
|
|
TAR_PART1="${TAR_PART1} --rsh-command=$RSH_COMMAND"
|
|
fi
|
|
if [ x$BLOCKING != x ]; then
|
|
TAR_PART1="${TAR_PART1} --blocking=${BLOCKING}"
|
|
fi
|
|
|
|
# Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs
|
|
if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then
|
|
TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
|
|
fi
|
|
# Set logfile name
|
|
# Logfile name should be in the form 'log-1993-03-18-level-0'
|
|
# They go in the directory '@sysconfdir@/log'.
|
|
# i.e. year-month-date. This format is useful for sorting by name, since
|
|
# logfiles are intentionally kept online for future reference.
|
|
LOGFILE="${LOGPATH}/log-`now`-level-${DUMP_LEVEL}"
|
|
}
|
|
|
|
init_restore() {
|
|
init_common
|
|
# FIXME: Replace --list with --extract
|
|
TAR_PART1="${TAR} --extract --multi-volume"
|
|
if [ "$RSH_COMMAND" != "" ]; then
|
|
TAR_PART1="${TAR_PART1} --rsh-command=$RSH_COMMAND"
|
|
fi
|
|
if [ x$BLOCKING != x ]; then
|
|
TAR_PART1="${TAR_PART1} --blocking=${BLOCKING}"
|
|
fi
|
|
|
|
# Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs
|
|
if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then
|
|
TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
|
|
fi
|
|
LOGFILE="${LOGPATH}/restore-`now`"
|
|
}
|
|
|
|
wait_time() {
|
|
if [ "${1}" != "now" ]; then
|
|
if [ "${1}x" != "x" ]; then
|
|
spec="${1}"
|
|
else
|
|
spec="${BACKUP_HOUR}"
|
|
fi
|
|
|
|
pausetime="`date | awk -v spec=\"${spec}\" '
|
|
BEGIN {
|
|
split(spec, time, ":")
|
|
}
|
|
{
|
|
split($4, now, ":")
|
|
diff = 3600 * (time[1] - now[1]) + 60 * (time[2] - now[2]);
|
|
if (diff < 0)
|
|
diff += 3600 * 24
|
|
print diff
|
|
}'`"
|
|
clear
|
|
echo "${SLEEP_MESSAGE}"
|
|
sleep "${pausetime}"
|
|
fi
|
|
}
|
|
|
|
level_log_name() {
|
|
echo "$REMOTEBACKUPDIR/${1}.level-${2-$DUMP_LEVEL}"
|
|
}
|
|
|
|
# Prepare a temporary level logfile
|
|
# usage: make_level_log HOSTNAME
|
|
make_level_log() {
|
|
if [ "z${localhost}" != "z$1" ] ; then
|
|
$RSH "$1" mkdir $REMOTEBACKUPDIR > /dev/null 2>&1
|
|
$RSH "$1" rm -f `level_log_name temp`
|
|
else
|
|
mkdir $REMOTEBACKUPDIR > /dev/null 2>&1
|
|
rm -f `level_log_name temp`
|
|
fi
|
|
}
|
|
|
|
# Rename temporary log
|
|
# usage: flush_level_log HOSTNAME FSNAME
|
|
flush_level_log() {
|
|
message 10 "RENAME: `level_log_name temp` --> `level_log_name $2`"
|
|
if [ "z${localhost}" != "z$1" ] ; then
|
|
$RSH "$1" mv -f `level_log_name temp` "`level_log_name $2`"
|
|
else
|
|
mv -f `level_log_name temp` "`level_log_name $2`"
|
|
fi
|
|
}
|
|
|
|
# Return the timestamp of the last backup.
|
|
# usage: get_dump_time LEVEL
|
|
get_dump_time() {
|
|
ls -r ${LOGPATH}/log-*-level-$1 \
|
|
| head -n 1 \
|
|
| sed "s,.*log-\(.*\)-level-$1,\1,"
|
|
}
|
|
|
|
# Do actual backup on a host
|
|
# usage: backup_host HOSTNAME [TAR_ARGUMENTS]
|
|
backup_host() {
|
|
message 10 "ARGS: $@"
|
|
rhost=$1
|
|
shift
|
|
if [ "z${localhost}" != "z$rhost" ] ; then
|
|
$RSH "$rhost" ${TAR_PART1} -f "${localhost}:${TAPE_FILE}" $@
|
|
else
|
|
# Using 'sh -c exec' causes nested quoting and shell substitution
|
|
# to be handled here in the same way rsh handles it.
|
|
CMD="exec ${TAR_PART1} -f \"${TAPE_FILE}\" $@"
|
|
message 10 "CMD: $CMD"
|
|
sh -c "$CMD"
|
|
message 10 "RC: $?"
|
|
fi
|
|
}
|
|
|
|
print_level() {
|
|
if [ ${1-$DUMP_LEVEL} -eq 0 ]; then
|
|
echo "Full"
|
|
else
|
|
echo "Level ${1-$DUMP_LEVEL}"
|
|
fi
|
|
}
|
|
|
|
prev_level() {
|
|
print_level `expr $DUMP_LEVEL - 1` | tr A-Z a-z
|
|
}
|
|
|
|
remote_run() {
|
|
rhost=$1
|
|
shift
|
|
message 10 "REMOTE $rhost: $@"
|
|
if [ "x$rhost" != "x${localhost}" ] ; then
|
|
$RSH "${rhost}" "$@"
|
|
else
|
|
$*
|
|
fi
|
|
}
|
|
|
|
license() {
|
|
cat - <<EOF
|
|
Copyright (C) 2006 Free Software Foundation, Inc.
|
|
This is free software. You may redistribute copies of it under the terms of
|
|
the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.
|
|
There is NO WARRANTY, to the extent permitted by law.
|
|
EOF
|
|
}
|