Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
#!/bin/bash
# tar backup script: tarbut-1.2.0
VER=1.2.0
if [ -r /etc/tarbut.conf ]; then
. /etc/tarbut.conf
fi
if [ -r ~/tarbut.conf ]; then
. ~/tarbut.conf
fi
function error () {
case $1 in
NO_ARG)
echo Error - No arguments passed;;
NO_TARGET)
echo Error - No target passed;;
NO_LIST)
echo Error - No such target \`$TARG\';;
INVALID_LEVEL)
echo Error - Invalid argument to --level option;;
INVALID_OPT)
echo Error - Invalid option;;
NO_SNAR)
echo Error - Incremental snap-shot not exist or write protected;;
esac
exit 1
}
function help () {
cat << EOM
Version $VER
Usage: tarbut [option]
Backups files and directories specified in list file using tar.
must be one of the base-name of list files - *.lst
that tells tarbut what files/directories should be backed-up.
Option is one of [--level=x|--clean|--cleanall|--kill|--status]
Archive files' extension depends on what or no compression
method you set in configuration file - tarbut.conf.
--level=x tarbut performs an incremental backup.
If x is 0, it does full backup, creates a new
incremental snap-shot file - .snar and
(if exists) renames previous .snar to .snar.back.
If AUTOCLEAN_LEVEL1 is 1 in tarbut.conf, it
also deletes series of previous level-1 backups.
The created backup - _lev0. can be
the first generation for the period (ex; week).
If x is 1, it creates an incremental backup
by inspecting and updating .snar file.
Achieved archive will be _yymmddHHMM.tar
to avoid overwriting existent level-1 backups.
Unless --level option, tarbut performs full backup regardless
of incremental snap-shot file nor touching it at all. This
behaviour may be ideal for occasional backup or those who
always take full backup only.
--clean deletes incremental level-1 archives and old
snap-shot files of corresponding TARGET.
--cleanall deletes incremental level-0/1 archives and all
snap-shot files of it.
--kill also deletes non-incremental archives of it.
--status performs simple integrity check of archive group.
--list lists the available targets.
EOM
exit 0
}
function list_target () {
ls $CONFDIR/ |awk '/\.lst$/ {sub(/\.lst$/,""); print}'
exit 0
}
function clean () {
# Clean up files. ARG is; 1=clean 2=cleanall 3=kill
case $1 in
1)
find $DESTDIR/ -maxdepth 1 -regex '.*\/'$TARG'_[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9].*\.\(tar\|tgz\|tar\.bz2\)' -print0 |xargs -0 rm -f &>/dev/null
rm -f $CACHEDIR/${TARG}.snar.{back,back2} &>/dev/null
echo \`$TARG\' level-1 archives deleted
echo \`$TARG\' old incremental snap-shot file deleted
;;
2|3)
find $DESTDIR/ -maxdepth 1 -regex '.*\/'$TARG'_[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9].*\.\(tar\|tgz\|tar\.bz2\)' -print0 |xargs -0 rm -f &>/dev/null
rm -f $DESTDIR/${TARG}_lev*.{tar,tgz,tar.bz2} &>/dev/null
rm -f $CACHEDIR/${TARG}.snar{,.back,.back2} &>/dev/null
echo \`$TARG\' level-0/1 archives deleted
echo \`$TARG\' incremental snap-shot file deleted
;;
esac
if [ $1 -eq 3 ]; then
rm -f $DESTDIR/${TARG}.{tar,tgz,tar.bz2} &>/dev/null
rm -f $DESTDIR/${TARG}_m*.{tar,tgz,tar.bz2} &>/dev/null
echo \`$TARG\' non-incremental archives deleted
fi
exit 0
}
function what_mtime () {
# Set modified time of ARG file to MTIME
RETM=$(ls -l --time-style='+%s' $1 2>&1 | \
awk '$6 ~ /^[0-9]+$/ {print $6}')
MTIME=${RETM:-0}
}
function mtimecmp () {
# Check existence and compare time-stamp of two files. returns;
# 0: neither F1 nor F2 exists
# 1: F1 exists but F2 not
# 2: F2 exists but F1 not
# 4: F2 newer than F1(incremental ever done and files are healthy)
# 8: F2 older than F1(incremental ever done but not healthy)
RETC=0
what_mtime $1
[ $MTIME -gt 0 ] && RETC=1
MT[0]=$MTIME
what_mtime $2
[ $MTIME -gt 0 ] && : $((RETC+=2))
MT[1]=$MTIME
[ $RETC -lt 3 ] && return $RETC
[ ${MT[1]} -gt ${MT[0]} ] && return 4
return 8
}
status () {
# Integrity check of archives
CHECK=0
echo Status of \`$TARG\' in $DESTDIR
MATCH=$(find $DESTDIR/ -maxdepth 1 -regex \
'.*\/'$TARG'\(_m0\)?\.\(tar\|tgz\|tar\.bz2\)' -printf '%f')
if [ ! -z "$MATCH" ]; then
echo [Healthy] : Full-backup archive
CHECK=1
fi
[ -f $CACHEDIR/${TARG}.snar ] || : $((CHECK+=2))
# Check existence and compare mtime of archives.
# Get the name of the oldest Level-1 archive.
L1OLDEST=$(ls -t $DESTDIR |grep -E $TARG'_[0-9]{10}(_m[0-9]+)?\..*' |tail -n 1)
: ${L1OLDEST:=tarbutdummy}
# Get the name of the newest Level-0.
MATCH=$(ls -tr $DESTDIR |grep -E ${TARG}_lev0'(_m[0-9]+)?\..*' |tail -n 1)
: ${MATCH:=tarbutdummy}
mtimecmp $DESTDIR/$MATCH $DESTDIR/$L1OLDEST
case $? in
0)
[ $CHECK -eq 0 -o $CHECK -eq 2 ] && echo No backups found;;
1)
if [ $CHECK -ge 2 ]; then
echo [Critical]: Level-0 incremental backup exists, but snap-shot not found
else
echo [Healthy] : Level-0 incremental backup
fi
;;
2)
[ $CHECK -ge 2 ] && echo [Critical]: No incremental snap-shot file found
echo [Notice] : Level-1 incremental backup exists, but Level-0 not found
;;
4)
if [ $CHECK -ge 2 ]; then
echo [Critical]: Level-0 and Level-1 incremental backup exists, but snap-shot file not found
else
echo [Healthy] : Level-0 and Level-1 incremental backups
fi
;;
8)
echo [Critical]: The oldest Level-1 incremental backup is older than Level-0
[ $CHECK -ge 2 ] && echo [Critical]: Incremental snap-shot file not found
;;
esac
exit 0
}
function mv_old () {
# Rename archives for fail-safe. First we put names of critical
# files into arrays for later use. ARG is $INCREMENT value.
# Build regular expressions to use in find.
case $1 in
0)
[ -f $CACHEDIR/${TARG}.snar -a ! -w $CACHEDIR/${TARG}.snar ] && error NO_SNAR
REGPAT='.*\/'$TARG'_lev0\(_m[0-9]+\)?\.\(tar\|tgz\|tar\.bz2\)'
if [ "$AUTOCLEAN_LEVEL1" = "1" ]; then
REGPAT2='.*\/'$TARG'_[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]\(_m[0-9]+\)?\.\(tar\|tgz\|tar\.bz2\)'
fi
mv -f $CACHEDIR/${TARG}.snar.back{,2} &>/dev/null
mv -f $CACHEDIR/${TARG}.snar{,.back} &>/dev/null
;;
1)
[ -w $CACHEDIR/${TARG}.snar ] || error NO_SNAR
;;
*)
REGPAT='.*\/'$TARG'\(_m[0-9]+\)?\.\(tar\|tgz\|tar\.bz2\)'
;;
esac
[ ${#REGPAT} -gt 0 ] && BAKTMP=( $(find $DESTDIR/ -maxdepth 1 -regex $REGPAT -print) )
[ ${#REGPAT2} -gt 0 ] && BAKTMP2=( $(find $DESTDIR/ -maxdepth 1 -regex $REGPAT2 -print) )
# Rename them now.
for X in ${BAKTMP[@]} ; do
mv -f $X ${X}.bak &>/dev/null
done
for X in ${BAKTMP2[@]} ; do
mv -f $X ${X}.bak &>/dev/null
done
}
#### Main procedures from here ####
# Arguments check.
[ -z "$1" ] && error NO_ARG
for X; do
case $X in
--level*)
INCREMENT=$(echo -n $X |sed 's/--level=\([0-9]\)/\1/')
case $INCREMENT in
0) ;;
1) ;;
*) error INVALID_LEVEL;;
esac
;;
--help|-h)
help;;
--clean)
CLR=1;;
--cleanall)
CLR=2;;
--kill)
CLR=3;;
--status)
STATUS=1;;
--list)
LIST=1;;
-*)
error INVALID_OPT;;
*)
TARG=$X;;
esac
done
if [ -z "$CONFDIR" -o -z "$DESTDIR" ]; then
echo Error - configuration error
exit 1
fi
if [ -z "$CACHEDIR" ]; then
echo Error - configuration error
exit 1
fi
[ -z "$LIST" ] || list_target
[ -z "$TARG" ] && error NO_TARGET
SRCLIST=$CONFDIR/${TARG}.lst
[ -r $SRCLIST ] || error NO_LIST
[ -z "$CLR" ] || clean $CLR
[ -z "$STATUS" ] || status
# Destination archive name draft.
if [ -r $CONFDIR/${TARG}.exc ]; then
OPT="$OPT --exclude-from=$CONFDIR/${TARG}.exc"
elif [ -r $CONFDIR/excludes ]; then
OPT="$OPT --exclude-from=$CONFDIR/excludes"
fi
if [ "$INCREMENT" = "1" ]; then
DEST="-f $DESTDIR/${TARG}_$(date +%y%m%d%H%M)"
OPT="$OPT -g $CACHEDIR/${TARG}.snar"
elif [ "$INCREMENT" = "0" ]; then
DEST="-f $DESTDIR/${TARG}_lev0"
OPT="$OPT -g $CACHEDIR/${TARG}.snar"
else
DEST="-f $DESTDIR/${TARG}"
fi
# Fetch source definition
SRC=$(awk <$SRCLIST '
BEGIN{ ORS=" " }
{
if (/^#/) next;
if (/^[[:blank:]]*$/) next;
sub(/^\//,"");
print;
}
')
# GNU tar limitation; cannot use multi-volume compressed archive.
# If source is smaller enough than MAX_DESTSIZE, prevent multi-
# volume operation, otherwise withdraw compression.
: ${MAX_DESTSIZE:=0}
if [ ${MAX_DESTSIZE} -gt 0 ]; then
TARCD=$(echo $OPT |awk '{
match($0,/(-C +|--directory=)([^ ]+)/,fld)
print fld[2]
}')
[ -z "$TARCD" ] || cd $TARCD
ACTSUM=$(du -skc $SRC |awk 'END{print $1}')
[ -z "$TARCD" ] || cd - &>/dev/null
if [ "$COMPRESS" = "gzip" -o "$COMPRESS" = "bzip2" ]; then
: ${MULTI_COMP_THRESHOLD:=60}
if [ $(($ACTSUM * ${MULTI_COMP_THRESHOLD} / 100)) -le $MAX_DESTSIZE ]; then
MAX_DESTSIZE=0
else
COMPRESS=none
fi
else
if [ $(($ACTSUM * 95 / 100)) -le $MAX_DESTSIZE ]; then
MAX_DESTSIZE=0
fi
fi
fi
case $COMPRESS in
gzip)
EXT=tgz
OPT="$OPT -z";;
bzip2)
EXT=tar.bz2
OPT="$OPT -j";;
*)
EXT=tar;;
esac
# Destination archive name conclusion.
if [ ${MAX_DESTSIZE} -gt 0 ]; then
# In case of multi-volume operation.
: ${MAX_VOL:=6}
for (( X=0; X<${MAX_VOL}; X++ )) ; do
XDEST="$XDEST ${DEST}_m${X}.$EXT"
done
else
XDEST="$DEST.$EXT"
fi
[ ${MAX_DESTSIZE} -gt 0 ] && OPT="$OPT -M --tape-length=${MAX_DESTSIZE}"
# Retract existent archives and snap-shots in concern
mv_old $INCREMENT
# The heart of script
cd /
nice -n 10 tar $OPT -c $XDEST $SRC 2>&1
RETVAL=$?
# Finally remove the retracted old archives on success.
if [ $RETVAL -eq 0 ]; then
for X in ${BAKTMP[@]} ; do
rm -f ${X}.bak &>/dev/null
done
for X in ${BAKTMP2[@]} ; do
rm -f ${X}.bak &>/dev/null
done
rm -f $CACHEDIR/${TARG}.snar.back2 &>/dev/null
# ..or restore to what they were.
else
for X in ${BAKTMP[@]} ; do
mv -f ${X}.bak $X &>/dev/null
done
for X in ${BAKTMP2[@]} ; do
mv -f ${X}.bak $X &>/dev/null
done
mv -f $CACHEDIR/${TARG}.snar.back{2,} &>/dev/null
fi
exit $RETVAL