re-mark 1.29b-2 as not yet uploaded (merge madness!)
[debian/tar] / scripts / backup.sh.in
1 #! /bin/sh
2 # Make backups.
3
4 # Copyright 2004-2006, 2013-2014, 2016 Free Software Foundation, Inc.
5
6 # This file is part of GNU tar.
7
8 # GNU tar is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 3 of the License, or
11 # (at your option) any later version.
12
13 # GNU tar is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU General Public License for more details.
17
18 # You should have received a copy of the GNU General Public License
19 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
21 PROGNAME=`basename $0`
22 CONFIGPATH="$SYSCONFDIR/backup"
23 REMOTEBACKUPDIR="$SYSCONFDIR/tar-backup"
24 CONFIGFILE=${CONFIGPATH}/backup-specs
25 DIRLIST=${CONFIGPATH}/dirs
26 FILELIST=${CONFIGPATH}/files
27 LOGPATH=${CONFIGPATH}/log
28
29 # Default functions for running various magnetic tape commands
30 mt_begin() {
31     $MT -f "$1" retension
32 }
33
34 mt_rewind() {
35     $MT -f "$1" rewind
36 }
37
38 mt_offline() {
39     $MT -f "$1" offl
40 }
41
42 mt_status() {
43     $MT -f "$1" status
44 }
45
46 # The main configuration file may override any of these variables
47 MT_BEGIN=mt_begin
48 MT_REWIND=mt_rewind
49 MT_OFFLINE=mt_offline
50 MT_STATUS=mt_status
51
52 # Insure 'mail' is in PATH.
53 PATH="/usr/ucb:${PATH}"
54 export PATH
55 # Put startdate in the subject line of mailed report, since if it happens
56 # to run longer than 24 hours (as may be the case if someone forgets to put
57 # in the next volume of the tape in adequate time), the backup date won't
58 # appear too misleading.
59 startdate="`date`"
60 here="`pwd`"
61 # Save local hostname
62 localhost="`hostname | sed -e 's/\..*//' | tr A-Z a-z`"
63
64 # Produce a diagnostic output
65 message() {
66     if [ "$VERBOSE" != "" ]; then
67         if [ $VERBOSE -ge $1 ]; then
68             shift
69             echo "$@" >&2
70         fi
71     fi
72 }
73
74 # Bail out and exit.
75 bailout() {
76     echo "$PROGNAME: $*" >&2
77     exit 1
78 }
79
80 # Return current date
81 now() {
82 #IF_DATE_FORMAT_OK
83         date +%Y-%m-%d
84 #ELSE_DATE_FORMAT_OK
85         LC_ALL=C date | \
86         sed 's/[^ ]*  *\([^ ]*\)  *\([^ ]*\).* \([^ ]*\)$/\3-\1-\2/
87             /-[0-9]$/s/\([0-9]\)$/0\1/
88             /Jan/{s/Jan/01/p;q;}
89             /Feb/{s/Feb/02/p;q;}
90             /Mar/{s/Mar/03/p;q;}
91             /Apr/{s/Apr/04/p;q;}
92             /May/{s/May/05/p;q;}
93             /Jun/{s/Jun/06/p;q;}
94             /Jul/{s/Jul/07/p;q;}
95             /Aug/{s/Aug/08/p;q;}
96             /Sep/{s/Sep/09/p;q;}
97             /Oct/{s/Oct/10/p;q;}
98             /Nov/{s/Nov/11/p;q;}
99             /Dec/{s/Dec/12/p;q;}'
100 #ENDIF_DATE_FORMAT_OK
101 }
102
103 # Bail out if we don't have root privileges.
104 test_root() {
105     if [ ! -w ${ROOT_FS-/} ]; then
106         bailout "The backup must be run as root or else some files will fail to be dumped."
107     fi
108 }
109
110 root_fs() {
111     echo "${ROOT_FS}$1" | tr -s /
112 }
113
114 advice() {
115     echo "Directory $1 is not found." >&2
116     cat >&2 <<EOF
117 The following directories and files are needed for the backup to function:
118
119 1. Directory with configuration files and file lists:
120 $CONFIGPATH
121 2. Directory for backup log files
122 $LOGPATH
123 3. Main configuration file
124 $CONFIGFILE
125
126 Please, create these and invoke the script again.
127 EOF
128 }
129
130 init_common() {
131     # Check if the necessary directories exist
132     if [ ! -d $CONFIGPATH ]; then
133         advice $CONFIGPATH
134         exit 1
135     fi
136     if [ ! -d $LOGPATH ]; then
137         if mkdir $LOGPATH; then
138             :
139         else
140             advice $LOGPATH
141             exit 1
142         fi
143     fi
144     # Get the values of BACKUP_DIRS, BACKUP_FILES, and other variables.
145     if [ ! -r $CONFIGFILE ]; then
146         echo "$PROGNAME: cannot read $CONFIGFILE. Stop." >&2
147         exit 1
148     fi
149     . $CONFIGFILE
150
151     # Environment sanity check
152
153     test_root
154
155     if [ x"${ADMINISTRATOR}" = x ]; then
156         bailout "ADMINISTRATOR not defined"
157     fi
158
159     [ x"$TAR" = x ] && TAR=tar
160     [ x"$SLEEP_TIME" = x ] && SLEEP_TIME=60
161
162     if [ x$VOLNO_FILE = x ]; then
163         bailout "VOLNO_FILE not specified"
164     fi
165
166     if [ -r $DIRLIST ]; then
167         BACKUP_DIRS="$BACKUP_DIRS `cat $DIRLIST`"
168     fi
169     if [ -r $FILELIST ]; then
170         BACKUP_FILES="$BACKUP_FILES `cat $FILELIST`"
171     fi
172
173     if [ \( x"$BACKUP_DIRS" = x \) -a \( x"$BACKUP_FILES" = x \) ]; then
174         bailout "Neither BACKUP_DIRS nor BACKUP_FILES specified"
175     fi
176     if [ -z "$RSH" ]; then
177         RSH=rsh
178         MT_RSH_OPTION=
179     else
180         MT_RSH_OPTION="--rsh-command=$RSH"
181     fi
182     if [ -z "$TAPE_FILE" ]; then
183         TAPE_FILE=/dev/tape
184     fi
185
186     # If TAPE_FILE is a remote device, update mt invocation accordingly
187     : ${MT:=mt}
188     case $TAPE_FILE in
189     *:*) MT="$MT $MT_RSH_OPTION";;
190     *)   ;;
191     esac
192
193     POSIXLY_CORRECT=1
194     export POSIXLY_CORRECT
195 }
196
197 init_backup() {
198     init_common
199     TAR_PART1="${TAR} -c --format=gnu --multi-volume --one-file-system --sparse --volno-file=${VOLNO_FILE}"
200     if [ "x$XLIST" != x ]; then
201         TAR_PART1="${TAR_PART1} \`test -r $REMOTEBACKUPDIR/$XLIST && echo \"--exclude-from $REMOTEBACKUPDIR/$XLIST\"\`"
202     fi
203     if [ "$RSH_COMMAND" != "" ]; then
204         TAR_PART1="${TAR_PART1} --rsh-command=$RSH_COMMAND"
205     fi
206     if [ x$BLOCKING != x ]; then
207         TAR_PART1="${TAR_PART1} --blocking=${BLOCKING}"
208     fi
209
210     # Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs
211     if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then
212         TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
213     fi
214     # Set logfile name
215     # Logfile name should be in the form 'log-1993-03-18-level-0'
216     # They go in the directory '@sysconfdir@/log'.
217     # i.e. year-month-date.  This format is useful for sorting by name, since
218     # logfiles are intentionally kept online for future reference.
219     LOGFILE="${LOGPATH}/log-`now`-level-${DUMP_LEVEL}"
220 }
221
222 init_restore() {
223     init_common
224     # FIXME: Replace --list with --extract
225     TAR_PART1="${TAR} --extract --multi-volume"
226     if [ "$RSH_COMMAND" != "" ]; then
227         TAR_PART1="${TAR_PART1} --rsh-command=$RSH_COMMAND"
228     fi
229     if [ x$BLOCKING != x ]; then
230         TAR_PART1="${TAR_PART1} --blocking=${BLOCKING}"
231     fi
232
233     # Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs
234     if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then
235         TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
236     fi
237     LOGFILE="${LOGPATH}/restore-`now`"
238 }
239
240 wait_time() {
241     if [ "${1}" != "now" ]; then
242         if [ "${1}x" != "x" ]; then
243             spec="${1}"
244         else
245             spec="${BACKUP_HOUR}"
246         fi
247
248         pausetime="`date | awk -v spec=\"${spec}\" '
249                 BEGIN {
250                     split(spec, time, ":")
251                 }
252                 {
253                     split($4, now, ":")
254                     diff = 3600 * (time[1] - now[1]) + 60 * (time[2] - now[2]);
255                     if (diff < 0)
256                         diff += 3600 * 24
257                     print diff
258                 }'`"
259         clear
260         echo "${SLEEP_MESSAGE}"
261         sleep "${pausetime}"
262     fi
263 }
264
265 level_log_name() {
266     echo "$REMOTEBACKUPDIR/${1}.level-${2-$DUMP_LEVEL}"
267 }
268
269 # Prepare a temporary level logfile
270 # usage: make_level_log HOSTNAME
271 make_level_log() {
272     if [ "z${localhost}" != "z$1" ] ; then
273         $RSH "$1" mkdir $REMOTEBACKUPDIR > /dev/null 2>&1
274         $RSH "$1" rm -f `level_log_name temp`
275     else
276         mkdir $REMOTEBACKUPDIR > /dev/null 2>&1
277         rm -f `level_log_name temp`
278     fi
279 }
280
281 # Rename temporary log
282 # usage: flush_level_log HOSTNAME FSNAME
283 flush_level_log() {
284     message 10 "RENAME: `level_log_name temp` --> `level_log_name $2`"
285     if [ "z${localhost}" != "z$1" ] ; then
286         $RSH "$1" mv -f `level_log_name temp` "`level_log_name $2`"
287     else
288         mv -f `level_log_name temp` "`level_log_name $2`"
289     fi
290 }
291
292 # Return the timestamp of the last backup.
293 # usage: get_dump_time LEVEL
294 get_dump_time() {
295     ls -r ${LOGPATH}/log-*-level-$1 \
296         | head -n 1 \
297         | sed "s,.*log-\(.*\)-level-$1,\1,"
298 }
299
300 # Do actual backup on a host
301 # usage: backup_host HOSTNAME [TAR_ARGUMENTS]
302 backup_host() {
303     message 10 "ARGS: $@"
304     rhost=$1
305     shift
306     if [ "z${localhost}" != "z$rhost" ] ; then
307         $RSH "$rhost" ${TAR_PART1} -f "${localhost}:${TAPE_FILE}" $@
308     else
309         # Using 'sh -c exec' causes nested quoting and shell substitution
310         # to be handled here in the same way rsh handles it.
311         CMD="exec ${TAR_PART1} -f \"${TAPE_FILE}\" $@"
312         message 10 "CMD: $CMD"
313         sh -c "$CMD"
314         message 10 "RC: $?"
315     fi
316 }
317
318 print_level() {
319     if [ ${1-$DUMP_LEVEL} -eq 0 ]; then
320         echo "Full"
321     else
322         echo "Level ${1-$DUMP_LEVEL}"
323     fi
324 }
325
326 prev_level() {
327     print_level `expr $DUMP_LEVEL - 1` | tr A-Z a-z
328 }
329
330 remote_run() {
331     rhost=$1
332     shift
333     message 10 "REMOTE $rhost: $@"
334     if [ "x$rhost" != "x${localhost}" ] ; then
335         $RSH "${rhost}" "$@"
336     else
337         $*
338     fi
339 }
340
341 license() {
342     cat - <<EOF
343 Copyright (C) 2013 Free Software Foundation, Inc.
344 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
345 This is free software: you are free to change and redistribute it.
346 There is NO WARRANTY, to the extent permitted by law.
347 EOF
348 }