Re: Несколько вопросов вразброс
Приложил скрипт, который у меня получился.
mkbackup - сам скрипт.
mks - парсер, убирающий тесты.
ready - готовый скрипт после обработки.
Вроде, работает, хотя и не всё доделано.
Ощущения: получилось очень "тяжеловесно". Просто запутаться в тестах. Но тесты
ловят случайные ошибки (лучше, чем без тестов совсем).
Что скажете?
#!/bin/sh
#
# Backup script, used rdiff-backup. Created by Artiom N..
#
# Using: mkbackup <path to config>
# Configuration options.
OPT_SRC_DIR="/"
OPT_BACKUP_DIR="/mnt/backup/backup_uc"
OPT_BTMP_DIR="/mnt/backup/btmp"
OPT_INC_LIST="include.cfg"
OPT_EXC_LIST="exclude.cfg"
OPT_MYSQL_LOGIN="root"
OPT_MYSQL_PASSWORD=""
OPT_LUKS_PARTS=""
OPT_KERNEL_CONFIG="/usr/src/linux/.config"
OPT_REMOVE_PERIOD="1M"
OPT_FBACKUP_KCONF="true"
OPT_FBACKUP_MYSQL="true"
OPT_FBACKUP_PACKAGES="true"
OPT_FBACKUP_PARTS="true"
# Verbosity: 0 - no diagnostics, 1 - error messages, 2 - verbose, 3 - debug.
V_LEVEL="3"
# Resulting filename constants.
FN_MYSQL_DUMP="mysql.dump"
FN_PKGS_DUMP="pagkages.dump"
FN_LVM_TEMPL="lvbk_%s"
FN_LUKS_TEMPL="luksbk_%s"
FN_KERNEL_CONF="linux_config"
# Directories in $OPT_BACKUP_DIR for backup system tree and special files.
FN_DIR_TREE="tree"
FN_DIR_SPECIAL="special"
# File or directory, used as flag, for selecting backup type.
FN_FLAG="rdiff-backup-data"
# Binaries path.
CMD_DPKG="dpkg"
CMD_VGBCK="vgcfgbackup"
CMD_DUMP="mysqldump"
CMD_CRYPTSETUP="cryptsetup"
CMD_RDBCKP="rdiff-backup"
CMD_NOTIFIER="logger"
###TESTING
assert()
# $1 - message;
# $2 - comannd.
{
local RT=0
echo "Command: $2"
eval $2 || { RT="$?"; printf "$1 (ret: 0x%x)" $RT && exit 1; }
return 0;
}
###/TESTING
#-------------------------------------------------------------------------------
dbg()
# $1 - verbosity level;
# $2 - message.
{
[ "$V_LEVEL" -ge "$1" ] && echo "$2" > /dev/stderr
}
#-------------------------------------------------------------------------------
err()
# $1 - message.
{
dbg 1 "$1"
dbg 0 "Backup failed..." # failed...&& exit 1
return 1
}
###TESTING
#-------------------------------------------------------------------------------
check_deps()
# Check for the using executables.
# $1..$n - list of executables.
{
local s
while [ ! -z "$1" ]; do
s="`type $1`" && dbg 3 "Checking dep $s" || { dbg 1 "$s" && return 1; }
shift
done;
return 0;
}
###/TESTING
#-------------------------------------------------------------------------------
get_execs()
# Set full path of the executables in the variables.
# $1..$n - list of executables.
{
local s
while [ ! -z "$1" ]; do
eval "s=\$$1"
dbg 3 "Exec filename: $s"
s="$(whereis -b $s|awk '{print $2}')"
dbg 3 "Exec fullpath: $s"
[ -z "$s" ] && { err "Cant't find \"eval \$$1\""; return 1; }
eval $1=$s
shift
done
return 0;
}
#-------------------------------------------------------------------------------
load_config()
# $1 - config filename.
{
dbg 3 "$LINENO ${FUNCNAME}(): Loading file \"$1\""
dbg 3 "PWD: $PWD"
[ -r "$1" ] || { err "Can't open file \"$1\"..."; return 1; }
. "$1" || return $?
return $?;
}
#-------------------------------------------------------------------------------
notify()
# Notify user, about backup process.
# $1 - message.
{
"$CMD_NOTIFIER" "$1"
return 0;
}
#-------------------------------------------------------------------------------
backup_special()
# Backup special system data.
# Return values:
# $? & 0x000f - backup_kernel_conf result;
# $? & 0x00f0 - backup_mysql result;
# $? & 0x0f00 - backup_packages result;
# $? & 0xf000 - backup_parted_data result.
{
#
# Interfaces.
#
backup_mysql()
# $1 - user name;
# $2 - password;
# $3 - options.
# Return 0, if all good, 1 if error.
{
dbg 3 "$LINENO ${FUNCNAME}(): Loading MySQL config..."
dbg 2 "Dumping databases..."
dbg 3 "Dump command: \"$CMD_DUMP\" -u\"$1\" -p\"$2\" --compact -f --all-databases $3"
"$CMD_DUMP" -u"$1" -p"$2" --compact -f --all-databases $3 || \
{ err "MySQL backup failed!"; return 1; }
return 0;
}
backup_packages()
{
dbg 3 "$LINENO ${FUNCNAME}(): Dumping package list..."
"$CMD_DPKG" --get-selections
return $?;
}
get_part_string()
# Return partition string, created from template,
# in the "part=file_to_save; ..." format.
# $1 - template, where %s - partition name (exmpl.: luksbk_%s).
# $2 - partition list ("part_1; part_2; ... ; part_n").
{
dbg 3 "$LINENO ${FUNCNAME}(): \$1 = \"$1\"; \$2 = \"$2\""
export TEMPL="$1"
local IFS=";"
for i in $2; do
# dbg 3 "\$i = $i"
echo "$i"|awk \
'/.*[^\/]+/ {
n = split($0, pcomps, "/")
printf("%s="ENVIRON["TEMPL"]";", $0, pcomps[n]);
}'
done
return 0;
}
backup_parted_data()
# $1 - template for the saving LVM backups;
# $2 - LUKS "partition=file_to_save; ..." list.
# Return values:
# 1 - LVM backup error;
# 2 - LUKS backup error;
# 3 - other.
{
dbg 2 "Dumping partition data..."
# LVM.
dbg 3 "$LINENO ${FUNCNAME}(): Dumping LVM headers to the files \"$1\"..."
"$CMD_VGBCK" -f"$1" --ignorelockingfailure || \
{ err "LVM backup failed!"; return 1; }
# LUKS.
#OIFS="$IFS"
# Local field separator.
local IFS=';'
dbg 3 "LUKS parts (\$2) = $2"
for i in $2; do
dbg 3 "$LINENO ${FUNCNAME}(): LUKS \$i = $i"
eval $(echo "$i"|awk 'BEGIN { FS="=" } { printf("LSB_HB_PART=\"%s\"; LSB_HB_FILE=\"%s\"", $1, $2); }')
dbg 2 "$LINENO ${FUNCNAME}(): Dumping LUKS header from partition \"$LSB_HB_PART\" to the file \"$LSB_HB_FILE\""
dbg 3 "$CMD_CRYPTSETUP" --header-backup-file="$LSB_HB_FILE" luksHeaderBackup "$LSB_HB_PART"
"$CMD_CRYPTSETUP" --header-backup-file="$LSB_HB_FILE" luksHeaderBackup "$LSB_HB_PART" || \
{ err "LUKS backup of \"$LSB_HB_PART\" to \"$LSB_HB_FILE\" failed!"; return 2; }
done
#IFS="$OIFS"
local RT=$?
[ $RT -ne 0 ] && RT=3
return $RT;
}
backup_kernel_conf()
# $1 - config filename;
{
dbg 3 "$LINENO ${FUNCNAME}(): Saving kernel configuration from \"$1\"..."
[ -s "$1" ] && cat "$1" || err "Kernel config [$1] backup failed!"
return $?;
}
#
# End of interfaces.
#
if [ ! -d "$OPT_BTMP_DIR" ]; then
mkdir -p "$OPT_BTMP_DIR" || return 1
else
rm -rf "$OPT_BTMP_DIR"/*
fi
touch "$OPT_BTMP_DIR/backup_directory" || return 2
###TESTING
OPT_MYSQL_LOGIN=root
OPT_MYSQL_UPSW=rootsqld
OPT_MYSQL_OPTS="--no-data"
assert "backup_mysql error 0" \
"backup_mysql $OPT_MYSQL_LOGIN $OPT_MYSQL_UPSW $OPT_MYSQL_OPTS > \"$OPT_BTMP_DIR/_mysql.log\""
assert "backup_packages error" "backup_packages > \"$OPT_BTMP_DIR/_pkg.log\""
assert "backup_parted_data error 0" \
'(backup_parted_data "_lvm bk_%s" "/dev/vol1=vol1.lbck;/dev/_volxxx2=vol2.lbck"; x=$?; [ $x -ne 0 ])'
assert "backup_kernel_conf error 0" \
'(backup_kernel_conf bla-bla-bla... '"$OPT_BTMP_DIR/_config"'; x=$?; [ $x -ne 0 ]; )'
assert "backup_kernel_conf error 1" \
"backup_kernel_conf \"$OPT_KERNEL_CONFIG\" > \"$OPT_BTMP_DIR/_config\""
assert "config compare error" "cmp \"$OPT_KERNEL_CONFIG\" \"$OPT_BTMP_DIR/_config\""
assert "get_part_string error 1" \
"([ 'part1=bck_part1_test;/etc/part2=bck_part2_test;/dev/part3=bck_part3_test;' = '`get_part_string bck_%s_test 'part1;;/etc/part2;/dev/part3;/'`' ])"
if [ `id -u` -ne 0 ]; then
echo "backup_parted_data not tested! Need to be root."
assert "backup_parted_data error 1" \
'(backup_parted_data "$OPT_BTMP_DIR/_lvm bk_%s" "`get_part_string $OPT_BTMP_DIR/_%s.lbck /dev/sdb1`;/dev/mapper/gv_main-luks=$OPT_BTMP_DIR/_main - luks.lbck"; x=$?; [ $x -ne 0 ])'
else
rm '_lvm bk'* _*.lbck
assert "backup_parted_data error 1" \
'backup_parted_data "$OPT_BTMP_DIR/_lvm bk_%s" "`get_part_string $OPT_BTMP_DIR/_%s.lbck /dev/sdb1`/dev/mapper/gv_main-luks=$OPT_BTMP_DIR/_main - luks.lbck"'
assert "backup_parted_data error 2" \
'(cd "$OPT_BTMP_DIR" && for i in "_lvm bk_"*; do echo Test size of "$i"; [ -s "$i" ] || exit 1; done && [ -s _sdb1.lbck ] && [ -s "_main - luks.lbck" ])'
fi
rm -rf "$OPT_BTMP_DIR" && mkdir "$OPT_BTMP_DIR"
[ "x$1" = "xtst" ] && return 0;
:
###/TESTING
# For error code used one hex digit on function.
local RET_CODE=0
local RT=0
if [ x"$OPT_FBACKUP_KCONF" = xtrue ]; then
backup_kernel_conf \
"$OPT_KERNEL_CONFIG" > "$OPT_BTMP_DIR/$FN_KERNEL_CONF"
# Error code == 1 is in use (can't make directory).
RT=$?
[ $RT -ne 0 ] && RET_CODE=$((0x2))
dbg 3 "Kernel backup errcode: $RT"
fi
if [ x"$OPT_FBACKUP_MYSQL" = xtrue ]; then
backup_mysql \
"$OPT_MYSQL_LOGIN" "$OPT_MYSQL_PASSWORD" "$OPT_MYSQL_OPTIONS" \
> "$OPT_BTMP_DIR/$FN_MYSQL_DUMP"
RT=$?
RET_CODE=$(($RT << 4 | $RET_CODE))
dbg 3 "MySQL backup errcode: $RT"
fi
if [ x"$OPT_FBACKUP_PACKAGES" = xtrue ]; then
backup_packages > "$OPT_BTMP_DIR/$FN_PKGS_DUMP"
RT=$?
RET_CODE=$(($RT << 8 | $RET_CODE))
dbg 3 "Packages backup errcode: $RT"
fi
if [ x"$OPT_FBACKUP_PARTS" = xtrue -a `id -u` -eq 0 ]; then
backup_parted_data \
"$FN_LVM_TEMPL" "`get_part_string \"$FN_LUKS_TEMPL\" \"$OPT_LUKS_PARTS\"`"
RT=$?
RET_CODE=$(($RT << 12 | $RET_CODE))
dbg 3 "Partitions backup errcode: $RT"
fi
dbg 3 "backup_special errcode: $RET_CODE"
return $RET_CODE;
}
#-------------------------------------------------------------------------------
backup_tree()
# $1 - tree;
# $2 - dest;
# $3 - incl globbing file list (optional);
# $4 - excl list (optional);
{
local RD_OPTS;
RD_OPTS="--create-full-path --exclude-device-files --exclude-fifos "
RD_OPTS="$RD_OPTS --exclude-sockets --exclude-symbolic-links --no-compression"
RD_OPTS="$RD_OPTS -v$((V_LEVEL * 3))"
if [ -n "$3" -o -n "$4" ]; then
[ -r "$3" ] || return 1
RD_OPTS="$RD_OPTS --include-globbing-filelist $3"
[ -r "$4" ] || return 2
RD_OPTS="$RD_OPTS --exclude-globbing-filelist $4"
fi
dbg 3 "Backup command: \"$CMD_RDBCKP\" $RD_OPTS \"$1\" \"$2\""
"$CMD_RDBCKP" $RD_OPTS "$1" "$2"
return $?;
}
#-------------------------------------------------------------------------------
full_backup()
# Full backup function.
# Return values:
# $? & 0x00000f - backup_tree for main tree code;
# $? & 0x0000f0 - backup_tree for special files code;
# $? & 0xffff00 - backup_special code.
{
local RET_CODE=0
local RT=0
dbg 3 "$LINENO ${FUNCNAME}(): Backup special files..."
backup_special || { RET_CODE="$?"; err "Backup special return non null error code ($RET_CODE)!"; notify "$0 -> backup_special error code: $RET_CODE"; }
if [ ! -d "$FN_DIR_SPECIAL" ]; then
mkdir -p "$FN_DIR_SPECIAL" || return 2
fi
if [ ! -d "$FN_DIR_TREE" ]; then
mkdir -p "$FN_DIR_TREE" || return 3
fi
backup_tree "$OPT_BTMP_DIR" "$FN_DIR_SPECIAL";
RT=$?
RET_CODE=$(($RET_CODE << 4 | $RT))
rm -rf "$OPT_BTMP_DIR"
dbg 3 "$LINENO ${FUNCNAME}(): Backup main tree..."
backup_tree "$OPT_SRC_DIR" "$FN_DIR_TREE" "$OPT_INC_LIST" "$OPT_EXC_LIST"
RT=$?
RET_CODE=$(($RET_CODE << 4 | $RT))
return $RET_CODE;
}
#-------------------------------------------------------------------------------
diff_backup()
# Function for the differential backup making.
# Return values:
# $? & 0x000000f - del_old_diffs code;
# $? & 0xffff000 - full_backup code.
{
local RET_CODE=0
local RT=0
del_old_diffs()
{
local CMD_REMOVE
CMD_REMOVE="$CMD_RDBCKP --remove-older-than $OPT_REMOVE_PERIOD"
dbg 2 "Deleting old differentials..."
dbg 3 "$LINENO ${FUNCNAME}(): $CMD_REMOVE \"$FN_DIR_TREE\" && $CMD_REMOVE \"$FN_DIR_SPECIAL\""
$CMD_REMOVE "$FN_DIR_TREE" && $CMD_REMOVE "$FN_DIR_SPECIAL"
return $?;
}
del_old_diffs
RET_CODE=$?
full_backup
RT=$?
RET_CODE=$(($RET_CODE << 4 | $RT))
return $RET_CODE;
}
#-------------------------------------------------------------------------------
main()
# $1 - config.
{
# Setting executables paths.
get_execs CMD_DPKG CMD_DUMP CMD_VGBCK CMD_CRYPTSETUP CMD_RDBCKP CMD_NOTIFIER
# Loading configuration file.
[ -z "$1" ] && { err "Syntax: $0 <config>" && return 1; }
load_config "$1"
notify "Backup started..."
FN_DIR_TREE="$OPT_BACKUP_DIR/$FN_DIR_TREE"
FN_DIR_SPECIAL="$OPT_BACKUP_DIR/$FN_DIR_SPECIAL"
FN_LUKS_TEMPL="$OPT_BTMP_DIR/$FN_LUKS_TEMPL"
FN_LVM_TEMPL="$OPT_BTMP_DIR/$FN_LVM_TEMPL"
# Selecting backup type and do work.
if [ -e "$FN_DIR_TREE/$FN_FLAG" ]; then
diff_backup
else
full_backup
fi
local RT=$(($? << 4))
notify "Backup ended with code $RT..."
return $RT
}
###TESTING
#-------------------------------------------------------------------------------
# Unit testing.
test_code()
{
mock_backup()
{
return 0;
}
assert "get_execs error 0" \
"get_execs CMD_DPKG CMD_DUMP CMD_VGBCK CMD_CRYPTSETUP CMD_RDBCKP"
assert "get_execs error 1" \
'(for i in "$CMD_DPKG" "$CMD_DUMP" "$CMD_VGBCK" "$CMD_CRYPTSETUP" "$CMD_RDBCKP"; do echo $i; [ -z "$i" ] && exit 1; done; exit 0;)'
assert "check_deps error 0" "check_deps ls dpkg"
assert "check_deps error 1" '(check_deps a b c; x=$?; [ $x -ne 0 ])'
assert "check deps error: real files" \
"check_deps \"$CMD_DPKG\" \"$CMD_DUMP\" \"$CMD_VGBCK\" \"$CMD_CRYPTSETUP\" \"$CMD_RDBCKP\""
rm -f "/tmp/lala la"
assert "load_config error 0" '(load_config "/tmp/lala la"; x=$?; [ $x -ne 0 ])'
echo "XPORT=1">'/tmp/lala la' || exit 1
assert "load_config error 1" "load_config '/tmp/lala la'"
assert "load_config error 2" '[ x1 = x$XPORT ]'
rm -f "/tmp/lala la"
OPT_MYSQL_PASSWORD="rootsqld"
OPT_BACKUP_DIR="$PWD/_tst"
OPT_BTMP_DIR="$PWD/_tmp"
FN_DIR_TREE="$OPT_BACKUP_DIR/$FN_DIR_TREE"
FN_DIR_SPECIAL="$OPT_BACKUP_DIR/$FN_DIR_SPECIAL"
FN_LUKS_TEMPL="$OPT_BTMP_DIR/$FN_LUKS_TEMPL"
FN_LVM_TEMPL="$OPT_BTMP_DIR/$FN_LVM_TEMPL"
assert "backup_special error" "backup_special tst"
echo 1 > /tmp/test_backup
echo "/tmp/test_backup" > il
rm -rf "$OPT_BACKUP_DIR" && mkdir "$OPT_BACKUP_DIR"
assert "backup_tree error 0" '(backup_tree; x=$?; [ $x -ne 0 ];)'
_CMD_RDBCKP="$CMD_RDBCKP"
CMD_RDBCKP=mock_backup
rm -rf "$OPT_BACKUP_DIR" && mkdir "$OPT_BACKUP_DIR"
assert 'backup_tree error 1' \
"(backup_tree / \"$OPT_BACKUP_DIR\" \"$PWD/not_existent\" not_existent"';x=$?; [ $x -ne 0 ])'
CMD_RDBCKP="$_CMD_RDBCKP"
unset _CMD_RDBCKP
rm -rf "$OPT_BACKUP_DIR" && mkdir "$OPT_BACKUP_DIR"
assert "backup_tree error 2" \
"(backup_tree / \"$OPT_BACKUP_DIR\" $PWD/il"';x=$?; [ $x -ne 0 ])'
rm -rf "$OPT_BACKUP_DIR"
echo "*" > el
assert "backup_tree error 3" "backup_tree / _tst $PWD/il $PWD/el"
assert "cat tst error 1" "[ `cat _tst/tmp/test_backup` -eq 1 ]"
rm -rf "$OPT_BACKUP_DIR" && mkdir "$OPT_BACKUP_DIR"
rm -rf _tmp_old && mv "$OPT_BTMP_DIR" _tmp_old
OPT_INC_LIST="$PWD/il"
OPT_EXC_LIST="$PWD/el"
OPT_LUKS_PARTS='/dev/mapper/gv_main-luks'
assert "full_backup error 0" "full_backup"
dbg 3 "Wait 1 second..."
sleep 1
assert "diff_backup error 0" "diff_backup"
exit 0;
}
main()
{
test_code
}
###/TESTING
#-------------------------------------------------------------------------------
main;
#-------------------------------------------------------------------------------
# EOF
#!/bin/sh
fl="$1"
fl=${-:-$fl}
awk '
BEGIN {
prf = 0;
}
/^#!\/bin\/bash/ {
print "#!/bin/sh";
next;
}
/###TESTING/ {
prf = pfm + 1;
next;
}
/###\/TESTING/ {
if (prf == 0)
{
print "Error: unexpected ###\/TESTING" > "/dev/stderr";
exit 1;
}
prf = prf - 1;
next;
}
{
if (prf == 0) print;
}
END {
if (prf > 0)
{
print "Error: unclosed ###TESTING";
exit 1;
}
}
' "$fl"
#!/bin/sh
#
# Backup script, used rdiff-backup. Created by Artiom N..
#
# Using: mkbackup <path to config>
# Configuration options.
OPT_SRC_DIR="/"
OPT_BACKUP_DIR="/mnt/backup/backup_uc"
OPT_BTMP_DIR="/mnt/backup/btmp"
OPT_INC_LIST="include.cfg"
OPT_EXC_LIST="exclude.cfg"
OPT_MYSQL_LOGIN="root"
OPT_MYSQL_PASSWORD=""
OPT_LUKS_PARTS=""
OPT_KERNEL_CONFIG="/usr/src/linux/.config"
OPT_REMOVE_PERIOD="1M"
OPT_FBACKUP_KCONF="true"
OPT_FBACKUP_MYSQL="true"
OPT_FBACKUP_PACKAGES="true"
OPT_FBACKUP_PARTS="true"
# Verbosity: 0 - no diagnostics, 1 - error messages, 2 - verbose, 3 - debug.
V_LEVEL="3"
# Resulting filename constants.
FN_MYSQL_DUMP="mysql.dump"
FN_PKGS_DUMP="pagkages.dump"
FN_LVM_TEMPL="lvbk_%s"
FN_LUKS_TEMPL="luksbk_%s"
FN_KERNEL_CONF="linux_config"
# Directories in $OPT_BACKUP_DIR for backup system tree and special files.
FN_DIR_TREE="tree"
FN_DIR_SPECIAL="special"
# File or directory, used as flag, for selecting backup type.
FN_FLAG="rdiff-backup-data"
# Binaries path.
CMD_DPKG="dpkg"
CMD_VGBCK="vgcfgbackup"
CMD_DUMP="mysqldump"
CMD_CRYPTSETUP="cryptsetup"
CMD_RDBCKP="rdiff-backup"
CMD_NOTIFIER="logger"
#-------------------------------------------------------------------------------
dbg()
# $1 - verbosity level;
# $2 - message.
{
[ "$V_LEVEL" -ge "$1" ] && echo "$2" > /dev/stderr
}
#-------------------------------------------------------------------------------
err()
# $1 - message.
{
dbg 1 "$1"
dbg 0 "Backup failed..." # failed...&& exit 1
return 1
}
#-------------------------------------------------------------------------------
get_execs()
# Set full path of the executables in the variables.
# $1..$n - list of executables.
{
local s
while [ ! -z "$1" ]; do
eval "s=\$$1"
dbg 3 "Exec filename: $s"
s="$(whereis -b $s|awk '{print $2}')"
dbg 3 "Exec fullpath: $s"
[ -z "$s" ] && { err "Cant't find \"eval \$$1\""; return 1; }
eval $1=$s
shift
done
return 0;
}
#-------------------------------------------------------------------------------
load_config()
# $1 - config filename.
{
dbg 3 "$LINENO ${FUNCNAME}(): Loading file \"$1\""
dbg 3 "PWD: $PWD"
[ -r "$1" ] || { err "Can't open file \"$1\"..."; return 1; }
. "$1" || return $?
return $?;
}
#-------------------------------------------------------------------------------
notify()
# Notify user, about backup process.
# $1 - message.
{
"$CMD_NOTIFIER" "$1"
return 0;
}
#-------------------------------------------------------------------------------
backup_special()
# Backup special system data.
# Return values:
# $? & 0x000f - backup_kernel_conf result;
# $? & 0x00f0 - backup_mysql result;
# $? & 0x0f00 - backup_packages result;
# $? & 0xf000 - backup_parted_data result.
{
#
# Interfaces.
#
backup_mysql()
# $1 - user name;
# $2 - password;
# $3 - options.
# Return 0, if all good, 1 if error.
{
dbg 3 "$LINENO ${FUNCNAME}(): Loading MySQL config..."
dbg 2 "Dumping databases..."
dbg 3 "Dump command: \"$CMD_DUMP\" -u\"$1\" -p\"$2\" --compact -f --all-databases $3"
"$CMD_DUMP" -u"$1" -p"$2" --compact -f --all-databases $3 || \
{ err "MySQL backup failed!"; return 1; }
return 0;
}
backup_packages()
{
dbg 3 "$LINENO ${FUNCNAME}(): Dumping package list..."
"$CMD_DPKG" --get-selections
return $?;
}
get_part_string()
# Return partition string, created from template,
# in the "part=file_to_save; ..." format.
# $1 - template, where %s - partition name (exmpl.: luksbk_%s).
# $2 - partition list ("part_1; part_2; ... ; part_n").
{
dbg 3 "$LINENO ${FUNCNAME}(): \$1 = \"$1\"; \$2 = \"$2\""
export TEMPL="$1"
local IFS=";"
for i in $2; do
# dbg 3 "\$i = $i"
echo "$i"|awk \
'/.*[^\/]+/ {
n = split($0, pcomps, "/")
printf("%s="ENVIRON["TEMPL"]";", $0, pcomps[n]);
}'
done
return 0;
}
backup_parted_data()
# $1 - template for the saving LVM backups;
# $2 - LUKS "partition=file_to_save; ..." list.
# Return values:
# 1 - LVM backup error;
# 2 - LUKS backup error;
# 3 - other.
{
dbg 2 "Dumping partition data..."
# LVM.
dbg 3 "$LINENO ${FUNCNAME}(): Dumping LVM headers to the files \"$1\"..."
"$CMD_VGBCK" -f"$1" --ignorelockingfailure || \
{ err "LVM backup failed!"; return 1; }
# LUKS.
#OIFS="$IFS"
# Local field separator.
local IFS=';'
dbg 3 "LUKS parts (\$2) = $2"
for i in $2; do
dbg 3 "$LINENO ${FUNCNAME}(): LUKS \$i = $i"
eval $(echo "$i"|awk 'BEGIN { FS="=" } { printf("LSB_HB_PART=\"%s\"; LSB_HB_FILE=\"%s\"", $1, $2); }')
dbg 2 "$LINENO ${FUNCNAME}(): Dumping LUKS header from partition \"$LSB_HB_PART\" to the file \"$LSB_HB_FILE\""
dbg 3 "$CMD_CRYPTSETUP" --header-backup-file="$LSB_HB_FILE" luksHeaderBackup "$LSB_HB_PART"
"$CMD_CRYPTSETUP" --header-backup-file="$LSB_HB_FILE" luksHeaderBackup "$LSB_HB_PART" || \
{ err "LUKS backup of \"$LSB_HB_PART\" to \"$LSB_HB_FILE\" failed!"; return 2; }
done
#IFS="$OIFS"
local RT=$?
[ $RT -ne 0 ] && RT=3
return $RT;
}
backup_kernel_conf()
# $1 - config filename;
{
dbg 3 "$LINENO ${FUNCNAME}(): Saving kernel configuration from \"$1\"..."
[ -s "$1" ] && cat "$1" || err "Kernel config [$1] backup failed!"
return $?;
}
#
# End of interfaces.
#
if [ ! -d "$OPT_BTMP_DIR" ]; then
mkdir -p "$OPT_BTMP_DIR" || return 1
else
rm -rf "$OPT_BTMP_DIR"/*
fi
touch "$OPT_BTMP_DIR/backup_directory" || return 2
# For error code used one hex digit on function.
local RET_CODE=0
local RT=0
if [ x"$OPT_FBACKUP_KCONF" = xtrue ]; then
backup_kernel_conf \
"$OPT_KERNEL_CONFIG" > "$OPT_BTMP_DIR/$FN_KERNEL_CONF"
# Error code == 1 is in use (can't make directory).
RT=$?
[ $RT -ne 0 ] && RET_CODE=$((0x2))
dbg 3 "Kernel backup errcode: $RT"
fi
if [ x"$OPT_FBACKUP_MYSQL" = xtrue ]; then
backup_mysql \
"$OPT_MYSQL_LOGIN" "$OPT_MYSQL_PASSWORD" "$OPT_MYSQL_OPTIONS" \
> "$OPT_BTMP_DIR/$FN_MYSQL_DUMP"
RT=$?
RET_CODE=$(($RT << 4 | $RET_CODE))
dbg 3 "MySQL backup errcode: $RT"
fi
if [ x"$OPT_FBACKUP_PACKAGES" = xtrue ]; then
backup_packages > "$OPT_BTMP_DIR/$FN_PKGS_DUMP"
RT=$?
RET_CODE=$(($RT << 8 | $RET_CODE))
dbg 3 "Packages backup errcode: $RT"
fi
if [ x"$OPT_FBACKUP_PARTS" = xtrue -a `id -u` -eq 0 ]; then
backup_parted_data \
"$FN_LVM_TEMPL" "`get_part_string \"$FN_LUKS_TEMPL\" \"$OPT_LUKS_PARTS\"`"
RT=$?
RET_CODE=$(($RT << 12 | $RET_CODE))
dbg 3 "Partitions backup errcode: $RT"
fi
dbg 3 "backup_special errcode: $RET_CODE"
return $RET_CODE;
}
#-------------------------------------------------------------------------------
backup_tree()
# $1 - tree;
# $2 - dest;
# $3 - incl globbing file list (optional);
# $4 - excl list (optional);
{
local RD_OPTS;
RD_OPTS="--create-full-path --exclude-device-files --exclude-fifos "
RD_OPTS="$RD_OPTS --exclude-sockets --exclude-symbolic-links --no-compression"
RD_OPTS="$RD_OPTS -v$((V_LEVEL * 3))"
if [ -n "$3" -o -n "$4" ]; then
[ -r "$3" ] || return 1
RD_OPTS="$RD_OPTS --include-globbing-filelist $3"
[ -r "$4" ] || return 2
RD_OPTS="$RD_OPTS --exclude-globbing-filelist $4"
fi
dbg 3 "Backup command: \"$CMD_RDBCKP\" $RD_OPTS \"$1\" \"$2\""
"$CMD_RDBCKP" $RD_OPTS "$1" "$2"
return $?;
}
#-------------------------------------------------------------------------------
full_backup()
# Full backup function.
# Return values:
# $? & 0x00000f - backup_tree for main tree code;
# $? & 0x0000f0 - backup_tree for special files code;
# $? & 0xffff00 - backup_special code.
{
local RET_CODE=0
local RT=0
dbg 3 "$LINENO ${FUNCNAME}(): Backup special files..."
backup_special || { RET_CODE="$?"; err "Backup special return non null error code ($RET_CODE)!"; notify "$0 -> backup_special error code: $RET_CODE"; }
if [ ! -d "$FN_DIR_SPECIAL" ]; then
mkdir -p "$FN_DIR_SPECIAL" || return 2
fi
if [ ! -d "$FN_DIR_TREE" ]; then
mkdir -p "$FN_DIR_TREE" || return 3
fi
backup_tree "$OPT_BTMP_DIR" "$FN_DIR_SPECIAL";
RT=$?
RET_CODE=$(($RET_CODE << 4 | $RT))
rm -rf "$OPT_BTMP_DIR"
dbg 3 "$LINENO ${FUNCNAME}(): Backup main tree..."
backup_tree "$OPT_SRC_DIR" "$FN_DIR_TREE" "$OPT_INC_LIST" "$OPT_EXC_LIST"
RT=$?
RET_CODE=$(($RET_CODE << 4 | $RT))
return $RET_CODE;
}
#-------------------------------------------------------------------------------
diff_backup()
# Function for the differential backup making.
# Return values:
# $? & 0x000000f - del_old_diffs code;
# $? & 0xffff000 - full_backup code.
{
local RET_CODE=0
local RT=0
del_old_diffs()
{
local CMD_REMOVE
CMD_REMOVE="$CMD_RDBCKP --remove-older-than $OPT_REMOVE_PERIOD"
dbg 2 "Deleting old differentials..."
dbg 3 "$LINENO ${FUNCNAME}(): $CMD_REMOVE \"$FN_DIR_TREE\" && $CMD_REMOVE \"$FN_DIR_SPECIAL\""
$CMD_REMOVE "$FN_DIR_TREE" && $CMD_REMOVE "$FN_DIR_SPECIAL"
return $?;
}
del_old_diffs
RET_CODE=$?
full_backup
RT=$?
RET_CODE=$(($RET_CODE << 4 | $RT))
return $RET_CODE;
}
#-------------------------------------------------------------------------------
main()
# $1 - config.
{
# Setting executables paths.
get_execs CMD_DPKG CMD_DUMP CMD_VGBCK CMD_CRYPTSETUP CMD_RDBCKP CMD_NOTIFIER
# Loading configuration file.
[ -z "$1" ] && { err "Syntax: $0 <config>" && return 1; }
load_config "$1"
notify "Backup started..."
FN_DIR_TREE="$OPT_BACKUP_DIR/$FN_DIR_TREE"
FN_DIR_SPECIAL="$OPT_BACKUP_DIR/$FN_DIR_SPECIAL"
FN_LUKS_TEMPL="$OPT_BTMP_DIR/$FN_LUKS_TEMPL"
FN_LVM_TEMPL="$OPT_BTMP_DIR/$FN_LVM_TEMPL"
# Selecting backup type and do work.
if [ -e "$FN_DIR_TREE/$FN_FLAG" ]; then
diff_backup
else
full_backup
fi
local RT=$(($? << 4))
notify "Backup ended with code $RT..."
return $RT
}
#-------------------------------------------------------------------------------
main;
#-------------------------------------------------------------------------------
# EOF
Reply to: