From: Bastian Dehn Date: Sun, 17 May 2026 18:53:49 +0000 (+0200) Subject: move source files into subdir X-Git-Tag: v1.0.0^2^2~1 X-Git-Url: https://gitweb.hhaalo.de/?a=commitdiff_plain;h=ab925a8e99cbc0951b1e8ff980fdc02662964284;p=simple-backup.git move source files into subdir --- diff --git a/Makefile b/Makefile index 977ca6e..82d0126 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION=1.0.0 PACKAGE=simple-backup PACKAGENAME=$(PACKAGE)-$(VERSION)$(EXTRA_VERSION)-1-x86_64 -SRCDIR=. +SRCDIR=src BUILDDIR=build PREFIX=usr/local BINDIR=$(BUILDDIR)/$(PACKAGENAME)/$(PREFIX)/bin diff --git a/backup b/backup deleted file mode 100755 index 6380481..0000000 --- a/backup +++ /dev/null @@ -1,352 +0,0 @@ -#!/bin/bash - -errlog() -{ - local lastexit=$? - local msg="$1" - - echo "❌ ERROR: $msg" - echo "🛑 EXIT $lastexit" - return $lastexit -} - -get_backup_type() -{ - local typ="none" - - [ -f "$backup_path/day" ] && typ="day" - [ -f "$backup_path/week" ] && typ="week" - [ -f "$backup_path/month" ] && typ="month" - - echo "$typ" -} - -write_current_date() -{ - local backup_path="$1" - local current_date="$(date +%F)" - local typ=$(get_backup_type) - - mkdir --parents "history" - - echo "$current_date" > $backup_path/$typ - echo "$current_date" > "history/$typ" -} - -rotate_history() -{ - local history_file="$1" - - [ -f "$history_file" ] || return 0 - - history_lines=$(cat $history_file | wc -l) - echo "ℹ️ INFO: $history_file has $history_lines lines" - [ $history_lines -ge 100 ] \ - && savelog -c 10 -l $history_file \ - && echo "ℹ️ INFO: $history_file rotated" -} - -write_history_entry() -{ - local msg="$1" - local current_date=$(date --iso-8601=seconds) - local typ=$(get_backup_type) - - mkdir --parents "history" - rotate_history "history/history" - - echo "ℹ️ INFO: $current_date $typ $msg" - echo "$current_date $typ $msg" >> "history/history" -} - -get_backup_dir() -{ - local backup_path="$1" - local backup_name="$2" - local last_backup_number="$3" - local date=$(date +%F) - - local backup_dir= - local number= - for number in $(seq --format "%02g" $last_backup_number 99); do - backup_dir="$date"_"$number"_"$backup_name" - [ -d "$backup_path/$backup_dir" ] || break; - done - - echo $backup_dir -} - -get_last_backup_dir_path() -{ - local backup_path="$1" - local backup_name="$2" - - local last_backup_dir_path=$(find $backup_path \ - -maxdepth 1 \ - -type d \ - -name "*_""$backup_name" \ - | sort \ - | tail --lines=1) - - echo "$last_backup_dir_path" -} - -print_line() -{ - local i= - for i in {1..80}; do - printf "#" - done - - printf "\n" -} - -backup_remote_pathes() -{ - local backup_path="$1" - local machine="$2" - local last_backup_dir_path="$3" - local hardlinkopt= - local remote_user=$(cat config.yaml \ - | yq --raw-output ".machines.\"$machine\".remote_user") - [ -n "$remote_user" ] && [ $remote_user != "null" ] \ - || errlog "config.yaml missing remote_user for $machine" \ - || return $? - local host=$(cat config.yaml \ - | yq --raw-output ".machines.\"$machine\".host") - [ -n "$host" ] && [ "$host" != "null" ] \ - || errlog "config.yaml missing host for $machine" \ - || return $? - local port=$(cat config.yaml \ - | yq --raw-output ".machines.\"$machine\".port") - [ -n "$port" ] && [ "$port" != "null" ] \ - || errlog "config.yaml missing port for $machine" \ - || return $? - local pathes=$(cat config.yaml \ - | yq --raw-output ".machines.\"$machine\".pathes[]") - [ -n "$pathes" ] \ - || errlog "config.yaml missing pathes for $machine" \ - || return $? - - local YELLOW="\e[0;33m" - local LIGHTPURPLE="\e[1;35m" - local RESET="\e[0m" - - local path= - for path in $pathes; do - print_line - printf "ℹ️ INFO: machine ${LIGHTPURPLE}%s${RESET}; " "$machine" - printf "path ${YELLOW}%s${RESET}\n\n" "$path" - - [ -n "$last_backup_dir_path" ] \ - && hardlinkopt="--link-dest=$last_backup_dir_path/$machine" - - rsync --archive \ - --verbose \ - --sparse \ - --acls \ - --hard-links \ - --relative \ - --human-readable \ - $hardlinkopt \ - --rsh "ssh -p $port" \ - $remote_user@$host:$path \ - $backup_path/$machine \ - || errlog "could not backup $machine with path $path" \ - || return $? - - print_line - done -} - -backup_remotes() -{ - local backup_path="$1" - local last_backup_dir_path="$2" - local hardlinkopt= - local machines=$(cat config.yaml | yq --raw-output '.machines | keys[]') - [ -n "$machines" ] \ - || errlog "config.yaml no machines" \ - || return $? - - local machine= - for machine in $machines; do - echo "ℹ️ INFO: create directory $backup_path/$machine" - mkdir --parents $backup_path/$machine \ - || errlog "could not create directory $backup_path/$machine" \ - || return $? - - backup_remote_pathes "$backup_path" \ - "$machine" \ - "$last_backup_dir_path" \ - || return $? - done -} - -remove_backup_dir() -{ - local backup_path="$1" - local backup_name="$2" - local delete_count=$3 - - local backups=$(find $backup_path -maxdepth 1 -name "*$backup_name" \ - | sort \ - | head --lines $delete_count) - - local backup= - for backup in $backups; do - echo "🗑️ DELETE: $backup" - rm --recursive $backup - write_history_entry "deleted ${backup##*/}" - done -} - -cleanup_backups() -{ - local backup_path="$1" - local backup_name="$2" - local backup_count=$3 - - local backup_counted=$(ls --directory $backup_path/*/ \ - | grep "_$backup_name" \ - | sort \ - | wc --lines) - local delete_count=$(( backup_counted - backup_count )) - - print_line - echo - echo "ℹ️ INFO: backup count: $backup_counted" - - if [ $backup_counted -gt $backup_count ]; then - echo "ℹ️ INFO: delete backup count: $delete_count" - echo - remove_backup_dir "$backup_path" "$backup_name" $delete_count - fi - - echo - print_line -} - -is_backup_old() -{ - local backup_typ="$1" - local backup_date="$2" - local backup_month=$(date --date="$backup_date" '+%Y-%m') - local now_month=$(date '+%Y-%m') - local diff=$(( ($(date --date="$backup_date" +%s) - $(date +%s)) / 86400 )) - - case "$backup_typ" in - "day") [ $diff -ge 0 ] || return $? ;; - "week") [ $diff -ge -6 ] || return $? ;; - "month") [ "$backup_month" == "$now_month" ] || return $? ;; - *) return 0;; - esac -} - -check_backup_date() -{ - local LIGHTRED="\e[1;31m" - local LIGHTGREEN="\e[1;32m" - local RESET="\e[0m" - local color=$LIGHTGREEN - local history_path="history" - - print_line - echo - local typ= - for typ in day week month; do - if [ -f "$history_path/$typ" ]; then - color=$LIGHTGREEN - is_backup_old $typ $(cat $history_path/$typ) \ - || color=$LIGHTRED - printf "${color}last backup %s " "$typ" - printf "am %s${RESET}\n" "$(cat $history_path/$typ)" - else - printf "${LIGHTRED}no backup %s " $typ - printf "exists${RESET}\n" - fi - done - echo - print_line -} - -main() -{ - local only_check="$1" - - [ "$only_check" == "check" ] && check_backup_date && return 0 - - echo "⭐ START: backup" - - command -v yq > /dev/null \ - || errlog "command yq not found" \ - || return $? - command -v rsync > /dev/null \ - || errlog "command rsync not found" \ - || return $? - command -v ssh > /dev/null \ - || errlog "command ssh not found" \ - || return $? - [ -f "config.yaml" ] \ - || errlog "file config.yaml not found" \ - || return $? - - backup_path=$(cat config.yaml | yq --raw-output '.backup_path') - backup_name=$(cat config.yaml | yq --raw-output '.backup_name') - backup_count=$(cat config.yaml | yq --raw-output '.backup_count') - - [ -n "$backup_path" ] && [ "$backup_path" != "null" ] \ - || errlog "config.yaml missing backup_path" \ - || return $? - [ -d "$backup_path" ] \ - || errlog "directory $backup_path not exists" \ - || return $? - echo "ℹ️ INFO: backup path $backup_path" - [ -n "$backup_name" ] && [ "$backup_name" != "null" ] \ - || errlog "config.yaml missing backup_name" \ - || return $? - echo "ℹ️ INFO: backup name $backup_name" - [ -n "$backup_count" ] && [ "$backup_count" != "null" ] \ - || errlog "config.yaml missing backup_count" \ - || return $? - echo "ℹ️ INFO: backup count $backup_count" - - local last_backup_dir_path=$(get_last_backup_dir_path \ - "$backup_path" \ - "$backup_name") - echo "ℹ️ INFO: last backup dir path $last_backup_dir_path" - - local today_date=$(date +%F) - local last_backup_number=1 - [[ "$last_backup_dir_path" =~ "$today_date" ]] \ - && last_backup_number=${last_backup_dir_path##*/} \ - && last_backup_number=${last_backup_number:11:2} - local backup_dir=$(get_backup_dir \ - "$backup_path" \ - "$backup_name" \ - "$last_backup_number") - - echo "ℹ️ INFO: backup folder $backup_dir" - local backup_full_path=$backup_path/$backup_dir - echo "ℹ️ INFO: create folder $backup_full_path" - - backup_remotes \ - "$backup_full_path" \ - "$last_backup_dir_path" \ - || return $? - write_current_date "$backup_path" \ - || return $? - write_history_entry "created $backup_dir" \ - || return $? - cleanup_backups \ - "$backup_path" \ - "$backup_name" \ - $backup_count \ - || return $? - check_backup_date \ - || return $? - - echo "✅ SUCCESS: backup" -} - -main $* diff --git a/backupmount b/backupmount deleted file mode 100755 index 8bb65d7..0000000 --- a/backupmount +++ /dev/null @@ -1,168 +0,0 @@ -#!/bin/bash - -errlog() -{ - local lastexit=$? - local msg="$1" - - echo "❌ ERROR: $msg" - echo "🛑 EXIT $lastexit" - return $lastexit -} - -infolog() -{ - local lastexit=$? - local msg="$1" - - echo "ℹ️ INFO: $msg" - return $lastexit -} - -partition_mount() -{ - local media="$1" - local partition=$(cat config.yaml \ - | yq --raw-output ".media.\"$media\".partition") - [ "$partition" != "null" ] \ - || errlog "config.yaml partition for $media missing" \ - || return $? - [ -b "$partition" ] \ - || errlog "partition $partition not found" \ - || return $? - local backup_path=$(cat config.yaml \ - | yq --raw-output ".backup_path") - [ "$backup_path" != "null" ] \ - || errlog "config.yaml backup path missing" \ - || return $? - - infolog "create backup path $backup_path" - mkdir --parents "$backup_path" \ - || errlog "could not create directory $backup_path" \ - || return $? - infolog "mount partition $partition to $backup_path" - mount "$partition" "$backup_path" \ - || errlog "cloud not mount $partition to $backup_path" \ - || return $? -} - -device_mount() -{ - local media="$1" - local device="$2" - - [ -b "$device" ] \ - || infolog "block device $device for $media not found" \ - || return $? - infolog "media $media with device $device found" - local key=$(cat "config.yaml" \ - | yq --raw-output ".media.\"$media\".key") - [ "$key" != "null" ] \ - || errlog "config.yaml key for $media missing" \ - || return $? - [ -f "$key" ] \ - || errlog "key $key not exists" \ - || return $? - infolog "use key $key" - local volume=$(cat "config.yaml" \ - | yq --raw-output ".backup_volume") - [ "$volume" != "null" ] \ - || errlog "config.yaml volume for $media missing" \ - || return $? - - infolog "volume open $volume" - cryptsetup open --key-file "$key" \ - "$device" \ - "$volume" \ - || errlog "could not open $device with $key" \ - || return $? - - partition_mount "$media" || return $? -} - -mount_backup() -{ - local medias=$(cat config.yaml \ - | yq --raw-output '.media | keys[]') - - [ -n "$medias" ] && [ "$medias" != "null" ] \ - || errlog "config.yaml missing media section" \ - || return $? - - local media= - local device= - for media in $medias; do - device=$(cat config.yaml \ - | yq --raw-output ".media.\"$media\".device") - [ "$device" != "null" ] \ - || errlog "missing path for $media" \ - || return $? - device_mount "$media" "$device" && return 0 - done - - errlog "no device was mounted" -} - -umount_backup() -{ - - local backup_path=$(cat config.yaml \ - | yq --raw-output ".backup_path") - [ "$backup_path" != "null" ] \ - || errlog "config.yaml backup path missing" \ - || return $? - - infolog "umount backup path $backup_path" - umount "$backup_path" \ - || errlog "could not unmount $backup_path" \ - || return $? - - infolog "remove backup path directory $backup_path" - rmdir "$backup_path" \ - || errlog "clound not remote $backup_path" \ - || return $? - - local volume=$(cat "config.yaml" \ - | yq --raw-output ".backup_volume") - [ "$volume" != "null" ] \ - || errlog "config.yaml volume for $media missing" \ - || return $? - - infolog "close volume $volume" - cryptsetup close "$volume" \ - || errlog "could not close $volume" \ - || return $? -} - -main() -{ - local cmd="$1" - - echo "⭐ START: backupmount" - - command -v yq > /dev/null \ - || errlog "command yq not found" \ - || return $? - command -v cryptsetup > /dev/null \ - || errlog "command cryptsetup not found" \ - || return $? - - [ -n "$cmd" ] \ - || errlog "missing command" \ - || return $? - [ -f "config.yaml" ] \ - || errlog "file config.yaml not exists" \ - || return $? - - if [ "$cmd" == "mount" ]; then - mount_backup || return $? - elif [ "$cmd" == "umount" ]; then - umount_backup || return $? - else - errlog "unknown command" || return $? - fi - - echo "✅ SUCCESS: backupmount" -} - -main $* diff --git a/control b/control deleted file mode 100644 index 2449ffa..0000000 --- a/control +++ /dev/null @@ -1,8 +0,0 @@ -Package: simple-backup -Version: $VERSION -Section: admin -Priority: optional -Architecture: amd64 -Maintainer: Bastian Dehn -Description: backup bash script on rsync base -Depends: yq (>= 3.4.3-2), rsync (>= 3.4.1+ds1-5+deb13u2), ssh (>= 1:10.0p1-7+deb13u4), cryptsetup (>= 2:2.7.5-2) diff --git a/restore b/restore deleted file mode 100755 index 2020d40..0000000 --- a/restore +++ /dev/null @@ -1,184 +0,0 @@ -#!/bin/bash - -errlog() -{ - local lastexit=$? - local msg="$1" - - echo "❌ ERROR: $msg" - echo "🛑 EXIT: $lastexit" - return $lastexit -} - -useage() -{ - echo "$0 -d -n -r -p -k -o" - echo - echo " -d date from backup" - echo " -n number of backup" - echo " -r host @:" - echo " -p path" - echo " -o restore origin (delete mode)" - echo -} - -print_line() -{ - for i in {1..80}; do - printf "#" - done - - printf "\n" -} - -restore() -{ - local date="$1" - local number="$2" - local machine="$3" - local path="$4" - local origin="$5" - - local backup_path=$(cat config.yaml \ - | yq --raw-output ".backup_path") - local backup_name=$(cat config.yaml \ - | yq --raw-output ".backup_name") - local machine=$(cat config.yaml \ - | yq --raw-output \ - ".machines | keys[] | select(. == \"$machine\")") - local remote_user=$(cat config.yaml \ - | yq --raw-output ".machines.\"$machine\".remote_user") - local remote_machine=$(cat config.yaml \ - | yq --raw-output ".machines.\"$machine\".host") - local remote_port=$(cat config.yaml \ - | yq --raw-output ".machines.\"$machine\".port") - - [ -d "$backup_path" ] \ - || errlog "could not find directory $backup_path" \ - || return $? - [ -n "$machine" ] \ - || errlog "config.yaml missing machine" \ - || return $? - [ "$backup_name" != "null" ] \ - || errlog "config.yaml missing backup_name" \ - || return $? - [ "$remote_user" != "null" ] \ - || errlog "config.yaml missing remote_user" \ - || return $? - [ "$remote_machine" != "null" ] \ - || errlog "config.yaml missing host" \ - || return $? - [ "$remote_port" != "null" ] \ - || errlog "config.yaml missing port" \ - || return $? - - local backup_dir="$date"_"$number"_"$backup_name" - - [ -d "$backup_path/$backup_dir" ] \ - || errlog "could not find directory $backup_path/$backup_dir" \ - || return $? - - local restore_prefix_path="$backup_path/$backup_dir/$machine" - [ -d "$restore_prefix_path" ] \ - || errlog "could not find directory $restore_prefix_path" \ - || return $? - - local restore_path="$restore_prefix_path$path" - local remote_path="$remote_user@$remote_machine:$path" - - local mode="directory" - [[ "$path" =~ /$ ]] || mode="file" - - [ -f "$restore_path" ] || [ -d "$restore_path" ] \ - || errlog "could not find $restore_path" \ - || return $? - - echo "ℹ️ INFO: restore mode $mode" - echo - - echo "ℹ️ INFO: restore path $restore_path" - echo "ℹ️ INFO: remote path $remote_path" - echo - - [ "$origin" == "deletemode-on" ] \ - && local deletemode="--delete" \ - && echo "⚠️ WARN: delete mode on" && echo - - local ask_restore="N" - read -p "❓ QUESTION: Do you want restore? [N/y] " ask_restore - local ask_restore=${ask_restore:-N} - local ask_restore=${ask_restore,,} - echo ${ask_restore,,} - - [ "$ask_restore" == "y" ] \ - || errlog "you want not do restore" \ - || return $? - - echo "ℹ️ INFO: restoring..." - - rsync --archive \ - --verbose \ - --sparse \ - --acls \ - --hard-links \ - --human-readable \ - $deletemode \ - --rsh "ssh -p $remote_port" \ - $restore_path \ - $remote_path \ - || errlog "could not restore" \ - || return $? - - echo "ℹ️ INFO: restored" -} - -main() -{ - local date= - local number= - local machine= - local path= - local key= - local origin="deletemode-off" - - echo "⭐ START: restore" - - while getopts "d:k:n:r:p:ho" optname; do - case "$optname" in - "d") date="$OPTARG" ;; - "n") number="$OPTARG" ;; - "r") machine="$OPTARG" ;; - "p") path="$OPTARG" ;; - "o") origin="deletemode-on" ;; - "h") useage && return 0 ;; - esac - done - - command -v yq > /dev/null \ - || errlog "command yq not found" \ - || return $? - command -v rsync > /dev/null \ - || errlog "command rsync not found" \ - || return $? - command -v ssh > /dev/null \ - || errlog "command ssh not found" \ - || return $? - - [ -f "config.yaml" ] \ - || errlog "file config.yaml not found" \ - || return $? - [ -n "$date" ] || errlog "missing date (-d)" || return $? - [ -n "$number" ] || errlog "missing number (-n)" || return $? - [[ "$number" =~ [[:digit:]]{2} ]] \ - || errlog "number must two digits" \ - || return $? - [ -n "$machine" ] || errlog "missing machine (-r)" || return $? - [ -n "$path" ] || errlog "missing path (-p)" || return $? - - restore "$date" "$number" "$machine" "$path" "$origin" \ - || return $? - - echo "✅ SUCCESS: restore" -} - -main $* diff --git a/src/backup b/src/backup new file mode 100755 index 0000000..6380481 --- /dev/null +++ b/src/backup @@ -0,0 +1,352 @@ +#!/bin/bash + +errlog() +{ + local lastexit=$? + local msg="$1" + + echo "❌ ERROR: $msg" + echo "🛑 EXIT $lastexit" + return $lastexit +} + +get_backup_type() +{ + local typ="none" + + [ -f "$backup_path/day" ] && typ="day" + [ -f "$backup_path/week" ] && typ="week" + [ -f "$backup_path/month" ] && typ="month" + + echo "$typ" +} + +write_current_date() +{ + local backup_path="$1" + local current_date="$(date +%F)" + local typ=$(get_backup_type) + + mkdir --parents "history" + + echo "$current_date" > $backup_path/$typ + echo "$current_date" > "history/$typ" +} + +rotate_history() +{ + local history_file="$1" + + [ -f "$history_file" ] || return 0 + + history_lines=$(cat $history_file | wc -l) + echo "ℹ️ INFO: $history_file has $history_lines lines" + [ $history_lines -ge 100 ] \ + && savelog -c 10 -l $history_file \ + && echo "ℹ️ INFO: $history_file rotated" +} + +write_history_entry() +{ + local msg="$1" + local current_date=$(date --iso-8601=seconds) + local typ=$(get_backup_type) + + mkdir --parents "history" + rotate_history "history/history" + + echo "ℹ️ INFO: $current_date $typ $msg" + echo "$current_date $typ $msg" >> "history/history" +} + +get_backup_dir() +{ + local backup_path="$1" + local backup_name="$2" + local last_backup_number="$3" + local date=$(date +%F) + + local backup_dir= + local number= + for number in $(seq --format "%02g" $last_backup_number 99); do + backup_dir="$date"_"$number"_"$backup_name" + [ -d "$backup_path/$backup_dir" ] || break; + done + + echo $backup_dir +} + +get_last_backup_dir_path() +{ + local backup_path="$1" + local backup_name="$2" + + local last_backup_dir_path=$(find $backup_path \ + -maxdepth 1 \ + -type d \ + -name "*_""$backup_name" \ + | sort \ + | tail --lines=1) + + echo "$last_backup_dir_path" +} + +print_line() +{ + local i= + for i in {1..80}; do + printf "#" + done + + printf "\n" +} + +backup_remote_pathes() +{ + local backup_path="$1" + local machine="$2" + local last_backup_dir_path="$3" + local hardlinkopt= + local remote_user=$(cat config.yaml \ + | yq --raw-output ".machines.\"$machine\".remote_user") + [ -n "$remote_user" ] && [ $remote_user != "null" ] \ + || errlog "config.yaml missing remote_user for $machine" \ + || return $? + local host=$(cat config.yaml \ + | yq --raw-output ".machines.\"$machine\".host") + [ -n "$host" ] && [ "$host" != "null" ] \ + || errlog "config.yaml missing host for $machine" \ + || return $? + local port=$(cat config.yaml \ + | yq --raw-output ".machines.\"$machine\".port") + [ -n "$port" ] && [ "$port" != "null" ] \ + || errlog "config.yaml missing port for $machine" \ + || return $? + local pathes=$(cat config.yaml \ + | yq --raw-output ".machines.\"$machine\".pathes[]") + [ -n "$pathes" ] \ + || errlog "config.yaml missing pathes for $machine" \ + || return $? + + local YELLOW="\e[0;33m" + local LIGHTPURPLE="\e[1;35m" + local RESET="\e[0m" + + local path= + for path in $pathes; do + print_line + printf "ℹ️ INFO: machine ${LIGHTPURPLE}%s${RESET}; " "$machine" + printf "path ${YELLOW}%s${RESET}\n\n" "$path" + + [ -n "$last_backup_dir_path" ] \ + && hardlinkopt="--link-dest=$last_backup_dir_path/$machine" + + rsync --archive \ + --verbose \ + --sparse \ + --acls \ + --hard-links \ + --relative \ + --human-readable \ + $hardlinkopt \ + --rsh "ssh -p $port" \ + $remote_user@$host:$path \ + $backup_path/$machine \ + || errlog "could not backup $machine with path $path" \ + || return $? + + print_line + done +} + +backup_remotes() +{ + local backup_path="$1" + local last_backup_dir_path="$2" + local hardlinkopt= + local machines=$(cat config.yaml | yq --raw-output '.machines | keys[]') + [ -n "$machines" ] \ + || errlog "config.yaml no machines" \ + || return $? + + local machine= + for machine in $machines; do + echo "ℹ️ INFO: create directory $backup_path/$machine" + mkdir --parents $backup_path/$machine \ + || errlog "could not create directory $backup_path/$machine" \ + || return $? + + backup_remote_pathes "$backup_path" \ + "$machine" \ + "$last_backup_dir_path" \ + || return $? + done +} + +remove_backup_dir() +{ + local backup_path="$1" + local backup_name="$2" + local delete_count=$3 + + local backups=$(find $backup_path -maxdepth 1 -name "*$backup_name" \ + | sort \ + | head --lines $delete_count) + + local backup= + for backup in $backups; do + echo "🗑️ DELETE: $backup" + rm --recursive $backup + write_history_entry "deleted ${backup##*/}" + done +} + +cleanup_backups() +{ + local backup_path="$1" + local backup_name="$2" + local backup_count=$3 + + local backup_counted=$(ls --directory $backup_path/*/ \ + | grep "_$backup_name" \ + | sort \ + | wc --lines) + local delete_count=$(( backup_counted - backup_count )) + + print_line + echo + echo "ℹ️ INFO: backup count: $backup_counted" + + if [ $backup_counted -gt $backup_count ]; then + echo "ℹ️ INFO: delete backup count: $delete_count" + echo + remove_backup_dir "$backup_path" "$backup_name" $delete_count + fi + + echo + print_line +} + +is_backup_old() +{ + local backup_typ="$1" + local backup_date="$2" + local backup_month=$(date --date="$backup_date" '+%Y-%m') + local now_month=$(date '+%Y-%m') + local diff=$(( ($(date --date="$backup_date" +%s) - $(date +%s)) / 86400 )) + + case "$backup_typ" in + "day") [ $diff -ge 0 ] || return $? ;; + "week") [ $diff -ge -6 ] || return $? ;; + "month") [ "$backup_month" == "$now_month" ] || return $? ;; + *) return 0;; + esac +} + +check_backup_date() +{ + local LIGHTRED="\e[1;31m" + local LIGHTGREEN="\e[1;32m" + local RESET="\e[0m" + local color=$LIGHTGREEN + local history_path="history" + + print_line + echo + local typ= + for typ in day week month; do + if [ -f "$history_path/$typ" ]; then + color=$LIGHTGREEN + is_backup_old $typ $(cat $history_path/$typ) \ + || color=$LIGHTRED + printf "${color}last backup %s " "$typ" + printf "am %s${RESET}\n" "$(cat $history_path/$typ)" + else + printf "${LIGHTRED}no backup %s " $typ + printf "exists${RESET}\n" + fi + done + echo + print_line +} + +main() +{ + local only_check="$1" + + [ "$only_check" == "check" ] && check_backup_date && return 0 + + echo "⭐ START: backup" + + command -v yq > /dev/null \ + || errlog "command yq not found" \ + || return $? + command -v rsync > /dev/null \ + || errlog "command rsync not found" \ + || return $? + command -v ssh > /dev/null \ + || errlog "command ssh not found" \ + || return $? + [ -f "config.yaml" ] \ + || errlog "file config.yaml not found" \ + || return $? + + backup_path=$(cat config.yaml | yq --raw-output '.backup_path') + backup_name=$(cat config.yaml | yq --raw-output '.backup_name') + backup_count=$(cat config.yaml | yq --raw-output '.backup_count') + + [ -n "$backup_path" ] && [ "$backup_path" != "null" ] \ + || errlog "config.yaml missing backup_path" \ + || return $? + [ -d "$backup_path" ] \ + || errlog "directory $backup_path not exists" \ + || return $? + echo "ℹ️ INFO: backup path $backup_path" + [ -n "$backup_name" ] && [ "$backup_name" != "null" ] \ + || errlog "config.yaml missing backup_name" \ + || return $? + echo "ℹ️ INFO: backup name $backup_name" + [ -n "$backup_count" ] && [ "$backup_count" != "null" ] \ + || errlog "config.yaml missing backup_count" \ + || return $? + echo "ℹ️ INFO: backup count $backup_count" + + local last_backup_dir_path=$(get_last_backup_dir_path \ + "$backup_path" \ + "$backup_name") + echo "ℹ️ INFO: last backup dir path $last_backup_dir_path" + + local today_date=$(date +%F) + local last_backup_number=1 + [[ "$last_backup_dir_path" =~ "$today_date" ]] \ + && last_backup_number=${last_backup_dir_path##*/} \ + && last_backup_number=${last_backup_number:11:2} + local backup_dir=$(get_backup_dir \ + "$backup_path" \ + "$backup_name" \ + "$last_backup_number") + + echo "ℹ️ INFO: backup folder $backup_dir" + local backup_full_path=$backup_path/$backup_dir + echo "ℹ️ INFO: create folder $backup_full_path" + + backup_remotes \ + "$backup_full_path" \ + "$last_backup_dir_path" \ + || return $? + write_current_date "$backup_path" \ + || return $? + write_history_entry "created $backup_dir" \ + || return $? + cleanup_backups \ + "$backup_path" \ + "$backup_name" \ + $backup_count \ + || return $? + check_backup_date \ + || return $? + + echo "✅ SUCCESS: backup" +} + +main $* diff --git a/src/backupmount b/src/backupmount new file mode 100755 index 0000000..8bb65d7 --- /dev/null +++ b/src/backupmount @@ -0,0 +1,168 @@ +#!/bin/bash + +errlog() +{ + local lastexit=$? + local msg="$1" + + echo "❌ ERROR: $msg" + echo "🛑 EXIT $lastexit" + return $lastexit +} + +infolog() +{ + local lastexit=$? + local msg="$1" + + echo "ℹ️ INFO: $msg" + return $lastexit +} + +partition_mount() +{ + local media="$1" + local partition=$(cat config.yaml \ + | yq --raw-output ".media.\"$media\".partition") + [ "$partition" != "null" ] \ + || errlog "config.yaml partition for $media missing" \ + || return $? + [ -b "$partition" ] \ + || errlog "partition $partition not found" \ + || return $? + local backup_path=$(cat config.yaml \ + | yq --raw-output ".backup_path") + [ "$backup_path" != "null" ] \ + || errlog "config.yaml backup path missing" \ + || return $? + + infolog "create backup path $backup_path" + mkdir --parents "$backup_path" \ + || errlog "could not create directory $backup_path" \ + || return $? + infolog "mount partition $partition to $backup_path" + mount "$partition" "$backup_path" \ + || errlog "cloud not mount $partition to $backup_path" \ + || return $? +} + +device_mount() +{ + local media="$1" + local device="$2" + + [ -b "$device" ] \ + || infolog "block device $device for $media not found" \ + || return $? + infolog "media $media with device $device found" + local key=$(cat "config.yaml" \ + | yq --raw-output ".media.\"$media\".key") + [ "$key" != "null" ] \ + || errlog "config.yaml key for $media missing" \ + || return $? + [ -f "$key" ] \ + || errlog "key $key not exists" \ + || return $? + infolog "use key $key" + local volume=$(cat "config.yaml" \ + | yq --raw-output ".backup_volume") + [ "$volume" != "null" ] \ + || errlog "config.yaml volume for $media missing" \ + || return $? + + infolog "volume open $volume" + cryptsetup open --key-file "$key" \ + "$device" \ + "$volume" \ + || errlog "could not open $device with $key" \ + || return $? + + partition_mount "$media" || return $? +} + +mount_backup() +{ + local medias=$(cat config.yaml \ + | yq --raw-output '.media | keys[]') + + [ -n "$medias" ] && [ "$medias" != "null" ] \ + || errlog "config.yaml missing media section" \ + || return $? + + local media= + local device= + for media in $medias; do + device=$(cat config.yaml \ + | yq --raw-output ".media.\"$media\".device") + [ "$device" != "null" ] \ + || errlog "missing path for $media" \ + || return $? + device_mount "$media" "$device" && return 0 + done + + errlog "no device was mounted" +} + +umount_backup() +{ + + local backup_path=$(cat config.yaml \ + | yq --raw-output ".backup_path") + [ "$backup_path" != "null" ] \ + || errlog "config.yaml backup path missing" \ + || return $? + + infolog "umount backup path $backup_path" + umount "$backup_path" \ + || errlog "could not unmount $backup_path" \ + || return $? + + infolog "remove backup path directory $backup_path" + rmdir "$backup_path" \ + || errlog "clound not remote $backup_path" \ + || return $? + + local volume=$(cat "config.yaml" \ + | yq --raw-output ".backup_volume") + [ "$volume" != "null" ] \ + || errlog "config.yaml volume for $media missing" \ + || return $? + + infolog "close volume $volume" + cryptsetup close "$volume" \ + || errlog "could not close $volume" \ + || return $? +} + +main() +{ + local cmd="$1" + + echo "⭐ START: backupmount" + + command -v yq > /dev/null \ + || errlog "command yq not found" \ + || return $? + command -v cryptsetup > /dev/null \ + || errlog "command cryptsetup not found" \ + || return $? + + [ -n "$cmd" ] \ + || errlog "missing command" \ + || return $? + [ -f "config.yaml" ] \ + || errlog "file config.yaml not exists" \ + || return $? + + if [ "$cmd" == "mount" ]; then + mount_backup || return $? + elif [ "$cmd" == "umount" ]; then + umount_backup || return $? + else + errlog "unknown command" || return $? + fi + + echo "✅ SUCCESS: backupmount" +} + +main $* diff --git a/src/control b/src/control new file mode 100644 index 0000000..2449ffa --- /dev/null +++ b/src/control @@ -0,0 +1,8 @@ +Package: simple-backup +Version: $VERSION +Section: admin +Priority: optional +Architecture: amd64 +Maintainer: Bastian Dehn +Description: backup bash script on rsync base +Depends: yq (>= 3.4.3-2), rsync (>= 3.4.1+ds1-5+deb13u2), ssh (>= 1:10.0p1-7+deb13u4), cryptsetup (>= 2:2.7.5-2) diff --git a/src/restore b/src/restore new file mode 100755 index 0000000..2020d40 --- /dev/null +++ b/src/restore @@ -0,0 +1,184 @@ +#!/bin/bash + +errlog() +{ + local lastexit=$? + local msg="$1" + + echo "❌ ERROR: $msg" + echo "🛑 EXIT: $lastexit" + return $lastexit +} + +useage() +{ + echo "$0 -d -n -r -p -k -o" + echo + echo " -d date from backup" + echo " -n number of backup" + echo " -r host @:" + echo " -p path" + echo " -o restore origin (delete mode)" + echo +} + +print_line() +{ + for i in {1..80}; do + printf "#" + done + + printf "\n" +} + +restore() +{ + local date="$1" + local number="$2" + local machine="$3" + local path="$4" + local origin="$5" + + local backup_path=$(cat config.yaml \ + | yq --raw-output ".backup_path") + local backup_name=$(cat config.yaml \ + | yq --raw-output ".backup_name") + local machine=$(cat config.yaml \ + | yq --raw-output \ + ".machines | keys[] | select(. == \"$machine\")") + local remote_user=$(cat config.yaml \ + | yq --raw-output ".machines.\"$machine\".remote_user") + local remote_machine=$(cat config.yaml \ + | yq --raw-output ".machines.\"$machine\".host") + local remote_port=$(cat config.yaml \ + | yq --raw-output ".machines.\"$machine\".port") + + [ -d "$backup_path" ] \ + || errlog "could not find directory $backup_path" \ + || return $? + [ -n "$machine" ] \ + || errlog "config.yaml missing machine" \ + || return $? + [ "$backup_name" != "null" ] \ + || errlog "config.yaml missing backup_name" \ + || return $? + [ "$remote_user" != "null" ] \ + || errlog "config.yaml missing remote_user" \ + || return $? + [ "$remote_machine" != "null" ] \ + || errlog "config.yaml missing host" \ + || return $? + [ "$remote_port" != "null" ] \ + || errlog "config.yaml missing port" \ + || return $? + + local backup_dir="$date"_"$number"_"$backup_name" + + [ -d "$backup_path/$backup_dir" ] \ + || errlog "could not find directory $backup_path/$backup_dir" \ + || return $? + + local restore_prefix_path="$backup_path/$backup_dir/$machine" + [ -d "$restore_prefix_path" ] \ + || errlog "could not find directory $restore_prefix_path" \ + || return $? + + local restore_path="$restore_prefix_path$path" + local remote_path="$remote_user@$remote_machine:$path" + + local mode="directory" + [[ "$path" =~ /$ ]] || mode="file" + + [ -f "$restore_path" ] || [ -d "$restore_path" ] \ + || errlog "could not find $restore_path" \ + || return $? + + echo "ℹ️ INFO: restore mode $mode" + echo + + echo "ℹ️ INFO: restore path $restore_path" + echo "ℹ️ INFO: remote path $remote_path" + echo + + [ "$origin" == "deletemode-on" ] \ + && local deletemode="--delete" \ + && echo "⚠️ WARN: delete mode on" && echo + + local ask_restore="N" + read -p "❓ QUESTION: Do you want restore? [N/y] " ask_restore + local ask_restore=${ask_restore:-N} + local ask_restore=${ask_restore,,} + echo ${ask_restore,,} + + [ "$ask_restore" == "y" ] \ + || errlog "you want not do restore" \ + || return $? + + echo "ℹ️ INFO: restoring..." + + rsync --archive \ + --verbose \ + --sparse \ + --acls \ + --hard-links \ + --human-readable \ + $deletemode \ + --rsh "ssh -p $remote_port" \ + $restore_path \ + $remote_path \ + || errlog "could not restore" \ + || return $? + + echo "ℹ️ INFO: restored" +} + +main() +{ + local date= + local number= + local machine= + local path= + local key= + local origin="deletemode-off" + + echo "⭐ START: restore" + + while getopts "d:k:n:r:p:ho" optname; do + case "$optname" in + "d") date="$OPTARG" ;; + "n") number="$OPTARG" ;; + "r") machine="$OPTARG" ;; + "p") path="$OPTARG" ;; + "o") origin="deletemode-on" ;; + "h") useage && return 0 ;; + esac + done + + command -v yq > /dev/null \ + || errlog "command yq not found" \ + || return $? + command -v rsync > /dev/null \ + || errlog "command rsync not found" \ + || return $? + command -v ssh > /dev/null \ + || errlog "command ssh not found" \ + || return $? + + [ -f "config.yaml" ] \ + || errlog "file config.yaml not found" \ + || return $? + [ -n "$date" ] || errlog "missing date (-d)" || return $? + [ -n "$number" ] || errlog "missing number (-n)" || return $? + [[ "$number" =~ [[:digit:]]{2} ]] \ + || errlog "number must two digits" \ + || return $? + [ -n "$machine" ] || errlog "missing machine (-r)" || return $? + [ -n "$path" ] || errlog "missing path (-p)" || return $? + + restore "$date" "$number" "$machine" "$path" "$origin" \ + || return $? + + echo "✅ SUCCESS: restore" +} + +main $*