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
+++ /dev/null
-#!/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 $*
+++ /dev/null
-#!/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 $*
+++ /dev/null
-Package: simple-backup
-Version: $VERSION
-Section: admin
-Priority: optional
-Architecture: amd64
-Maintainer: Bastian Dehn <hhaalo@arcor.de>
-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)
+++ /dev/null
-#!/bin/bash
-
-errlog()
-{
- local lastexit=$?
- local msg="$1"
-
- echo "❌ ERROR: $msg"
- echo "🛑 EXIT: $lastexit"
- return $lastexit
-}
-
-useage()
-{
- echo "$0 -d <date> -n <number> -r <host> -p <path> -k <key> -o"
- echo
- echo " -d date from backup"
- echo " -n number of backup"
- echo " -r host <user>@<rechner>:<port>"
- 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 $*
--- /dev/null
+#!/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 $*
--- /dev/null
+#!/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 $*
--- /dev/null
+Package: simple-backup
+Version: $VERSION
+Section: admin
+Priority: optional
+Architecture: amd64
+Maintainer: Bastian Dehn <hhaalo@arcor.de>
+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)
--- /dev/null
+#!/bin/bash
+
+errlog()
+{
+ local lastexit=$?
+ local msg="$1"
+
+ echo "❌ ERROR: $msg"
+ echo "🛑 EXIT: $lastexit"
+ return $lastexit
+}
+
+useage()
+{
+ echo "$0 -d <date> -n <number> -r <host> -p <path> -k <key> -o"
+ echo
+ echo " -d date from backup"
+ echo " -n number of backup"
+ echo " -r host <user>@<rechner>:<port>"
+ 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 $*