diff --git a/Makefile b/Makefile index 89a1867..7252f1f 100644 --- a/Makefile +++ b/Makefile @@ -18,8 +18,8 @@ help: @echo ' tests run tests from $(TESTS_DIR)' @echo ' lint run shellcheck' @echo ' manpages build manual pages from $(DOCS_DIR)' - @echo ' install install boring-backup with prefix' - @echo ' uninstall uninstall boring-backup with prefix' + @echo ' install install boring_backup with prefix' + @echo ' uninstall uninstall boring_backup with prefix' @echo @echo 'prefix examples: $$HOME/.local, /usr/local, /usr/bin' @echo See README for more info. @@ -31,7 +31,7 @@ tests: done lint: - shellcheck $(SRC_DIR)/boring-backup + shellcheck $(SRC_DIR)/boring_backup shellcheck $(SRC_DIR)/lib/*.sh shellcheck $(SRC_DIR)/lib/handlers/sources/*.sh shellcheck $(SRC_DIR)/lib/handlers/targets/*.sh @@ -40,59 +40,59 @@ manpages: mkdir -pv $(BUILD_DIR)/share/man/ru/man1 # See rst2man(1) # https://docutils.sourceforge.io/docs/index.html - rst2man -v $(DOCS_DIR)/manpages/boring-backup.ru.1.rst \ - > $(BUILD_DIR)/share/man/ru/man1/boring-backup.1 + rst2man -v $(DOCS_DIR)/manpages/boring_backup.ru.1.rst \ + > $(BUILD_DIR)/share/man/ru/man1/boring_backup.1 sed -e 's/.SH NAME/.SH ИМЯ/' \ -e 's/.SH AUTHOR/.SH АВТОРЫ/' \ -e 's/.SH COPYRIGHT/.SH АВТОРСКИЕ ПРАВА/' \ - -i $(BUILD_DIR)/share/man/ru/man1/boring-backup.1 - gzip -vf9 $(BUILD_DIR)/share/man/ru/man1/boring-backup.1 + -i $(BUILD_DIR)/share/man/ru/man1/boring_backup.1 + gzip -vf9 $(BUILD_DIR)/share/man/ru/man1/boring_backup.1 html: manpages - mkdir -p $(BUILD_DIR)/share/doc/boring-backup - zcat $(BUILD_DIR)/share/man/ru/man1/boring-backup.1.gz | \ + mkdir -p $(BUILD_DIR)/share/doc/boring_backup + zcat $(BUILD_DIR)/share/man/ru/man1/boring_backup.1.gz | \ groff -man -Kutf8 -Thtml \ - > $(BUILD_DIR)/share/doc/boring-backup/boring-backup.1.html 2>/dev/null + > $(BUILD_DIR)/share/doc/boring_backup/boring_backup.1.html 2>/dev/null rm -v grohtml-*.png install: manpages @echo prefix: $$prefix - install -Dm755 $(SRC_DIR)/boring-backup $$prefix/bin/boring-backup - install -Dm644 $(SRC_DIR)/lib/lib.sh $$prefix/share/boring-backup/lib.sh - install -Dm644 $(SRC_DIR)/lib/backup.sh $$prefix/share/boring-backup/backup.sh - install -Dm644 $(SRC_DIR)/lib/common.sh $$prefix/share/boring-backup/common.sh - install -Dm644 $(SRC_DIR)/lib/source.sh $$prefix/share/boring-backup/source.sh - install -Dm644 $(SRC_DIR)/lib/uri.sh $$prefix/share/boring-backup/uri.sh - install -Dm644 $(SRC_DIR)/lib/handlers/sources/tar.sh $$prefix/share/boring-backup/handlers/sources/tar.sh - install -Dm644 $(SRC_DIR)/lib/handlers/sources/mysqldump.sh $$prefix/share/boring-backup/handlers/sources/mysqldump.sh - install -Dm644 $(SRC_DIR)/lib/handlers/sources/pg_dump.sh $$prefix/share/boring-backup/handlers/sources/pg_dump.sh - install -Dm644 $(SRC_DIR)/lib/handlers/targets/cp.sh $$prefix/share/boring-backup/handlers/targets/cp.sh - install -Dm644 $(SRC_DIR)/lib/handlers/targets/s3cmd.sh $$prefix/share/boring-backup/handlers/targets/s3cmd.sh - sed -e "s%LIBRARY=\"\$${LIBRARY:-.\/lib}\"%LIBRARY=\"\$${LIBRARY:-$$prefix\/share\/boring-backup}\"%" \ - -i $$prefix/share/boring-backup/lib.sh \ - -i $$prefix/bin/boring-backup - install -Dm664 $(BUILD_DIR)/share/man/ru/man1/boring-backup.1.gz $$prefix/share/man/ru/man1/boring-backup.1.gz + install -Dm755 $(SRC_DIR)/boring_backup $$prefix/bin/boring_backup + install -Dm644 $(SRC_DIR)/lib/lib.sh $$prefix/share/boring_backup/lib.sh + install -Dm644 $(SRC_DIR)/lib/backup.sh $$prefix/share/boring_backup/backup.sh + install -Dm644 $(SRC_DIR)/lib/common.sh $$prefix/share/boring_backup/common.sh + install -Dm644 $(SRC_DIR)/lib/source.sh $$prefix/share/boring_backup/source.sh + install -Dm644 $(SRC_DIR)/lib/uri.sh $$prefix/share/boring_backup/uri.sh + install -Dm644 $(SRC_DIR)/lib/handlers/sources/tar.sh $$prefix/share/boring_backup/handlers/sources/tar.sh + install -Dm644 $(SRC_DIR)/lib/handlers/sources/mysqldump.sh $$prefix/share/boring_backup/handlers/sources/mysqldump.sh + install -Dm644 $(SRC_DIR)/lib/handlers/sources/pg_dump.sh $$prefix/share/boring_backup/handlers/sources/pg_dump.sh + install -Dm644 $(SRC_DIR)/lib/handlers/targets/cp.sh $$prefix/share/boring_backup/handlers/targets/cp.sh + install -Dm644 $(SRC_DIR)/lib/handlers/targets/s3cmd.sh $$prefix/share/boring_backup/handlers/targets/s3cmd.sh + sed -e "s%LIBRARY=\"\$${LIBRARY:-.\/lib}\"%LIBRARY=\"\$${LIBRARY:-$$prefix\/share\/boring_backup}\"%" \ + -i $$prefix/share/boring_backup/lib.sh \ + -i $$prefix/bin/boring_backup + install -Dm664 $(BUILD_DIR)/share/man/ru/man1/boring_backup.1.gz $$prefix/share/man/ru/man1/boring_backup.1.gz uninstall: @echo prefix: $$prefix - rm $$prefix/bin/boring-backup - rm $$prefix/share/boring-backup/lib.sh - rm $$prefix/share/boring-backup/backup.sh - rm $$prefix/share/boring-backup/common.sh - rm $$prefix/share/boring-backup/source.sh - rm $$prefix/share/boring-backup/uri.sh - rm $$prefix/share/boring-backup/handlers/sources/tar.sh - rm $$prefix/share/boring-backup/handlers/sources/mysqldump.sh - rm $$prefix/share/boring-backup/handlers/sources/pg_dump.sh - rm $$prefix/share/boring-backup/handlers/targets/cp.sh - rm $$prefix/share/boring-backup/handlers/targets/s3cmd.sh - rm -rv $$prefix/share/boring-backup - rm $$prefix/share/man/ru/man1/boring-backup.1.gz + rm $$prefix/bin/boring_backup + rm $$prefix/share/boring_backup/lib.sh + rm $$prefix/share/boring_backup/backup.sh + rm $$prefix/share/boring_backup/common.sh + rm $$prefix/share/boring_backup/source.sh + rm $$prefix/share/boring_backup/uri.sh + rm $$prefix/share/boring_backup/handlers/sources/tar.sh + rm $$prefix/share/boring_backup/handlers/sources/mysqldump.sh + rm $$prefix/share/boring_backup/handlers/sources/pg_dump.sh + rm $$prefix/share/boring_backup/handlers/targets/cp.sh + rm $$prefix/share/boring_backup/handlers/targets/s3cmd.sh + rm -rv $$prefix/share/boring_backup + rm $$prefix/share/man/ru/man1/boring_backup.1.gz fixpath: - # Set boring-backup library path + # Set boring_backup library path @echo prefix: $$prefix @echo path: $$path sed -e "s%LIBRARY=\"\$${LIBRARY:-.\/lib}\"%LIBRARY=\"\$${LIBRARY:-$$path}\"%" \ - -i $$prefix/share/boring-backup/lib.sh \ - -i $$prefix/bin/boring-backup + -i $$prefix/share/boring_backup/lib.sh \ + -i $$prefix/bin/boring_backup diff --git a/docs/manpages/boring-backup.ru.1.rst b/docs/manpages/boring-backup.ru.1.rst index e226308..b651956 100644 --- a/docs/manpages/boring-backup.ru.1.rst +++ b/docs/manpages/boring-backup.ru.1.rst @@ -36,13 +36,13 @@ boring_backup - это расширяемая утилита для резерв -l, --log-file=\ `файл` Путь до файла лога. +-p, --pid-file=\ `файл` + Путь до PID-файла. + -s, --use-syslog Записывать лог в syslog вместо файла. Эта опция несовместима с опцией --log-file и переменной log_date_format. --p, --pid-file=\ `файл` - Путь до PID-файла. - ОБЗОР ----- diff --git a/src/boring_backup b/src/boring_backup index a7e2f7a..8457707 100755 --- a/src/boring_backup +++ b/src/boring_backup @@ -16,6 +16,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +set -o pipefail # trace ERR through pipes +set -o errtrace # trace ERR through 'time command' and other functions + VERSION='0.1.0' LIBRARY="${LIBRARY:-./lib}" @@ -29,10 +32,10 @@ else fi print_help() { - printf << EOF \ + printf \ "USAGE: - $0 [-hVvs] [-c \033[4mfile\033[0m] [-l \033[4mfile\033[0m] \ + %s [-hVvs] [-c \033[4mfile\033[0m] [-l \033[4mfile\033[0m] \ [-p \033[4mfile\033[0m] file ... OPTIONS: @@ -54,19 +57,18 @@ OPTIONS: -l, --log-file=\033[4mfile\033[0m Log file. + -p, --pid-file=\033[4mfile\033[0m + PID file. Default: /tmp/boring_backup.pid + -s, --use-syslog Write log into syslog via logger instead of log file. This option is incompatible with --log-file option and log_date_format variable. - -p, --pid-file=\033[4mfile\033[0m - PID file. Default: /tmp/boring_backup.pid - ENVIRONMENT: LIBRARY Path to boring_backup library. Current path is - $LIBRARY -" -EOF + %s +" "$0" "$LIBRARY" } # ---------------------------------------------------------- # @@ -132,6 +134,7 @@ while (( "$#" )); do exit 0 ;; -v|--verbose) + # shellcheck disable=SC2034 verbose_output=1 shift ;; @@ -145,15 +148,16 @@ while (( "$#" )); do log_file="$val" shift "$sft" ;; - -s|--use-syslog) - use_syslog=1 - shift - ;; -p|--pid-file|--pid-file=*) optval "$1" "$2" pid_file="$val" shift "$sft" ;; + -s|--use-syslog) + # shellcheck disable=SC2034 + use_syslog=1 + shift + ;; -*) echo "Error: Unknown option: $1" >&2 exit 1 @@ -175,11 +179,14 @@ if ! declare -F -- log > /dev/null 2>&1; then exit 1 fi +# Set up error handler +trap 'error $BASH_SOURCE $FUNCNAME $LINENO $? $BASH_COMMAND' ERR + # ---------------------------------------------------------- # # * Do backups # # ---------------------------------------------------------- # -log -V "Backup STARTED" +log -V "Backup started" # Check PID file if [ -e "$pid_file" ]; then @@ -275,7 +282,7 @@ for script in "${__args[@]}"; do done echo -e "\nBackup [Done]" -log -V "Backup FINISHED" +log -V "Backup finished successsfully" # Remove PID file rm "$pid_file" diff --git a/src/lib/common.sh b/src/lib/common.sh index 70bfa77..95833ca 100644 --- a/src/lib/common.sh +++ b/src/lib/common.sh @@ -66,22 +66,33 @@ log() { done } -handle_error() { +error() { # Handle errors # - # Usage: handle_error ERROR_MESSAGE + # Usage: error SCRIPTNAME FUNCNAME LINENO EXIT_CODE COMMAND - # Display amd log message - log -p "$*" >&2 - log -p "Check $log_file log for details." >&2 + local script lastline funcname lasterr msg + script="$1" + funcname="$2" + lastline="$3" + lasterr="$4" + shift 4 + + # Display and log message + msg="ERROR in $script:$lastline: function '$funcname': \ +command '$*' failed with exit code $lasterr" + + log -p "\e[31m$msg\nCheck $log_file log for details.\e[0m" >&2 # Run user defined error handler function if set if is_function_set on_error; then echo -e "Run \e[1mon_error()\e[0m" | log -p - on_error "$*" + on_error "$msg" fi - log -p "Backup ERROR: Exiting with previous errors" >&2; exit 1 + log -p Exiting with previous errors. >&2 + log -V Backup finished with errors. + exit 1 } is_installed() { diff --git a/src/lib/handlers/sources/mysqldump.sh b/src/lib/handlers/sources/mysqldump.sh index 16e9f7c..998a5dd 100644 --- a/src/lib/handlers/sources/mysqldump.sh +++ b/src/lib/handlers/sources/mysqldump.sh @@ -63,17 +63,10 @@ src_mysqldump() { log "Run command: $*" # shellcheck disable=SC2154 - if "$@" 2>> "$log_file" > "$sqldump"; then - # Compress file - sqldump="$(compress_file "$sqldump")" - # Append path to 'backups' array - backups+=("$sqldump") - log "Dump saved as: $sqldump" - else - remove_if_empty "$sqldump" - handle_error \ - "Error: Something went wrong when executing command:\n\t$*" - fi + "$@" > "$sqldump" |& log + sqldump="$(compress_file "$sqldump")" # Compress file + backups+=("$sqldump") # Append path to 'backups' array + log "Dump saved as: $sqldump" unset MYSQL_PWD } diff --git a/src/lib/handlers/sources/pg_dump.sh b/src/lib/handlers/sources/pg_dump.sh index 0ac2f26..90e6199 100644 --- a/src/lib/handlers/sources/pg_dump.sh +++ b/src/lib/handlers/sources/pg_dump.sh @@ -64,17 +64,10 @@ src_pg_dump() { log "Run command: $*" # shellcheck disable=SC2154 - if "$@" 2>> "$log_file" > "$sqldump"; then - # Compress dump - sqldump="$(compress_file "$sqldump")" - # Append path to 'backups' array - backups+=("$sqldump") - log "Dump file: $sqldump" - else - remove_if_empty "$sqldump" - handle_error \ - "Error: Something went wrong when executing command:\n\t$*" - fi + "$@" > "$sqldump" |& log + sqldump="$(compress_file "$sqldump")" # Compress file + backups+=("$sqldump") + log "Dump file: $sqldump" unset PGPASSWORD } diff --git a/src/lib/handlers/sources/tar.sh b/src/lib/handlers/sources/tar.sh index 90a77b5..9d78942 100644 --- a/src/lib/handlers/sources/tar.sh +++ b/src/lib/handlers/sources/tar.sh @@ -86,12 +86,7 @@ src_tar() { log "Run command: $*" # shellcheck disable=SC2154 - if "$@" 2>> "$log_file"; then - # Append path to 'backups' array - backups+=("$archive") - else - remove_if_empty "$archive" - handle_error \ - "Error: Something went wrong when executing command:\n\t$*" - fi + "$@" 2>> "$log_file" + # Append path to 'backups' array + backups+=("$archive") } diff --git a/src/lib/handlers/targets/cp.sh b/src/lib/handlers/targets/cp.sh index 1ebce1e..bcea3d1 100644 --- a/src/lib/handlers/targets/cp.sh +++ b/src/lib/handlers/targets/cp.sh @@ -59,12 +59,6 @@ tgt_cp() { set -- cp --archive "$backup" "$dst_path" log "Run command: $*" - - if "$@" 2>> "$log_file"; then - : # Success - else - handle_error \ - "Error: Something went wrong when executing command:\n\t$*" - fi + "$@" |& log done } diff --git a/src/lib/handlers/targets/s3cmd.sh b/src/lib/handlers/targets/s3cmd.sh index deb203d..dccb1ab 100644 --- a/src/lib/handlers/targets/s3cmd.sh +++ b/src/lib/handlers/targets/s3cmd.sh @@ -70,10 +70,6 @@ tgt_s3cmd() { # Upload backups # shellcheck disable=SC2154 - if "$@" 2>> "$log_file"; then - : # Success - else - handle_error \ - "Error: Something went wrong when executing command:\n\t$*" - fi + #"$@" 2>> "$log_file" + "$@" |& log } diff --git a/src/lib/source.sh b/src/lib/source.sh index 4d696c3..386a989 100644 --- a/src/lib/source.sh +++ b/src/lib/source.sh @@ -82,6 +82,7 @@ validate_targets() { __main_target="${file_targets[0]}" # Fail if __main_target's path is not a directory parse_uri "$__main_target" + # shellcheck disable=SC2154 __main_target_path="$path" # Make dirs if `make_target_dir` is set