diff --git a/bootstrap.sh b/bootstrap.sh index 93a6a6e..97fbd7b 100644 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -1,157 +1,186 @@ #!/bin/bash ### # Part of a stupid script to backup some stuff # # This bootstrap.sh file does nothing by itself but loads useful stuff. # # Author: Valerio B. # Date: Wed 5 ago 2020 ## # current directory DIR="${BASH_SOURCE%/*}" if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi # check if the standard input is not a terminal INTERACTIVE= if [ -t 0 ]; then INTERACTIVE=1 fi # # Check if this is the quiet mode # # Actually we are in quiet mode if it's not interactive. # This lazy behavior is to avoid stupid emails from the crontab # without the need to specify some --quiet etc. # Note that in quiet mode only WARN and ERROR messages are shown. # I've not created a --quiet flag because nobody is needing it. QUIET= if [ "$INTERACTIVE" != 1 ]; then QUIET=1 fi # path to the instructions file INSTRUCTIONS="$DIR/backup-instructions.conf" # path to the configuration file CONFIG="$DIR/options.conf" # no config no party if [ ! -f $CONFIG ]; then echo "missing options expected in $CONFIG" exit 1 fi # no instructions no party if [ ! -f $INSTRUCTIONS ]; then echo "missing instructions expected in $INSTRUCTIONS" exit 1 fi # default mysql commands MYSQL="mysql" MYSQLDUMP="mysqldump" # default rsync command # --archive: Try to keep all the properties # --fuzzy: Try to check if a file was renamed instead of delete and download a new one # It's efficient for example with log rotated files. # --delete: Delete the destination files if not present in the source # NOTE: we want this behaviour but it's not a good idea toghether with --fuzzy # that's why we do not use --delete but we use the next flags # --delay-updates Put all updated files into place at end (useful with fuzzy and delete modes) # --delete-delay Delete after everything (useful with fuzzy and delete modes) RSYNC="rsync --archive --fuzzy --delay-updates --delete-delay" # default base backup directory for all backups BASE="/home/backups" # default box name BOX="$(hostname)" # set to 1 to avoid any disservice (e.g. systemctl stop/start) NO_DISSERVICE= # set to 1 to do nothing PORCELAIN= # include the configuration to eventually override some options . "$CONFIG" # full pathnames to the backup directories BASEBOX="$BASE/$BOX" DAILY="$BASEBOX/daily" DAILY_FILES="$DAILY/files" DAILY_DATABASES="$DAILY/databases" DAILY_LASTLOG="$DAILY/last.log" DAILY_LASTTIME="$DAILY/last.timestamp" # apply the porcelain to the rsync command if [ "$PORCELAIN" = 1 ]; then RSYNC="$RSYNC --dry-run" fi ### # Print something # # It also put the message in the backup directory # # @param string severity # @param string message # function printthis() { local msg="[$(date)][$1] $2" # print to standard output if it's not in quiet mode if [ "$QUIET" != 1 ]; then echo "$msg" fi # put in the log file if possible if [ -f "$DAILY_LASTLOG" ]; then echo "$msg" >> "$DAILY_LASTLOG" fi } ### # Run an rsync # function copy() { # show what we are doing log "copy $*" # run the rsync command - $RSYNC $@ + if [ "$PORCELAIN" != 1 ]; then + $RSYNC $@ + fi +} + +### +# Remove a pathname +# +function drop() { + + # show what we are doing + log "drop $*" + + # well, proceed... finger crossed... with some protections + if [ "$PORCELAIN" != 1 ]; then + rm --recursive --force --one-file-system --preserve-root -- $@ + fi +} + +### +# Move something somewhere +# +function move() { + + # show what we are doing + log "move $*" + + if [ "$PORCELAIN" != 1 ]; then + mv --force $@ + fi } ### # Print a information message # # @param msg Message # function log() { printthis INFO "$1" } ### # Print a warning message # # @param msg Message # function warn() { printthis WARN "$1" } ### # Print an error message # # @param msg Message # function error() { printthis ERROR "$1" } diff --git a/rotate.sh b/rotate.sh index 6028eca..195d2d7 100755 --- a/rotate.sh +++ b/rotate.sh @@ -1,115 +1,120 @@ #!/bin/bash ### # Stupid script to rotate a backup # # Author: Valerio B. # Date: Wed 4 Ago 2020 ## # do not proceed in case of errors set -e # current directory MYDIR="$(dirname "$(realpath "$0")")" # include all the stuff and useful functions . "$MYDIR"/bootstrap.sh # arguments place="$1" days="$2" max="$3" last_timestamp_file="$place.timestamp" # current timestamp current_timestamp=$(date +%s) # show usage function show_help_rotate() { echo "USAGE" echo " $0 PATH DAYS MAX_ROTATIONS" echo "EXAMPLE" echo " $0 /home/backups 1 30" } # all the arguments must exist (just check the last one) if [ -z "$max" ]; then echo "Bad usage" show_help_rotate exit 1 fi # the place to be rotated must exist if [ ! -e "$place" ]; then error "unexisting directory '$place'" exit 2 fi # validate max parameter if [ "$max" -lt 2 ]; then echo "The MAX parameter must be greater than 1" show_help_rotate exit 3 fi # check if the last timestamp was writed if [ -f "$last_timestamp_file" ]; then # check the timestamp saved in the file timestamp=$(<"$last_timestamp_file") if [ "$timestamp" -lt 1000 ]; then echo "bad format in file $last_timestamp_file" exit fi # seconds spent from the last rotation diff_seconds=$(( "$current_timestamp" - "$timestamp" )) # expected seconds from the last rotation before continuing expected_seconds=$(( "$days" * 86400 )) # check if it's not passed enought time if [ "$diff_seconds" -lt "$expected_seconds" ]; then warn "Doing nothing: last rotation was executed $diff_seconds seconds ago (expected at least $expected_seconds)" exit fi fi # save the last timestamp before rotating everything # this will avoid even parallel rotations echo $(date +%s) > "$last_timestamp_file" +# eventually drop the last backup step +# if it does not exist, don't care +max_path="$place.$max" +drop "$max_path" + # shift all the backups after="$max" while [[ "$after" -gt 1 ]]; do before=$(( "$after" - 1 )) # do not process the root directory for no reason in the world if you type that by mistake # the --preserve-root is already implicit but... let's be sure! asd before_path="$place.$before" after_path="$place.$after" # the source must exist. asd if [ -e "$before_path" ]; then # the trailing slash means: copy files and not just the directory - copy "$before_path/" "$after_path" + move "$before_path/" "$after_path" fi #`next after="$before" done # at the end, move the base forward # the trailing slash means: copy files and not just the directory copy "$place/" "$place.1" # now you are ready to overwrite "$place"