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