mirror of
https://github.com/deajan/obackup.git
synced 2024-12-25 15:03:41 +01:00
Rebuilt targets
This commit is contained in:
parent
9fed22d4f9
commit
b7c49ed6d9
@ -1,22 +1,21 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
#TODO: test bad return of _GetDirectoriesSizeRemote
|
#TODO: test bad return of _GetDirectoriesSizeRemote
|
||||||
#TODO(critical): fix double path in rotate functions (switching from ls to find)
|
#TODO(critical): test RotateCopies remote
|
||||||
#TODO(high): check paths with spaces (again)
|
#TODO(high): check paths with spaces (again) - fails
|
||||||
#TODO(low): investigate all exit codes and adapt depending on WARN / ERROR so obackup-batch won't rerun WARN runs
|
#TODO(low): doc obackup-rerun is minimal 1 and not 0
|
||||||
#TODO(low): obackup-rerun is minimal 1 and not 0
|
|
||||||
|
|
||||||
###### Remote push/pull (or local) backup script for files & databases
|
###### Remote push/pull (or local) backup script for files & databases
|
||||||
PROGRAM="obackup"
|
PROGRAM="obackup"
|
||||||
AUTHOR="(C) 2013-2016 by Orsiris de Jong"
|
AUTHOR="(C) 2013-2016 by Orsiris de Jong"
|
||||||
CONTACT="http://www.netpower.fr/obackup - ozy@netpower.fr"
|
CONTACT="http://www.netpower.fr/obackup - ozy@netpower.fr"
|
||||||
PROGRAM_VERSION=2.1-dev
|
PROGRAM_VERSION=2.1-dev
|
||||||
PROGRAM_BUILD=2016081702
|
PROGRAM_BUILD=2016081803
|
||||||
IS_STABLE=no
|
IS_STABLE=no
|
||||||
|
|
||||||
#### MINIMAL-FUNCTION-SET BEGIN ####
|
#### MINIMAL-FUNCTION-SET BEGIN ####
|
||||||
|
|
||||||
## FUNC_BUILD=2016081605
|
## FUNC_BUILD=2016081701
|
||||||
## BEGIN Generic functions for osync & obackup written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr
|
## BEGIN Generic functions for osync & obackup written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr
|
||||||
|
|
||||||
## type -p does not work on platforms other than linux (bash). If if does not work, always assume output is not a zero exitcode
|
## type -p does not work on platforms other than linux (bash). If if does not work, always assume output is not a zero exitcode
|
||||||
@ -620,7 +619,7 @@ function WaitForTaskCompletion {
|
|||||||
if kill -0 $pid > /dev/null 2>&1; then
|
if kill -0 $pid > /dev/null 2>&1; then
|
||||||
# Handle uninterruptible sleep state or zombies by ommiting them from running process array
|
# Handle uninterruptible sleep state or zombies by ommiting them from running process array
|
||||||
#TODO(high): have this tested on *BSD, Mac & Win
|
#TODO(high): have this tested on *BSD, Mac & Win
|
||||||
pidState=$(ps -p$pid -o state=)
|
pidState=$(ps -p$pid -o state= 2 > /dev/null)
|
||||||
if [ "$pidState" != "D" ] && [ "$pidState" != "Z" ]; then
|
if [ "$pidState" != "D" ] && [ "$pidState" != "Z" ]; then
|
||||||
newPidsArray+=($pid)
|
newPidsArray+=($pid)
|
||||||
fi
|
fi
|
||||||
@ -734,7 +733,7 @@ function EscapeSpaces {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function IsNumeric {
|
function IsNumeric {
|
||||||
eval "local value=\"${1}\"" # Needed so variable variables can be processed
|
eval "local value=\"${1}\"" # Needed eval so variable variables can be processed
|
||||||
|
|
||||||
local re="^-?[0-9]+([.][0-9]+)?$"
|
local re="^-?[0-9]+([.][0-9]+)?$"
|
||||||
if [[ $value =~ $re ]]; then
|
if [[ $value =~ $re ]]; then
|
||||||
@ -763,9 +762,9 @@ function urlEncode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function urlDecode {
|
function urlDecode {
|
||||||
local url_encoded="${1//+/ }"
|
local url_encoded="${1//+/ }"
|
||||||
|
|
||||||
printf '%b' "${url_encoded//%/\\x}"
|
printf '%b' "${url_encoded//%/\\x}"
|
||||||
}
|
}
|
||||||
|
|
||||||
function GetLocalOS {
|
function GetLocalOS {
|
||||||
@ -1341,7 +1340,8 @@ PARTIAL_DIR=".obackup_workdir_partial"
|
|||||||
# $FILE_BACKUP_TASKS list of directories to backup, found in config file
|
# $FILE_BACKUP_TASKS list of directories to backup, found in config file
|
||||||
# $FILE_RECURSIVE_BACKUP_TASKS, list of directories to backup, computed from config file recursive list
|
# $FILE_RECURSIVE_BACKUP_TASKS, list of directories to backup, computed from config file recursive list
|
||||||
# $FILE_RECURSIVE_EXCLUDED_TASKS, list of all directories excluded from recursive list
|
# $FILE_RECURSIVE_EXCLUDED_TASKS, list of all directories excluded from recursive list
|
||||||
# $FILE_SIZE_LIST, list of all directories to include in GetDirectoriesSize
|
# $FILE_SIZE_LIST_LOCAL, list of all directories to include in GetDirectoriesSize, enclosed by escaped doublequotes for local command
|
||||||
|
# $FILE_SIZE_LIST_LOCAL, list of all directories to include in GetDirectoriesSize, enclosed by escaped singlequotes for remote command
|
||||||
|
|
||||||
CAN_BACKUP_SQL=1
|
CAN_BACKUP_SQL=1
|
||||||
CAN_BACKUP_FILES=1
|
CAN_BACKUP_FILES=1
|
||||||
@ -1560,7 +1560,7 @@ function ListDatabases {
|
|||||||
|
|
||||||
if [ "$DATABASES_ALL" == "yes" ]; then
|
if [ "$DATABASES_ALL" == "yes" ]; then
|
||||||
dbBackup=1
|
dbBackup=1
|
||||||
IFs=$PATH_SEPARATOR_CHAR read -r -a dbArray <<< "$DATABASES_ALL_EXCLUDE_LIST"
|
IFS=$PATH_SEPARATOR_CHAR read -r -a dbArray <<< "$DATABASES_ALL_EXCLUDE_LIST"
|
||||||
for j in "${dbArray[@]}"; do
|
for j in "${dbArray[@]}"; do
|
||||||
if [ "$dbName" == "$j" ]; then
|
if [ "$dbName" == "$j" ]; then
|
||||||
dbBackup=0
|
dbBackup=0
|
||||||
@ -1568,7 +1568,7 @@ function ListDatabases {
|
|||||||
done
|
done
|
||||||
else
|
else
|
||||||
dbBackup=0
|
dbBackup=0
|
||||||
IFs=$PATH_SEPARATOR_CHAR read -r -a dbArray <<< "$DATABASES_LIST"
|
IFS=$PATH_SEPARATOR_CHAR read -r -a dbArray <<< "$DATABASES_LIST"
|
||||||
for j in "${dbArray[@]}"; do
|
for j in "${dbArray[@]}"; do
|
||||||
if [ "$dbName" == "$j" ]; then
|
if [ "$dbName" == "$j" ]; then
|
||||||
dbBackup=1
|
dbBackup=1
|
||||||
@ -1694,11 +1694,13 @@ function ListRecursiveBackupDirectories {
|
|||||||
|
|
||||||
if [ $file_exclude -eq 0 ]; then
|
if [ $file_exclude -eq 0 ]; then
|
||||||
if [ "$FILE_RECURSIVE_BACKUP_TASKS" == "" ]; then
|
if [ "$FILE_RECURSIVE_BACKUP_TASKS" == "" ]; then
|
||||||
|
FILE_SIZE_LIST_LOCAL="\"$line\""
|
||||||
|
FILE_SIZE_LIST_REMOTE="\'$line\'"
|
||||||
FILE_RECURSIVE_BACKUP_TASKS="$line"
|
FILE_RECURSIVE_BACKUP_TASKS="$line"
|
||||||
FILE_SIZE_LIST="$(EscapeSpaces $line)"
|
|
||||||
else
|
else
|
||||||
|
FILE_SIZE_LIST_LOCAL="$FILE_SIZE_LIST_LOCAL \"$line\""
|
||||||
|
FILE_SIZE_LIST_REMOTE="$FILE_SIZE_LIST_REMOTE \'$line\'"
|
||||||
FILE_RECURSIVE_BACKUP_TASKS="$FILE_RECURSIVE_BACKUP_TASKS$PATH_SEPARATOR_CHAR$line"
|
FILE_RECURSIVE_BACKUP_TASKS="$FILE_RECURSIVE_BACKUP_TASKS$PATH_SEPARATOR_CHAR$line"
|
||||||
FILE_SIZE_LIST="$FILE_SIZE_LIST $(EscapeSpaces $line)"
|
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
FILE_RECURSIVE_EXCLUDED_TASKS="$FILE_RECURSIVE_EXCLUDED_TASKS$PATH_SEPARATOR_CHAR$line"
|
FILE_RECURSIVE_EXCLUDED_TASKS="$FILE_RECURSIVE_EXCLUDED_TASKS$PATH_SEPARATOR_CHAR$line"
|
||||||
@ -1708,7 +1710,14 @@ function ListRecursiveBackupDirectories {
|
|||||||
|
|
||||||
IFS=$PATH_SEPARATOR_CHAR read -r -a fileArray <<< "$DIRECTORY_LIST"
|
IFS=$PATH_SEPARATOR_CHAR read -r -a fileArray <<< "$DIRECTORY_LIST"
|
||||||
for directory in "${fileArray[@]}"; do
|
for directory in "${fileArray[@]}"; do
|
||||||
FILE_SIZE_LIST="$FILE_SIZE_LIST $(EscapeSpaces $directory)"
|
if [ "$FILE_SIZE_LIST_LOCAL" == "" ]; then
|
||||||
|
FILE_SIZE_LIST_LOCAL="\"$directory\""
|
||||||
|
FILE_SIZE_LIST_REMOTE="\'$directory\'"
|
||||||
|
else
|
||||||
|
FILE_SIZE_LIST_LOCAL="$FILE_SIZE_LIST_LOCAL \"$directory\""
|
||||||
|
FILE_SIZE_LIST_REMOTE="$FILE_SIZE_LIST_REMOTE \'$directory\'"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$FILE_BACKUP_TASKS" == "" ]; then
|
if [ "$FILE_BACKUP_TASKS" == "" ]; then
|
||||||
FILE_BACKUP_TASKS="$directory"
|
FILE_BACKUP_TASKS="$directory"
|
||||||
else
|
else
|
||||||
@ -1724,7 +1733,8 @@ function _GetDirectoriesSizeLocal {
|
|||||||
local cmd
|
local cmd
|
||||||
|
|
||||||
# No sudo here, assuming you should have all the necessary rights
|
# No sudo here, assuming you should have all the necessary rights
|
||||||
cmd='echo "'$dir_list'" | xargs du -cs | tail -n1 | cut -f1 > '$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID 2> $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID
|
# This is not pretty, but works with all supported systems
|
||||||
|
cmd="du -cs $dir_list | tail -n1 | cut -f1 > $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID 2> $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID"
|
||||||
Logger "cmd: $cmd" "DEBUG"
|
Logger "cmd: $cmd" "DEBUG"
|
||||||
eval "$cmd" &
|
eval "$cmd" &
|
||||||
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_FILE_TASK $HARD_MAX_EXEC_TIME_FILE_TASK ${FUNCNAME[0]} false true $KEEP_LOGGING
|
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_FILE_TASK $HARD_MAX_EXEC_TIME_FILE_TASK ${FUNCNAME[0]} false true $KEEP_LOGGING
|
||||||
@ -1755,7 +1765,7 @@ function _GetDirectoriesSizeRemote {
|
|||||||
local cmd
|
local cmd
|
||||||
|
|
||||||
# Error output is different from stdout because not all files in list may fail at once
|
# Error output is different from stdout because not all files in list may fail at once
|
||||||
cmd=$SSH_CMD' "echo '$dir_list' | xargs '$COMMAND_SUDO' du -cs | tail -n1 | cut -f1" > '$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID' 2> '$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID
|
cmd=$SSH_CMD' '$COMMAND_SUDO' du -cs '$dir_list' | tail -n1 | cut -f1 > '$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID' 2> '$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID
|
||||||
Logger "cmd: $cmd" "DEBUG"
|
Logger "cmd: $cmd" "DEBUG"
|
||||||
eval "$cmd" &
|
eval "$cmd" &
|
||||||
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_FILE_TASK $HARD_MAX_EXEC_TIME_FILE_TASK ${FUNCNAME[0]} false true $KEEP_LOGGING
|
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_FILE_TASK $HARD_MAX_EXEC_TIME_FILE_TASK ${FUNCNAME[0]} false true $KEEP_LOGGING
|
||||||
@ -1785,11 +1795,11 @@ function GetDirectoriesSize {
|
|||||||
|
|
||||||
if [ "$BACKUP_TYPE" == "local" ] || [ "$BACKUP_TYPE" == "push" ]; then
|
if [ "$BACKUP_TYPE" == "local" ] || [ "$BACKUP_TYPE" == "push" ]; then
|
||||||
if [ "$FILE_BACKUP" != "no" ]; then
|
if [ "$FILE_BACKUP" != "no" ]; then
|
||||||
_GetDirectoriesSizeLocal "$FILE_SIZE_LIST"
|
_GetDirectoriesSizeLocal "$FILE_SIZE_LIST_LOCAL"
|
||||||
fi
|
fi
|
||||||
elif [ "$BACKUP_TYPE" == "pull" ]; then
|
elif [ "$BACKUP_TYPE" == "pull" ]; then
|
||||||
if [ "$FILE_BACKUP" != "no" ]; then
|
if [ "$FILE_BACKUP" != "no" ]; then
|
||||||
_GetDirectoriesSizeRemote "$FILE_SIZE_LIST"
|
_GetDirectoriesSizeRemote "$FILE_SIZE_LIST_REMOTE"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@ -2289,20 +2299,25 @@ function _RotateBackupsLocal {
|
|||||||
local cmd
|
local cmd
|
||||||
local path
|
local path
|
||||||
|
|
||||||
find "$backup_path" -iname "*.$PROGRAM.*" -print0 | while IFS= read -r -d $'\0' backup; do
|
#TODO(low): check if mindepth / maxdepth is compatible BSD & MSYS
|
||||||
|
find "$backup_path" -mindepth 1 -maxdepth 1 ! -iname "*.$PROGRAM.*" -print0 | while IFS= read -r -d $'\0' backup; do
|
||||||
copy=$rotate_copies
|
copy=$rotate_copies
|
||||||
while [ $copy -gt 1 ]; do
|
while [ $copy -gt 1 ]; do
|
||||||
if [ $copy -eq $rotate_copies ]; then
|
if [ $copy -eq $rotate_copies ]; then
|
||||||
cmd="rm -rf \"$backup.$PROGRAM.$copy\""
|
path="$backup.$PROGRAM.$copy"
|
||||||
Logger "cmd: $cmd" "DEBUG"
|
if [ -f "$path" ] || [ -d "$path" ]; then
|
||||||
eval "$cmd" &
|
cmd="rm -rf \"$path\""
|
||||||
WaitForTaskCompletion $! 3600 0 ${FUNCNAME[0]} false true $KEEP_LOGGING
|
Logger "cmd: $cmd" "DEBUG"
|
||||||
if [ $? != 0 ]; then
|
eval "$cmd" &
|
||||||
Logger "Cannot delete oldest copy [$backup.$PROGRAM.$copy]." "ERROR"
|
WaitForTaskCompletion $! 3600 0 ${FUNCNAME[0]} false true $KEEP_LOGGING
|
||||||
|
if [ $? != 0 ]; then
|
||||||
|
Logger "Cannot delete oldest copy [$path]." "ERROR"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
path="$backup.$PROGRAM.$(($copy-1))"
|
path="$backup.$PROGRAM.$(($copy-1))"
|
||||||
if [[ -f $path || -d $path ]]; then
|
if [ -f "$path" ] || [ -d "$path" ]; then
|
||||||
cmd="mv \"$path\" \"$backup.$PROGRAM.$copy\""
|
cmd="mv \"$path\" \"$backup.$PROGRAM.$copy\""
|
||||||
Logger "cmd: $cmd" "DEBUG"
|
Logger "cmd: $cmd" "DEBUG"
|
||||||
eval "$cmd" &
|
eval "$cmd" &
|
||||||
@ -2393,19 +2408,22 @@ function RemoteLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _RotateBackupsRemoteSSH {
|
function _RotateBackupsRemoteSSH {
|
||||||
find "$backup_path" -iname "*.$PROGRAM.*" -print0 | while IFS= read -r -d $'\0' backup; do
|
find "$backup_path" -mindepth 1 -maxdepth 1 ! -iname "*.$PROGRAM.*" -print0 | while IFS= read -r -d $'\0' backup; do
|
||||||
copy=$rotate_copies
|
copy=$rotate_copies
|
||||||
while [ $copy -gt 1 ]; do
|
while [ $copy -gt 1 ]; do
|
||||||
if [ $copy -eq $rotate_copies ]; then
|
if [ $copy -eq $rotate_copies ]; then
|
||||||
cmd="$COMMAND_SUDO rm -rf \"$backup.$PROGRAM.$copy\""
|
path="$backup.$PROGRAM.$copy"
|
||||||
RemoteLogger "cmd: $cmd" "DEBUG"
|
if [ -f "$path" ] || [ -d "$path" ]; then
|
||||||
eval "$cmd"
|
cmd="$COMMAND_SUDO rm -rf \"$path\""
|
||||||
if [ $? != 0 ]; then
|
RemoteLogger "cmd: $cmd" "DEBUG"
|
||||||
RemoteLogger "Cannot delete oldest copy [$backup.$PROGRAM.$copy]." "ERROR"
|
eval "$cmd"
|
||||||
|
if [ $? != 0 ]; then
|
||||||
|
RemoteLogger "Cannot delete oldest copy [$path]." "ERROR"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
path="$backup.$PROGRAM.$(($copy-1))"
|
path="$backup.$PROGRAM.$(($copy-1))"
|
||||||
if [[ -f $path || -d $path ]]; then
|
if [ -f "$path" ] || [ -d "$path" ]; then
|
||||||
cmd="$COMMAND_SUDO mv \"$path\" \"$backup.$PROGRAM.$copy\""
|
cmd="$COMMAND_SUDO mv \"$path\" \"$backup.$PROGRAM.$copy\""
|
||||||
RemoteLogger "cmd: $cmd" "DEBUG"
|
RemoteLogger "cmd: $cmd" "DEBUG"
|
||||||
eval "$cmd"
|
eval "$cmd"
|
||||||
@ -2466,7 +2484,7 @@ function RotateBackups {
|
|||||||
local rotate_copies="${2}"
|
local rotate_copies="${2}"
|
||||||
__CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
|
__CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
|
||||||
|
|
||||||
Logger "Rotating backups." "NOTICE"
|
Logger "Rotating backups in [$backup_path] for [$rotate_copies] copies." "NOTICE"
|
||||||
|
|
||||||
if [ "$BACKUP_TYPE" == "local" ] || [ "$BACKUP_TYPE" == "pull" ]; then
|
if [ "$BACKUP_TYPE" == "local" ] || [ "$BACKUP_TYPE" == "pull" ]; then
|
||||||
_RotateBackupsLocal "$backup_path" "$rotate_copies"
|
_RotateBackupsLocal "$backup_path" "$rotate_copies"
|
||||||
|
@ -3,11 +3,16 @@ SUBPROGRAM=obackup
|
|||||||
PROGRAM="$SUBPROGRAM-batch" # Batch program to run osync / obackup instances sequentially and rerun failed ones
|
PROGRAM="$SUBPROGRAM-batch" # Batch program to run osync / obackup instances sequentially and rerun failed ones
|
||||||
AUTHOR="(L) 2013-2016 by Orsiris de Jong"
|
AUTHOR="(L) 2013-2016 by Orsiris de Jong"
|
||||||
CONTACT="http://www.netpower.fr - ozy@netpower.fr"
|
CONTACT="http://www.netpower.fr - ozy@netpower.fr"
|
||||||
PROGRAM_BUILD=2016081703
|
PROGRAM_BUILD=2016081704
|
||||||
|
|
||||||
## Runs an osync /obackup instance for every conf file found
|
## Runs an osync /obackup instance for every conf file found
|
||||||
## If an instance fails, run it again if time permits
|
## If an instance fails, run it again if time permits
|
||||||
|
|
||||||
|
if ! type "$BASH" > /dev/null; then
|
||||||
|
echo "Please run this script only with bash shell. Tested on bash >= 3.2"
|
||||||
|
exit 127
|
||||||
|
fi
|
||||||
|
|
||||||
## Configuration file path. The path where all the osync / obackup conf files are, usually /etc/osync or /etc/obackup
|
## Configuration file path. The path where all the osync / obackup conf files are, usually /etc/osync or /etc/obackup
|
||||||
CONF_FILE_PATH=/etc/$SUBPROGRAM
|
CONF_FILE_PATH=/etc/$SUBPROGRAM
|
||||||
|
|
||||||
@ -110,7 +115,7 @@ function Batch {
|
|||||||
wait $!
|
wait $!
|
||||||
result=$?
|
result=$?
|
||||||
if [ $result != 0 ]; then
|
if [ $result != 0 ]; then
|
||||||
if [ $result == 1 ] || [ $result == 120 ] || [ $result == 128 ]; then
|
if [ $result == 1 ] || [ $result == 128 ]; then # Do not handle exit code 127 because it is already handled here
|
||||||
Logger "Run instance $(basename $confFile) failed with exit code [$result]." "ERROR"
|
Logger "Run instance $(basename $confFile) failed with exit code [$result]." "ERROR"
|
||||||
if [ "$runAgainList" == "" ]; then
|
if [ "$runAgainList" == "" ]; then
|
||||||
runAgainList="$confFile"
|
runAgainList="$confFile"
|
||||||
|
90
obackup.sh
90
obackup.sh
@ -1,22 +1,21 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
#TODO: test bad return of _GetDirectoriesSizeRemote
|
#TODO: test bad return of _GetDirectoriesSizeRemote
|
||||||
#TODO(critical): fix double path in rotate functions (switching from ls to find)
|
#TODO(critical): test RotateCopies remote
|
||||||
#TODO(high): check paths with spaces (again)
|
#TODO(high): check paths with spaces (again) - fails
|
||||||
#TODO(low): investigate all exit codes and adapt depending on WARN / ERROR so obackup-batch won't rerun WARN runs
|
#TODO(low): doc obackup-rerun is minimal 1 and not 0
|
||||||
#TODO(low): obackup-rerun is minimal 1 and not 0
|
|
||||||
|
|
||||||
###### Remote push/pull (or local) backup script for files & databases
|
###### Remote push/pull (or local) backup script for files & databases
|
||||||
PROGRAM="obackup"
|
PROGRAM="obackup"
|
||||||
AUTHOR="(C) 2013-2016 by Orsiris de Jong"
|
AUTHOR="(C) 2013-2016 by Orsiris de Jong"
|
||||||
CONTACT="http://www.netpower.fr/obackup - ozy@netpower.fr"
|
CONTACT="http://www.netpower.fr/obackup - ozy@netpower.fr"
|
||||||
PROGRAM_VERSION=2.1-dev
|
PROGRAM_VERSION=2.1-dev
|
||||||
PROGRAM_BUILD=2016081702
|
PROGRAM_BUILD=2016081803
|
||||||
IS_STABLE=no
|
IS_STABLE=no
|
||||||
|
|
||||||
#### MINIMAL-FUNCTION-SET BEGIN ####
|
#### MINIMAL-FUNCTION-SET BEGIN ####
|
||||||
|
|
||||||
## FUNC_BUILD=2016081605
|
## FUNC_BUILD=2016081701
|
||||||
## BEGIN Generic functions for osync & obackup written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr
|
## BEGIN Generic functions for osync & obackup written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr
|
||||||
|
|
||||||
## type -p does not work on platforms other than linux (bash). If if does not work, always assume output is not a zero exitcode
|
## type -p does not work on platforms other than linux (bash). If if does not work, always assume output is not a zero exitcode
|
||||||
@ -601,7 +600,7 @@ function WaitForTaskCompletion {
|
|||||||
if kill -0 $pid > /dev/null 2>&1; then
|
if kill -0 $pid > /dev/null 2>&1; then
|
||||||
# Handle uninterruptible sleep state or zombies by ommiting them from running process array
|
# Handle uninterruptible sleep state or zombies by ommiting them from running process array
|
||||||
#TODO(high): have this tested on *BSD, Mac & Win
|
#TODO(high): have this tested on *BSD, Mac & Win
|
||||||
pidState=$(ps -p$pid -o state=)
|
pidState=$(ps -p$pid -o state= 2 > /dev/null)
|
||||||
if [ "$pidState" != "D" ] && [ "$pidState" != "Z" ]; then
|
if [ "$pidState" != "D" ] && [ "$pidState" != "Z" ]; then
|
||||||
newPidsArray+=($pid)
|
newPidsArray+=($pid)
|
||||||
fi
|
fi
|
||||||
@ -713,7 +712,7 @@ function EscapeSpaces {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function IsNumeric {
|
function IsNumeric {
|
||||||
eval "local value=\"${1}\"" # Needed so variable variables can be processed
|
eval "local value=\"${1}\"" # Needed eval so variable variables can be processed
|
||||||
|
|
||||||
local re="^-?[0-9]+([.][0-9]+)?$"
|
local re="^-?[0-9]+([.][0-9]+)?$"
|
||||||
if [[ $value =~ $re ]]; then
|
if [[ $value =~ $re ]]; then
|
||||||
@ -742,9 +741,9 @@ function urlEncode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function urlDecode {
|
function urlDecode {
|
||||||
local url_encoded="${1//+/ }"
|
local url_encoded="${1//+/ }"
|
||||||
|
|
||||||
printf '%b' "${url_encoded//%/\\x}"
|
printf '%b' "${url_encoded//%/\\x}"
|
||||||
}
|
}
|
||||||
|
|
||||||
function GetLocalOS {
|
function GetLocalOS {
|
||||||
@ -1267,7 +1266,8 @@ PARTIAL_DIR=".obackup_workdir_partial"
|
|||||||
# $FILE_BACKUP_TASKS list of directories to backup, found in config file
|
# $FILE_BACKUP_TASKS list of directories to backup, found in config file
|
||||||
# $FILE_RECURSIVE_BACKUP_TASKS, list of directories to backup, computed from config file recursive list
|
# $FILE_RECURSIVE_BACKUP_TASKS, list of directories to backup, computed from config file recursive list
|
||||||
# $FILE_RECURSIVE_EXCLUDED_TASKS, list of all directories excluded from recursive list
|
# $FILE_RECURSIVE_EXCLUDED_TASKS, list of all directories excluded from recursive list
|
||||||
# $FILE_SIZE_LIST, list of all directories to include in GetDirectoriesSize
|
# $FILE_SIZE_LIST_LOCAL, list of all directories to include in GetDirectoriesSize, enclosed by escaped doublequotes for local command
|
||||||
|
# $FILE_SIZE_LIST_LOCAL, list of all directories to include in GetDirectoriesSize, enclosed by escaped singlequotes for remote command
|
||||||
|
|
||||||
CAN_BACKUP_SQL=1
|
CAN_BACKUP_SQL=1
|
||||||
CAN_BACKUP_FILES=1
|
CAN_BACKUP_FILES=1
|
||||||
@ -1480,7 +1480,7 @@ function ListDatabases {
|
|||||||
|
|
||||||
if [ "$DATABASES_ALL" == "yes" ]; then
|
if [ "$DATABASES_ALL" == "yes" ]; then
|
||||||
dbBackup=1
|
dbBackup=1
|
||||||
IFs=$PATH_SEPARATOR_CHAR read -r -a dbArray <<< "$DATABASES_ALL_EXCLUDE_LIST"
|
IFS=$PATH_SEPARATOR_CHAR read -r -a dbArray <<< "$DATABASES_ALL_EXCLUDE_LIST"
|
||||||
for j in "${dbArray[@]}"; do
|
for j in "${dbArray[@]}"; do
|
||||||
if [ "$dbName" == "$j" ]; then
|
if [ "$dbName" == "$j" ]; then
|
||||||
dbBackup=0
|
dbBackup=0
|
||||||
@ -1488,7 +1488,7 @@ function ListDatabases {
|
|||||||
done
|
done
|
||||||
else
|
else
|
||||||
dbBackup=0
|
dbBackup=0
|
||||||
IFs=$PATH_SEPARATOR_CHAR read -r -a dbArray <<< "$DATABASES_LIST"
|
IFS=$PATH_SEPARATOR_CHAR read -r -a dbArray <<< "$DATABASES_LIST"
|
||||||
for j in "${dbArray[@]}"; do
|
for j in "${dbArray[@]}"; do
|
||||||
if [ "$dbName" == "$j" ]; then
|
if [ "$dbName" == "$j" ]; then
|
||||||
dbBackup=1
|
dbBackup=1
|
||||||
@ -1611,11 +1611,13 @@ function ListRecursiveBackupDirectories {
|
|||||||
|
|
||||||
if [ $file_exclude -eq 0 ]; then
|
if [ $file_exclude -eq 0 ]; then
|
||||||
if [ "$FILE_RECURSIVE_BACKUP_TASKS" == "" ]; then
|
if [ "$FILE_RECURSIVE_BACKUP_TASKS" == "" ]; then
|
||||||
|
FILE_SIZE_LIST_LOCAL="\"$line\""
|
||||||
|
FILE_SIZE_LIST_REMOTE="\'$line\'"
|
||||||
FILE_RECURSIVE_BACKUP_TASKS="$line"
|
FILE_RECURSIVE_BACKUP_TASKS="$line"
|
||||||
FILE_SIZE_LIST="$(EscapeSpaces $line)"
|
|
||||||
else
|
else
|
||||||
|
FILE_SIZE_LIST_LOCAL="$FILE_SIZE_LIST_LOCAL \"$line\""
|
||||||
|
FILE_SIZE_LIST_REMOTE="$FILE_SIZE_LIST_REMOTE \'$line\'"
|
||||||
FILE_RECURSIVE_BACKUP_TASKS="$FILE_RECURSIVE_BACKUP_TASKS$PATH_SEPARATOR_CHAR$line"
|
FILE_RECURSIVE_BACKUP_TASKS="$FILE_RECURSIVE_BACKUP_TASKS$PATH_SEPARATOR_CHAR$line"
|
||||||
FILE_SIZE_LIST="$FILE_SIZE_LIST $(EscapeSpaces $line)"
|
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
FILE_RECURSIVE_EXCLUDED_TASKS="$FILE_RECURSIVE_EXCLUDED_TASKS$PATH_SEPARATOR_CHAR$line"
|
FILE_RECURSIVE_EXCLUDED_TASKS="$FILE_RECURSIVE_EXCLUDED_TASKS$PATH_SEPARATOR_CHAR$line"
|
||||||
@ -1625,7 +1627,14 @@ function ListRecursiveBackupDirectories {
|
|||||||
|
|
||||||
IFS=$PATH_SEPARATOR_CHAR read -r -a fileArray <<< "$DIRECTORY_LIST"
|
IFS=$PATH_SEPARATOR_CHAR read -r -a fileArray <<< "$DIRECTORY_LIST"
|
||||||
for directory in "${fileArray[@]}"; do
|
for directory in "${fileArray[@]}"; do
|
||||||
FILE_SIZE_LIST="$FILE_SIZE_LIST $(EscapeSpaces $directory)"
|
if [ "$FILE_SIZE_LIST_LOCAL" == "" ]; then
|
||||||
|
FILE_SIZE_LIST_LOCAL="\"$directory\""
|
||||||
|
FILE_SIZE_LIST_REMOTE="\'$directory\'"
|
||||||
|
else
|
||||||
|
FILE_SIZE_LIST_LOCAL="$FILE_SIZE_LIST_LOCAL \"$directory\""
|
||||||
|
FILE_SIZE_LIST_REMOTE="$FILE_SIZE_LIST_REMOTE \'$directory\'"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$FILE_BACKUP_TASKS" == "" ]; then
|
if [ "$FILE_BACKUP_TASKS" == "" ]; then
|
||||||
FILE_BACKUP_TASKS="$directory"
|
FILE_BACKUP_TASKS="$directory"
|
||||||
else
|
else
|
||||||
@ -1640,7 +1649,8 @@ function _GetDirectoriesSizeLocal {
|
|||||||
local cmd
|
local cmd
|
||||||
|
|
||||||
# No sudo here, assuming you should have all the necessary rights
|
# No sudo here, assuming you should have all the necessary rights
|
||||||
cmd='echo "'$dir_list'" | xargs du -cs | tail -n1 | cut -f1 > '$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID 2> $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID
|
# This is not pretty, but works with all supported systems
|
||||||
|
cmd="du -cs $dir_list | tail -n1 | cut -f1 > $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID 2> $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID"
|
||||||
Logger "cmd: $cmd" "DEBUG"
|
Logger "cmd: $cmd" "DEBUG"
|
||||||
eval "$cmd" &
|
eval "$cmd" &
|
||||||
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_FILE_TASK $HARD_MAX_EXEC_TIME_FILE_TASK ${FUNCNAME[0]} false true $KEEP_LOGGING
|
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_FILE_TASK $HARD_MAX_EXEC_TIME_FILE_TASK ${FUNCNAME[0]} false true $KEEP_LOGGING
|
||||||
@ -1670,7 +1680,7 @@ function _GetDirectoriesSizeRemote {
|
|||||||
local cmd
|
local cmd
|
||||||
|
|
||||||
# Error output is different from stdout because not all files in list may fail at once
|
# Error output is different from stdout because not all files in list may fail at once
|
||||||
cmd=$SSH_CMD' "echo '$dir_list' | xargs '$COMMAND_SUDO' du -cs | tail -n1 | cut -f1" > '$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID' 2> '$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID
|
cmd=$SSH_CMD' '$COMMAND_SUDO' du -cs '$dir_list' | tail -n1 | cut -f1 > '$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID' 2> '$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID
|
||||||
Logger "cmd: $cmd" "DEBUG"
|
Logger "cmd: $cmd" "DEBUG"
|
||||||
eval "$cmd" &
|
eval "$cmd" &
|
||||||
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_FILE_TASK $HARD_MAX_EXEC_TIME_FILE_TASK ${FUNCNAME[0]} false true $KEEP_LOGGING
|
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_FILE_TASK $HARD_MAX_EXEC_TIME_FILE_TASK ${FUNCNAME[0]} false true $KEEP_LOGGING
|
||||||
@ -1699,11 +1709,11 @@ function GetDirectoriesSize {
|
|||||||
|
|
||||||
if [ "$BACKUP_TYPE" == "local" ] || [ "$BACKUP_TYPE" == "push" ]; then
|
if [ "$BACKUP_TYPE" == "local" ] || [ "$BACKUP_TYPE" == "push" ]; then
|
||||||
if [ "$FILE_BACKUP" != "no" ]; then
|
if [ "$FILE_BACKUP" != "no" ]; then
|
||||||
_GetDirectoriesSizeLocal "$FILE_SIZE_LIST"
|
_GetDirectoriesSizeLocal "$FILE_SIZE_LIST_LOCAL"
|
||||||
fi
|
fi
|
||||||
elif [ "$BACKUP_TYPE" == "pull" ]; then
|
elif [ "$BACKUP_TYPE" == "pull" ]; then
|
||||||
if [ "$FILE_BACKUP" != "no" ]; then
|
if [ "$FILE_BACKUP" != "no" ]; then
|
||||||
_GetDirectoriesSizeRemote "$FILE_SIZE_LIST"
|
_GetDirectoriesSizeRemote "$FILE_SIZE_LIST_REMOTE"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@ -2187,20 +2197,25 @@ function _RotateBackupsLocal {
|
|||||||
local cmd
|
local cmd
|
||||||
local path
|
local path
|
||||||
|
|
||||||
find "$backup_path" -iname "*.$PROGRAM.*" -print0 | while IFS= read -r -d $'\0' backup; do
|
#TODO(low): check if mindepth / maxdepth is compatible BSD & MSYS
|
||||||
|
find "$backup_path" -mindepth 1 -maxdepth 1 ! -iname "*.$PROGRAM.*" -print0 | while IFS= read -r -d $'\0' backup; do
|
||||||
copy=$rotate_copies
|
copy=$rotate_copies
|
||||||
while [ $copy -gt 1 ]; do
|
while [ $copy -gt 1 ]; do
|
||||||
if [ $copy -eq $rotate_copies ]; then
|
if [ $copy -eq $rotate_copies ]; then
|
||||||
cmd="rm -rf \"$backup.$PROGRAM.$copy\""
|
path="$backup.$PROGRAM.$copy"
|
||||||
Logger "cmd: $cmd" "DEBUG"
|
if [ -f "$path" ] || [ -d "$path" ]; then
|
||||||
eval "$cmd" &
|
cmd="rm -rf \"$path\""
|
||||||
WaitForTaskCompletion $! 3600 0 ${FUNCNAME[0]} false true $KEEP_LOGGING
|
Logger "cmd: $cmd" "DEBUG"
|
||||||
if [ $? != 0 ]; then
|
eval "$cmd" &
|
||||||
Logger "Cannot delete oldest copy [$backup.$PROGRAM.$copy]." "ERROR"
|
WaitForTaskCompletion $! 3600 0 ${FUNCNAME[0]} false true $KEEP_LOGGING
|
||||||
|
if [ $? != 0 ]; then
|
||||||
|
Logger "Cannot delete oldest copy [$path]." "ERROR"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
path="$backup.$PROGRAM.$(($copy-1))"
|
path="$backup.$PROGRAM.$(($copy-1))"
|
||||||
if [[ -f $path || -d $path ]]; then
|
if [ -f "$path" ] || [ -d "$path" ]; then
|
||||||
cmd="mv \"$path\" \"$backup.$PROGRAM.$copy\""
|
cmd="mv \"$path\" \"$backup.$PROGRAM.$copy\""
|
||||||
Logger "cmd: $cmd" "DEBUG"
|
Logger "cmd: $cmd" "DEBUG"
|
||||||
eval "$cmd" &
|
eval "$cmd" &
|
||||||
@ -2285,19 +2300,22 @@ function RemoteLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _RotateBackupsRemoteSSH {
|
function _RotateBackupsRemoteSSH {
|
||||||
find "$backup_path" -iname "*.$PROGRAM.*" -print0 | while IFS= read -r -d $'\0' backup; do
|
find "$backup_path" -mindepth 1 -maxdepth 1 ! -iname "*.$PROGRAM.*" -print0 | while IFS= read -r -d $'\0' backup; do
|
||||||
copy=$rotate_copies
|
copy=$rotate_copies
|
||||||
while [ $copy -gt 1 ]; do
|
while [ $copy -gt 1 ]; do
|
||||||
if [ $copy -eq $rotate_copies ]; then
|
if [ $copy -eq $rotate_copies ]; then
|
||||||
cmd="$COMMAND_SUDO rm -rf \"$backup.$PROGRAM.$copy\""
|
path="$backup.$PROGRAM.$copy"
|
||||||
RemoteLogger "cmd: $cmd" "DEBUG"
|
if [ -f "$path" ] || [ -d "$path" ]; then
|
||||||
eval "$cmd"
|
cmd="$COMMAND_SUDO rm -rf \"$path\""
|
||||||
if [ $? != 0 ]; then
|
RemoteLogger "cmd: $cmd" "DEBUG"
|
||||||
RemoteLogger "Cannot delete oldest copy [$backup.$PROGRAM.$copy]." "ERROR"
|
eval "$cmd"
|
||||||
|
if [ $? != 0 ]; then
|
||||||
|
RemoteLogger "Cannot delete oldest copy [$path]." "ERROR"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
path="$backup.$PROGRAM.$(($copy-1))"
|
path="$backup.$PROGRAM.$(($copy-1))"
|
||||||
if [[ -f $path || -d $path ]]; then
|
if [ -f "$path" ] || [ -d "$path" ]; then
|
||||||
cmd="$COMMAND_SUDO mv \"$path\" \"$backup.$PROGRAM.$copy\""
|
cmd="$COMMAND_SUDO mv \"$path\" \"$backup.$PROGRAM.$copy\""
|
||||||
RemoteLogger "cmd: $cmd" "DEBUG"
|
RemoteLogger "cmd: $cmd" "DEBUG"
|
||||||
eval "$cmd"
|
eval "$cmd"
|
||||||
@ -2357,7 +2375,7 @@ function RotateBackups {
|
|||||||
local backup_path="${1}"
|
local backup_path="${1}"
|
||||||
local rotate_copies="${2}"
|
local rotate_copies="${2}"
|
||||||
|
|
||||||
Logger "Rotating backups." "NOTICE"
|
Logger "Rotating backups in [$backup_path] for [$rotate_copies] copies." "NOTICE"
|
||||||
|
|
||||||
if [ "$BACKUP_TYPE" == "local" ] || [ "$BACKUP_TYPE" == "pull" ]; then
|
if [ "$BACKUP_TYPE" == "local" ] || [ "$BACKUP_TYPE" == "pull" ]; then
|
||||||
_RotateBackupsLocal "$backup_path" "$rotate_copies"
|
_RotateBackupsLocal "$backup_path" "$rotate_copies"
|
||||||
|
Loading…
Reference in New Issue
Block a user