Working star backup script
"Zoran Ljubisic" <[email protected]> Wed, 2 Nov 2005 13:19:50 +0100
| Newsgroups | gmane.comp.archivers.star.user |
|---|---|
| Message-ID | <004301c5dfa7$f24de1d0$fd01a8c0@zoran> |
Hi all,
I found out this script that use star for backup. Maybe somebody here find
it usefull also.
Original is locate on
http://homepage.sunrise.ch/mysunrise/joerg.hau/linux/#backup2tape
Here it comes:
#!/bin/sh
# 'backup2tape.sh'
#
# - writes data to tape drive
# - allows to specify directories & exclude patterns
# - supports full & differential backup
# - supports both GNU mt and mt-st
# -----------------------------------------------------------------
# This program is free software; you can redistribute it and/or
# modify it under the terms of the version 2 of the GNU General
# Public License as published by the Free Software Foundation.
#
# 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.
# -----------------------------------------------------------------
# Copyright (c) 2003...2005 Joerg Hau <joerg.hau(at)dplanet.ch>.
#
# Idea(s) based on
#
# - Joerg Schilling's 'star'
# - a script from Karsten M. Self (kmself(at)ix.netcom.com)
# http://kmself.home.netcom.com/Linux/FAQs/backups.html
# - Vincent Stemen's 'bu' script (1998)
# - the easyBackup-Script v0.1 (c) 2000 by CCONE.at
# - material from Tim Jones Linux Magazine (1999)
#
# Revisions:
# 2003-10-05, first operational version (JHa)
# 2003-10-06, cmd line parsing and more variables (JHa)
# 2003-10-07, ctrl-c handler; error log via mail (JHa)
# 2003-10-14, fixed exclude patterns, added verify (JHa)
# 2003-10-15, all msg are now logged (JHa)
# 2003-10-29, bugfix: tape positioning before verify (JHa)
# 2003-12-20, introduced a tape label (JHa)
# 2004-01-28, minor bugfix in tape label (JHa)
# 2004-03-06, minor bugfix in label assignment on cmd line (JHa)
# 2004-08-02, bugfix in redirection to STDERR (JHa)
# 2004-12-19, fixed typo (JHa)
# 2004-12-25, hostname now from environment (JHa)
# 2004-12-29, removed domain from hostname (JHa)
# 2005-01-12, introduced handling of mt-st in addition to mt (JHa)
# 2005-02-21, added check for executables (JHa)
# 2005-02-26, $TAR, $MT now set after config file (JHa)
# 2005-03-18, fix in checkfor() error message (JHa)
# -----------------------------------------------------------------
# NOTES:
# - adjust parameters, tape device etc. below.
# - All variables below can be specified in an external file
# which is read on the cmd line. In other words: put all 'your'
# stuff in that external file - no need to modify this script.
#
# - for differential backup, the ctime of $LASTTIME counts.
# - if you change DIRLIST, you should perform a full backup.
#
# - This must be run as root.
# -----------------------------------------------------------------
# disable expansion of wildcards in commands
#
set -f
# default list of directories to archive
# star will NOT descend mount points, so you must specify them separately
#
DIRLIST="/home /root /etc /var /usr/local /mnt/win/Home /mnt/share/archive"
# list of exclude patterns for 'star'
#
EXCLUDE="tmp/* var/tmp/* var/spool/wwwoffle/* proc/* */[cC]ache/*
*/[.][tT]humbnail[s]/* *~"
# default backup mode is either "Differential" or "Full"
# This string is also used for logging.
# Attention, this is case-sensitive!
#
MODE="Differential"
# the non-rewinding tape device
#
TAPE="/dev/nst0"
# Blocksize for the tape drive (to be multiplied by 512)
# for a HP1533A (DDS-2), 125 is fine
# for a HP DLT4000 (DLT), 500 is fine
#
BS="125"
# the tar and mt executables to use
# I use Joerg Schilling's 'star' and GNU 'mt'
# note that some options used below are version-specific!
#
TAR_EXE="/usr/bin/star"
MT_EXE="/usr/bin/mt"
# Get the system name (without domain suffix)
#
NAME=${HOSTNAME%%.*}
# Backup log directory
#
LOGDIR="/var/log/backup"
# One "general" log file
# to keep track of date/time & success/failure
# (one line per event)
#
LOGFILE=${LOGDIR}/${NAME}.log
# "individual" log files, a pair for each backup process
# The filenames contain hostname & date/time, so they do not
# get overwritten when multiple backups are done the same day
#
LOGNAME=${LOGFILE}.`date +%Y%m%dT%H%M`
STDOUT=${LOGNAME}.ok
STDERR=${LOGNAME}.err
DIFF=${LOGNAME}.diff
# A file whose date/time stamp is used for incremental backups
#
LASTTIME=${LOGDIR}/${NAME}.lasttime
# Error control file (see 'star' manpage for details)
#
ERRCTLFILE=${LOGDIR}/${NAME}.errctl
VERBOSE="" # verbose mode or not (empty string = no)
INIT_TAPE="" # should tape be rewritten or appended? (empty = append)
ERRCNT=0 #error counter
MAILTO="root@${HOSTNAME}" # Backup operator
#
# --- "No user adjustable parts below this line" :-) ---
#
# -----------------------------------------------------------------
# subroutine to check for some required executables
# argument: (list of) programs to test for
# will exit with rc=1 if any program was not found
# -----------------------------------------------------------------
function checkfor()
{
for i in $*; do
PROG=`which $i`
if [ $? != 0 ]; then
echo "'$i' command not found, exiting."
exit 1
else
# echo "'$i' command found."
shift
fi
done
}
# ------------------------------------------------------------
# subroutine to log stuff to file with date/time stamp
# argument: text to log
# ------------------------------------------------------------
function logging()
{
# get date/time stamp
DATETIME=`date --iso-8601=sec`
# append text ($1) to file
echo "${DATETIME}. $1" >> $LOGFILE
# if verbose mode is set, echo also to screen
if [ $VERBOSE ] ; then
echo "${DATETIME}. $1"
fi
}
# ------------------------------------------------------------
# subroutine to check error status of last command
# argument: error message
# will exit with rc=1 if errorlevel was not 0
# ------------------------------------------------------------
function errcheck()
{
if [ $? != 0 ]; then
logging "Abort: $1, status: $?"
echo `date --iso-8601=sec`. $1 >> $STDERR
mail -s "$NAME-Backup ABORT!" $MAILTO < $STDERR
exit 1
fi
}
# ------------------------------------------------------------
# subroutine to create an "exceptions" file
# argument: filename
# see the 'star' manpage for explanations
# ------------------------------------------------------------
function makectlfile()
{
cat << eof > $1
GROW ${LOGDIR}*
eof
if [ $? != 0 ]; then
logging "Warning: cannot create exceptions file. Verify will report
everything."
fi
}
# ------------------------------------------------------------
# subroutine to obtain tape position
#
# Most Linux distributions use GNU mt, but RedHat uses mt-st.
# Both have different status messages!
#
# argument: none
# sets : tape position (in TPOS)
# ------------------------------------------------------------
function get_tape_position()
{
if ( $MT --version | grep -q 'mt-st' ) ; then
# mt-st: "File number=1, block number=0, partition=0."
TPOS=`$MT status | grep "File number" | cut -d "," -f 1 | cut -d "=" -f
2`
else
# GNU tar: "file number=1"
TPOS=`$MT status | grep "file number" | cut -d ' ' -f 4`
fi
}
# ------------------------------------------------------------
# subroutine to print usage mode
# ------------------------------------------------------------
function usage()
{
cat << eof
${0##*/} - Backup to Tape
A script to back up files and directories to a tape streamer.
Copyright (c) 2003...2005 Joerg Hau <joerg.hau(at)dplanet.ch>.
This program is free software; you can redistribute it and/or
modify it under the terms of version 2 of the GNU General Public
License as published by the Free Software Foundation.
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.
Usage: ${0##*/} [-f | --full] [-d | --diff] [-i | --init]
[-c | --config config_file] [-l | --label text] [-v | --verbose]
Invoking "${0##*/}" with no arguments will perform a
differential backup of the files listed at the beginning of
this script. Otherwise:
-f, --full write full backup.
-d, --diff write differential backup.
-i, --init write tape from the beginning. This is done by default
for a full backup, but not for incremental stuff:
you may use this function to "re-initialise" a tape.
-c config_file Specify a configuration file.
Default is to use the built-in values.
-l label Label (a descriptive text) to identify the tape.
At present this is provided merely for convenience.
-v, --verbose Verbose mode.
-? | -h | --help This help.
Notes:
o Full backup always starts at beginning of the tape.
o There is no incremental backup (not yet? ;-)
o Differential backup appends at the end of the tape (simply
due to the fact that I do not change that tape every day ;-).
The tape position is written to $LOGFILE,
so that you can use "$MT_EXE -f ${TAPE} asf \$position"
to position the tape before extracting that backup.
o It does not traverse mounted file systems, so you can backup
file systems like '/' without umounting file systems you do
not want included, such as NFS mounts.
o WARNING: This requires that you explicitly specify mounted fs that
shall *be* included! Look up /etc/fstab ...
o To restore a subset (e.g. all in /home), use a command like
"$TAR_EXE -f ${TAPE} -xpv -b $BS pat='home/*'".
eof
}
################## script starts here ;-) ####################
# ------------------------------------------------------------
# handle command line parameters (flags)
# ------------------------------------------------------------
while [ "$1" != "" ]; do
case $1 in
-f | --full ) MODE="Full"
;;
-d | --diff ) MODE="Differential"
;;
-v | --verbose ) VERBOSE="talkative"
;;
-i | --init ) INIT_TAPE="init"
;;
-c | --config ) shift
CONFIG_FILE="$1"
;;
-l | --label ) shift
LABEL="$1"
;;
-h | -? | --help ) usage
exit 2
;;
* ) usage
exit 1
esac
shift
done
# ------------------------------------------------------------
# see if you have the right to access all this stuff
# ------------------------------------------------------------
if [ `whoami` != 'root' ]; then
echo "You must be root to run this script."
exit 2
fi
# ------------------------------------------------------------
# handle Ctrl-C and other stuff
# ------------------------------------------------------------
trap 'errcheck "${0##*/} killed!" ; \
cp -p ${LASTTIME}.previous $LASTTIME ; \
exit 1' \
9 15
# default label text. This variable is not used in the backup process
# "as such" but is written to the log file. It can be used e.g. to
# identify the tape in a set of backup tapes.
# FIXME: could use this in VOLHDR=$LABEL
LABEL="Backup-${NAME}-${MODE}"
# ------------------------------------------------------------
# if an external config file was specified, source it
# ------------------------------------------------------------
if [ $CONFIG_FILE ]; then
logging "Reading configuration from $CONFIG_FILE"
if [ -e "$CONFIG_FILE" ]; then
source $CONFIG_FILE
else
logging "Configuration file $CONFIG_FILE not found!"
exit 1
fi
fi
# ------------------------------------------------------------
# set the tar and mt *commands* to use
# ------------------------------------------------------------
TAR="${TAR_EXE} -f ${TAPE}"
MT="${MT_EXE} -f ${TAPE}"
# ------------------------------------------------------------
# see if everything is accessible
# ------------------------------------------------------------
checkfor $TAR_EXE $MT_EXE gzip uuencode mail cp echo cat
# ------------------------------------------------------------
# Check if log directory exists, exit if problem
# ------------------------------------------------------------
if [ ! -d $LOGDIR ] ; then
echo "Error: $LOGDIR does not exist. Exiting."
exit 1
fi
# ------------------------------------------------------------
# See if differential or full backup is desired
# if differential, the date/time stamp file must exist
# ------------------------------------------------------------
if [ $MODE = "Full" ] ; then
MODE_CMD="-cv"
else # all else
if [ ! -e $LASTTIME ] ; then
echo "Error: no previous backup detected! Must do a full backup
first."
exit 2
fi
MODE_CMD="-cv -newer=${LASTTIME}"
fi
# log event to file
#
logging "$MODE backup initiated."
# ------------------------------------------------------------
# concatenate list of directories & excludes
# we'll cd to '/' first, so all dirnames will start with './'
# ------------------------------------------------------------
DIRS=`for X in $DIRLIST; do echo -n ".${X} "; done`
EXCL=`for X in $EXCLUDE; do echo -n "-not pat=${X} "; done`
logging "Preparing to archive: $DIRLIST"
logging "Excluding: $EXCLUDE"
makectlfile $ERRCTLFILE
# ------------------------------------------------------------
# tape initialisation
# blocksizes are given in multiples of 512 bytes
# ------------------------------------------------------------
TAPE_BS=512
logging "Using blocksize of $BS (x${TAPE_BS} bytes)"
let TAPE_BS="${TAPE_BS}*${BS}"
$MT setblk $TAPE_BS
errcheck "Error during initialisation of $TAPE to a blocksize of $TAPE_BS!"
# ------------------------------------------------------------
# full backup --> just rewind and shoot ;-)
# differential backup --> write at the end of the tape
# ------------------------------------------------------------
if [ $MODE = "Full" ] ; then
$MT rewind
else
if [ $INIT_TAPE ] ; then
$MT rewind # force write at the beginning
else
$MT eod # end of data (eom = en of media)
# GNU tar uses eom, mt-st uses eod, both are compatible :-)
fi
fi
errcheck "Error during positioning of $TAPE!"
# ------------------------------------------------------------
# write tape position to log file, so that we can easily find
# which file contains which backup
# ------------------------------------------------------------
get_tape_position
errcheck "Error during status check of $TAPE!"
logging "Tape '$LABEL' is positioned at file number $TPOS"
# ------------------------------------------------------------
# For a partial backup, we rely on the date/time stamp
# of the file $LASTTIME. Two issues here:
# (1) If we create this file AFTER the backup is complete,
# changes that occur between the start of this script and
# the end of the backup process are missed.
# (2) If we 'touch' $LASTTIME before and an error occurs, the
# datetime of the previous "good" backup would be lost.
# --> Solution: copy -p preserves date/time stamp :-)
# ------------------------------------------------------------
if [ $MODE = "Full" ] ; then
if [ -e $LASTTIME ] ; then
cp -p $LASTTIME ${LASTTIME}.previous
errcheck "Error copying ${LASTTIME}!"
fi
echo "`date --iso-8601=sec`, $MODE backup was started. DO NOT TOUCH THIS
FILE!" > $LASTTIME
fi
# ------------------------------------------------------------
# ... ah, finally, now we run $TAR :-)
# Some options used:
# -C / start at "/" and strip off leading slash
# -acl save ACLs if present
# H=exustar use exustar header (this one supports acl)
# -M do not descend mount points
# ------------------------------------------------------------
${TAR} -C / ${MODE_CMD} H=exustar -b ${BS} -acl -M errctl=${ERRCTLFILE}
${EXCL} ${DIRS} > $STDOUT 2> $STDERR
ERRCNT=$?
logging "$MODE backup written, status: $ERRCNT"
# ------------------------------------------------------------
# verify tape
# ------------------------------------------------------------
sleep 30s # give $MT some time to finish
$MT asf $TPOS # position to beginning of this archive
get_tape_position
errcheck "Error during status check of $TAPE!"
logging "Starting verify at tape position (file number) $TPOS"
# compare tape with filesystem - not the other way round -,
# thus we do *not* need to specify a lot of parameters
#
${TAR} -C / -diff -b ${BS} errctl=${ERRCTLFILE} > ${DIFF} 2> ${DIFF}
ERRCNT=$?
logging "Verify complete, status: $ERRCNT"
# if something goes wrong, do NOT bail out here - the backup may still be
useful
# ------------------------------------------------------------
# After a FULL _AND_ SUCCESSFUL backup, $LASTTIME has the
# correct date/time stamp.
# Only in case of trouble, we copy the previous file back.
# ------------------------------------------------------------
if [ $MODE = "Full" ] ; then
if [ $ERRCNT != 0 ] ; then # problem occurred
cp -p ${LASTTIME}.previous $LASTTIME
fi
fi
# ------------------------------------------------------------
# full backup --> force tape change by ejecting
# differential backup --> leave it in the drive, so that we can
# add at the end of the tape
# ------------------------------------------------------------
if [ $MODE = "Full" ] ; then
$MT rewoffl
logging "$TAPE ejected, status: $?. Please change the tape."
else
$MT rewind
logging "$TAPE rewound, status: $?."
fi
# ------------------------------------------------------------
# mail last few lines of logfile to backup-admin
# ------------------------------------------------------------
if [ $ERRCNT -gt 0 ] ; then
mail -s "$NAME-Backup ERROR!" $MAILTO < $STDERR
else
cat $STDOUT | gzip | uuencode backup-ok-`date --iso-8601=min`.gz | \
mail -s "$NAME-Backup OK!" $MAILTO
fi
gzip $STDOUT
if [ $VERBOSE ] ; then echo `date --iso-8601=sec`", Backup script ended." ;
fi
exit 0
I found minor bug with label option and config file. Everything else looks
very well.
Zoran