445 lines
11 KiB
Bash
445 lines
11 KiB
Bash
#!/bin/sh
|
|
# Define this variable _NOSPINDLE before calling this script if this script run through a systemd service
|
|
# if this variable _SAFESYNC is also defined, it will do a wd safe sync instead (when watchdog daemon is not used)
|
|
|
|
STAG=mbackup:
|
|
ENDSIG=/tmp/mbackup_sig
|
|
ERRSIG=/tmp/mbackup_err
|
|
PENDINGCHK=/tmp/.boot_pending
|
|
# lock wait time max 15mn * 60 = 900 secs (sufficient time to update)
|
|
LOCKWAIT=900
|
|
bname=mbackup
|
|
TMPBK=""
|
|
DEFBAKPATH=/mnt/storage/.sysbackup/
|
|
BAKPATH=$DEFBAKPATH
|
|
_curr_dir=""
|
|
BAKEXT=".tar.gz"
|
|
PREVEXT=".tar.gz.bk1"
|
|
TMPEXT=".tar.gz.tmp"
|
|
BAKMD5EXT=".md5"
|
|
PREVMD5EXT=".md5.bk1"
|
|
TMPMD5EXT=".md5.tmp"
|
|
mybasename=""
|
|
CREATEPBACK=1
|
|
|
|
sp="/-\|"
|
|
sc=0
|
|
spin() {
|
|
if [ -z "$_NOSPINDLE" ]; then
|
|
printf "\r${STAG} ${sp:sc++:1}"
|
|
((sc==${#sp})) && sc=0
|
|
else
|
|
printf "${STAG} ${sp:sc++:1} \n"
|
|
((sc==${#sp})) && sc=0
|
|
if [ ! -z "$_SAFESYNC" ]; then
|
|
dmesg -D
|
|
echo 1 > /dev/watchdog
|
|
dmesg -E
|
|
fi
|
|
fi
|
|
}
|
|
endspin() {
|
|
if [ -z "$_NOSPINDLE" ]; then
|
|
printf "\r"
|
|
else
|
|
if [ ! -z "$_SAFESYNC" ]; then
|
|
dmesg -E
|
|
fi
|
|
fi
|
|
}
|
|
|
|
readonly LOCKFILE_DIR=/var/lock
|
|
readonly LOCK_FD=980
|
|
|
|
lock() {
|
|
local prefix=$1
|
|
local fd=${2:-$LOCK_FD}
|
|
local lock_file=$LOCKFILE_DIR/$prefix.lock
|
|
|
|
# still allow to run unlocked if the lock dir does not exist
|
|
if [ ! -d "${LOCKFILE_DIR}" ]; then
|
|
return 0
|
|
fi
|
|
|
|
# create lock file
|
|
eval "exec $fd>$lock_file"
|
|
# still allow to run unlocked if the lock file cannot be created
|
|
if [ $? -ne 0 ]; then
|
|
return 0
|
|
fi
|
|
|
|
# acquier the lock
|
|
flock -w ${LOCKWAIT} $fd \
|
|
&& return 0 \
|
|
|| return 1
|
|
}
|
|
|
|
unlock() {
|
|
local prefix=$1
|
|
local fd=${2:-$LOCK_FD}
|
|
local lock_file=$LOCKFILE_DIR/$prefix.lock
|
|
|
|
# release the lock
|
|
flock -u $fd
|
|
sync
|
|
}
|
|
|
|
function my_exit()
|
|
{
|
|
sync
|
|
if [ -f "$BAKPATH$mybasename$TMPEXT" ]; then
|
|
rm -f $BAKPATH$mybasename$TMPEXT
|
|
fi
|
|
if [ -f "$BAKPATH$mybasename$TMPMD5EXT" ]; then
|
|
rm -f $BAKPATH$mybasename$TMPMD5EXT
|
|
fi
|
|
if [ -d "${TMPBK}" ]; then
|
|
TMPBKMNT_RES=$(mount | grep "${TMPBK}")
|
|
TMPBKMNT_RET=$?
|
|
if [ $TMPBKMNT_RET -eq 0 ]; then
|
|
umount ${TMPBK}
|
|
fi
|
|
rmdir "${TMPBK}"
|
|
fi
|
|
sync
|
|
cd "$_curr_dir"
|
|
unlock $bname
|
|
exit $*
|
|
}
|
|
|
|
function __sig_int {
|
|
endspin
|
|
log_write " "
|
|
log_write "$STAG WARNING: SIGINT caught"
|
|
my_exit 110
|
|
}
|
|
|
|
function __sig_quit {
|
|
endspin
|
|
log_write " "
|
|
log_write "$STAG WARNING: SIGQUIT caught"
|
|
my_exit 111
|
|
}
|
|
|
|
function __sig_term {
|
|
endspin
|
|
log_write " "
|
|
log_write "$STAG WARNING: SIGTERM caught"
|
|
my_exit 112
|
|
}
|
|
|
|
function __sig_hup {
|
|
endspin
|
|
log_write " "
|
|
log_write "$STAG WARNING: SIGHUP caught"
|
|
my_exit 113
|
|
}
|
|
|
|
function log_write()
|
|
{
|
|
echo "$*"
|
|
}
|
|
|
|
function log_write_nr()
|
|
{
|
|
echo -n "$*"
|
|
}
|
|
|
|
function show_help {
|
|
log_write "mbackup help information:"
|
|
log_write "Usage: mbackup [ [ [-f file] [-n] ] | [--help] ] <spath>"
|
|
log_write " where: <spath> # source directory path to backup recursively"
|
|
log_write " options: -f file # force output file name (will be appended with .tar.gz/.md5)"
|
|
log_write " # specified file destination directory must exist!"
|
|
log_write " # if -f not used, default dest. dir. is created: $BAKPATH"
|
|
log_write " # with auto generated filename according to <spath>"
|
|
log_write " -n # do not create a previous backup (*.bk1) if one already exist"
|
|
log_write " # default is to create one"
|
|
log_write " --help # displays this help information"
|
|
log_write "example: mbackup /mnt/rom/user; # backup user flash configuration to default dir"
|
|
log_write "example: mbackup -f /tmp/qq /mnt/rom/user; # backup user flash configuration to /tmp/qq"
|
|
}
|
|
|
|
function create_basename()
|
|
{
|
|
local retval
|
|
local retval2
|
|
local repchr=-
|
|
local srcchr=/
|
|
local slen=${#1}
|
|
local mystr
|
|
local mystr2
|
|
if [ "${1:$slen - 1:1}" == "/" ] ; then
|
|
mystr=${1:0:$slen - 1}
|
|
slen=$((slen-1))
|
|
else
|
|
mystr=$1
|
|
fi
|
|
if [ ${1:0:1} == "/" ] ; then
|
|
mystr2=${mystr:1:$slen - 1}
|
|
slen=$((slen-1))
|
|
else
|
|
mystr2=$mystr
|
|
fi
|
|
retval="bk-"${mystr2//$srcchr/$repchr}
|
|
retval2=${retval// /$repchr}
|
|
echo $retval2
|
|
}
|
|
|
|
# returns the file basename without directory and extension
|
|
function get_basename()
|
|
{
|
|
echo ${1//+(*\/|.*)}
|
|
return 0
|
|
}
|
|
|
|
function check_destpath()
|
|
{
|
|
local retval=0
|
|
local slen=${#1}
|
|
local mystr
|
|
if ! [ -d $1 ] ; then
|
|
log_write "$STAG Destination directory does not exist ($1)!"
|
|
retval=80
|
|
else
|
|
if [ "${1:$slen - 1:1}" == "/" ] ; then
|
|
mystr=${1:0:$slen - 1}
|
|
slen=$((slen-1))
|
|
else
|
|
mystr=$1
|
|
fi
|
|
BAKPATH=$mystr"/"
|
|
fi
|
|
return $retval
|
|
}
|
|
|
|
# corrects md5 associated source file
|
|
# param1=originalfilename
|
|
# param2=newfilename
|
|
# param3=md5 file to correct
|
|
function correct_md5_file()
|
|
{
|
|
local name1
|
|
local name2
|
|
name1=`basename $1`
|
|
if [ $? -ne 0 ]; then
|
|
log_write "$STAG Getting basename of ($1) fail!"
|
|
return 81
|
|
fi
|
|
name2=`basename $2`
|
|
if [ $? -ne 0 ]; then
|
|
log_write "$STAG Getting basename of ($2) fail!"
|
|
return 82
|
|
fi
|
|
sed -i "s/$name1/$name2/g" $3
|
|
if [ $? -ne 0 ]; then
|
|
log_write "$STAG Sed md5 file ($3) fail!"
|
|
return 83
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
if [ -e "${PENDINGCHK}" ]; then
|
|
log_write "$STAG Pending reboot, could not run!"
|
|
exit 97
|
|
fi
|
|
|
|
_curr_dir=`pwd`
|
|
|
|
# Lock to test a single instance is running, and exit if wait timeout
|
|
log_write "$STAG Checking if allowed to run..."
|
|
lock $bname || ( log_write "$STAG Checking if allowed to run... failed"; exit 100 )
|
|
log_write "$STAG Checking if allowed to run... done"
|
|
|
|
# Set TRAPs to release lock if forced to exit
|
|
trap __sig_int SIGINT
|
|
trap __sig_quit SIGQUIT
|
|
trap __sig_term SIGTERM
|
|
trap __sig_hup SIGHUP
|
|
|
|
if [ -e "${PENDINGCHK}" ]; then
|
|
log_write "$TAG Pending reboot, could not run!"
|
|
my_exit 97
|
|
fi
|
|
|
|
TOTALARG=$#
|
|
while getopts :f:n- FLAG; do
|
|
case $FLAG in
|
|
f)
|
|
#log_write "#Filename (-f)"
|
|
check_destpath `dirname "$OPTARG"`
|
|
valret=$?
|
|
if [ $valret -ne 0 ]; then
|
|
my_exit $valret
|
|
fi
|
|
mybasename=`basename "$OPTARG"`;;
|
|
n)
|
|
log_write "$STAG No previous backup option specified (-n)"
|
|
CREATEPBACK=0;;
|
|
'-')
|
|
show_help
|
|
my_exit 0;;
|
|
\?)
|
|
log_write "Invalid option: -$OPTARG" && my_exit 1;;
|
|
\:)
|
|
log_write "Required argument not found for option: -$OPTARG" && my_exit 2;;
|
|
esac
|
|
done
|
|
|
|
# removes processed option(s) from the cmd line args
|
|
shift $((OPTIND-1))
|
|
|
|
if [ "$#" -ne 1 ]; then
|
|
show_help
|
|
my_exit 3
|
|
fi
|
|
|
|
if ! [ -d $1 ] ; then
|
|
log_write "$STAG Source directory does not exist ($1)!"
|
|
my_exit 4
|
|
fi
|
|
if [ "x$mybasename" == "x" ] ; then
|
|
mybasename=$(create_basename $1)
|
|
if ! [ -d "$BAKPATH" ]; then
|
|
mkdir -p $BAKPATH
|
|
if [ $? -ne 0 ]; then
|
|
log_write "$STAG create dir ($BAKPATH) fail!"
|
|
my_exit 5
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
log_write "$STAG Creating backup to: "$BAKPATH$mybasename
|
|
TMPBK=$(mktemp -d)
|
|
if [ $? -ne 0 ]; then
|
|
log_write "$STAG mktemp fail!"
|
|
my_exit 6
|
|
fi
|
|
|
|
# temporarily bind mount dir to backup to TMPBK
|
|
mount --bind -o ro $1 ${TMPBK}
|
|
if [ $? -ne 0 ]; then
|
|
log_write "$STAG mount $1 to temp folder fail!"
|
|
my_exit 7
|
|
fi
|
|
|
|
rm -f $BAKPATH$mybasename$TMPEXT
|
|
if [ $? -ne 0 ]; then
|
|
log_write "$STAG cannot remove ($BAKPATH$mybasename$TMPEXT)!"
|
|
my_exit 8
|
|
fi
|
|
rm -f $BAKPATH$mybasename$TMPMD5EXT
|
|
if [ $? -ne 0 ]; then
|
|
log_write "$STAG cannot remove ($BAKPATH$mybasename$TMPMD5EXT)!"
|
|
my_exit 9
|
|
fi
|
|
rm -f ${ENDSIG}
|
|
rm -f ${ERRSIG}
|
|
log_write "$STAG Creating files backup..."
|
|
(
|
|
tar -zcf $BAKPATH$mybasename$TMPEXT -C ${TMPBK} .
|
|
if [ $? -ne 0 ]; then
|
|
log_write " $STAG tar ($BAKPATH$mybasename$TMPEXT) fail!"
|
|
touch ${ERRSIG}
|
|
exit 10
|
|
fi
|
|
touch ${ENDSIG}
|
|
) &
|
|
until [ -f ${ENDSIG} ]; do
|
|
spin
|
|
if [ -f ${ERRSIG} ]; then
|
|
my_exit 11
|
|
fi
|
|
if [ ! -f ${ENDSIG} ]; then
|
|
sleep 1s
|
|
fi
|
|
done
|
|
endspin
|
|
log_write "$STAG Creating files backup... done"
|
|
|
|
# create md5
|
|
cd $BAKPATH
|
|
if [ $? -ne 0 ]; then
|
|
log_write "$STAG cannot change dir to ($BAKPATH)!"
|
|
my_exit 12
|
|
fi
|
|
md5sum ./$mybasename$TMPEXT > ./$mybasename$TMPMD5EXT
|
|
if [ $? -ne 0 ]; then
|
|
log_write "$STAG cannot create md5 for ($BAKPATH$mybasename$TMPEXT)!"
|
|
my_exit 13
|
|
fi
|
|
|
|
# create a previous backup if one already exit
|
|
if [ $CREATEPBACK -eq 1 ]; then
|
|
if [ -f "$BAKPATH$mybasename$BAKEXT" ] && [ -f "$BAKPATH$mybasename$BAKMD5EXT" ]; then
|
|
log_write "$STAG Copy prev. backup to: "$BAKPATH$mybasename$PREVEXT
|
|
cp -f $BAKPATH$mybasename$BAKEXT $BAKPATH$mybasename$PREVEXT
|
|
if [ $? -ne 0 ]; then
|
|
log_write "$STAG Creating previous backup ($BAKPATH$mybasename$PREVEXT) fail!"
|
|
my_exit 14
|
|
fi
|
|
log_write "$STAG Copy prev. MD5 to: "$BAKPATH$mybasename$PREVMD5EXT
|
|
cp -f $BAKPATH$mybasename$BAKMD5EXT $BAKPATH$mybasename$PREVMD5EXT
|
|
if [ $? -ne 0 ]; then
|
|
log_write "$STAG Creating previous backup ($BAKPATH$mybasename$PREVMD5EXT) fail!"
|
|
my_exit 15
|
|
fi
|
|
correct_md5_file $BAKPATH$mybasename$BAKEXT $BAKPATH$mybasename$PREVEXT $BAKPATH$mybasename$PREVMD5EXT
|
|
if [ $? -ne 0 ]; then
|
|
my_exit $?
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# create current backup from temporary files
|
|
rm -f $BAKPATH$mybasename$BAKEXT
|
|
if [ $? -ne 0 ]; then
|
|
log_write " $STAG cannot remove ($BAKPATH$mybasename$BAKEXT) fail!"
|
|
my_exit 16
|
|
fi
|
|
rm -f $BAKPATH$mybasename$BAKMD5EXT
|
|
if [ $? -ne 0 ]; then
|
|
log_write " $STAG cannot remove ($BAKPATH$mybasename$BAKMD5EXT) fail!"
|
|
my_exit 17
|
|
fi
|
|
log_write "$STAG Move backup to: "$BAKPATH$mybasename$BAKEXT
|
|
mv $BAKPATH$mybasename$TMPEXT $BAKPATH$mybasename$BAKEXT
|
|
if [ $? -ne 0 ]; then
|
|
log_write " $STAG cannot move to ($BAKPATH$mybasename$BAKEXT) fail!"
|
|
my_exit 18
|
|
fi
|
|
log_write "$STAG Move MD5 to: "$BAKPATH$mybasename$BAKMD5EXT
|
|
mv $BAKPATH$mybasename$TMPMD5EXT $BAKPATH$mybasename$BAKMD5EXT
|
|
if [ $? -ne 0 ]; then
|
|
log_write " $STAG cannot move to ($BAKPATH$mybasename$BAKMD5EXT) fail!"
|
|
my_exit 19
|
|
fi
|
|
correct_md5_file $BAKPATH$mybasename$TMPEXT $BAKPATH$mybasename$BAKEXT $BAKPATH$mybasename$BAKMD5EXT
|
|
if [ $? -ne 0 ]; then
|
|
my_exit $?
|
|
fi
|
|
rm -f ${ENDSIG}
|
|
rm -f ${ERRSIG}
|
|
log_write "$STAG System sync..."
|
|
(
|
|
sync
|
|
if [ $? -ne 0 ]; then
|
|
log_write " $STAG sync fail!"
|
|
touch ${ERRSIG}
|
|
exit 20
|
|
fi
|
|
touch ${ENDSIG}
|
|
) &
|
|
until [ -f ${ENDSIG} ]; do
|
|
spin
|
|
if [ -f ${ERRSIG} ]; then
|
|
my_exit 21
|
|
fi
|
|
if [ ! -f ${ENDSIG} ]; then
|
|
sleep 1s
|
|
fi
|
|
done
|
|
endspin
|
|
log_write "$STAG System sync... done"
|
|
my_exit 0
|