X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=bin%2Fbackup-script;h=2b9f7d7f2e91f4c45cdea62581bc211bbf1a934d;hb=566dfc1852216acad83272d9216858f44d5ce26f;hp=37cbc53bd9d2da49d6b3ed9b01cf00b876665f91;hpb=f3df17831cebf184f3fca41a76f5576e82d87a89;p=backup-script.git diff --git a/bin/backup-script b/bin/backup-script index 37cbc53..2b9f7d7 100755 --- a/bin/backup-script +++ b/bin/backup-script @@ -26,11 +26,13 @@ declare -i count_ok_vanished=0 destinations="" # Default settings, can be overwritten in backup-script.conf: -conf_d="/etc/backup-script.d" +[ -d "/usr/local/etc/backup-script.d" ] \ + && conf_d="/usr/local/etc/backup-script.d" \ + || conf_d="/etc/backup-script.d" pre_exec="" post_exec="" default_source_root="/" -default_target="" +default_target="/var/backups" default_user="root" default_ssh_args_add="" default_rsync_args_add="" @@ -50,7 +52,10 @@ Usage() { echo echo "When no is given, all defined systems are used." echo - exit 1 + echo "Configuration file is \"$conf\"," + echo "using \"$conf_d\" as configuration directory." + echo + exit 2 } CleanUp() { @@ -72,6 +77,7 @@ GotSignal() { CleanUp echo -n "Aborted: "; date echo + sleep 3 exit 9 } @@ -122,6 +128,9 @@ CreateSubvolume() { "btrfs") btrfs subvolume create "$volume" >/dev/null || return 1 ;; + "zfs") + zfs create "$(echo "$volume" | cut -c2-)" || return 1 + ;; *) echo "CreateSubvolume: Incompatible FS type \"$fs\" on \"$dir\"!" return 9 @@ -135,6 +144,7 @@ CloneSubvolume() { local snapshot="$3" local dir local fs + local link_name dir=$(dirname "source") fs=$(GetFS "$source") @@ -142,6 +152,13 @@ CloneSubvolume() { "btrfs") btrfs subvolume snapshot "$source" "$snapshot" >/dev/null || return 1 ;; + "zfs") + zfs snapshot "$snapshot" || return 1 + link_name="$(echo "$snapshot" | cut -d@ -f2-)" + ln -s \ + "$volume/.zfs/snapshot/$link_name" \ + "$(dirname "$volume")/$link_name" + ;; *) echo "CloneSubvolume: Incompatible FS type \"$fs\" on \"$source\"!" return 9 @@ -159,6 +176,12 @@ RenameSubvolume() { "btrfs") mv "$source" "$target" || return 1 ;; + "zfs") + zfs rename \ + "$(echo "$source" | cut -c2-)" \ + "$(echo "$target" | cut -c2-)" \ + || return 1 + ;; *) echo "RenameSubvolume: Incompatible FS type \"$fs\" on \"$source\"!" return 9 @@ -169,12 +192,24 @@ RenameSubvolume() { DeleteSubvolume() { local volume="$1" local fs + local id + local snapshot fs=$(GetFS "$volume") case "$fs" in "btrfs") btrfs subvolume delete "$volume" >/dev/null || return 1 ;; + "zfs") + id="$(basename "$volume")" + if [ -h "$volume" ]; then + snapshot="$(dirname "$volume")/current@$id" + else + snapshot="$volume" + fi + zfs destroy -r "$(echo "$snapshot" | cut -c2-)" >/dev/null || return 1 + [ -h "$volume" ] && rm "$volume" + ;; *) echo "DeleteSubvolume: Incompatible FS type \"$fs\" on \"$volume\"!" return 9 @@ -202,6 +237,25 @@ Initialize_Last_SysTarget_Snapshot() { sys_target="$sys_target/$(date +%Y%m%d-%H%M%S)" snapshot="$sys_target" ;; + "zfs") + # On ZFS, the last generation is always named "current" + if [ -e "$sys_target/current" ]; then + last="$sys_target/current" + if [ "$(uname)" = "Linux" ]; then + date=$(LC_ALL=C stat "$1" | grep "^Modify: " \ + | cut -d':' -f2- | cut -d. -f1) + else + date=$(LC_ALL=C stat -f "%Sc" "$1") + fi + date=$(echo "$date" | sed -e's/^ //g' -e 's/[-:]//g' -e 's/ /-/g') + + else + last="" + date="$(date +%Y%m%d-%H%M%S)" + fi + snapshot="$(echo "$sys_target/current" | cut -c2-)@$date" + sys_target="$sys_target/current" + ;; *) echo "Initialize_Last_SysTarget_Snapshot: Incompatible FS type \"$fs\" on \"$sys_target\"!" return 1 @@ -209,6 +263,16 @@ Initialize_Last_SysTarget_Snapshot() { return 0 } +# Search configuration file (last one is used as default!) +for conf in \ + "/usr/local/etc/backup-script.conf" \ + "/etc/backup-script.conf" \ + "${conf_d}/backup-script.conf" \ + "/usr/local/etc/backup-script.conf" \ +; do + [ -r "$conf" ] && break +done + while [ $# -gt 0 ]; do case "$1" in "-n"|"--dry-run") @@ -229,19 +293,20 @@ trap GotSignal SIGINT echo -n "Started: "; date -for conf in "/etc/backup-script.conf" "${conf_d}/backup-script.conf"; do - if [ -r "$conf" ]; then - echo "Reading configuration: \"$conf\" ..." - source "$conf" - fi -done +# Read in configuration file +if [ -r "$conf" ]; then + echo "Reading configuration: \"$conf\" ..." + source "$conf" +else + echo "No configuration file found, using defaults." +fi echo if [ $# -ge 1 ]; then for s in "$@"; do if [ ! -r "${conf_d}/$s" ]; then echo "$NAME: Can' read \"${conf_d}/$s\"!" - exit 1 + exit 3 fi sys="$sys ${conf_d}/$s" done @@ -256,7 +321,7 @@ if [ -e "$PIDFILE" ]; then echo echo -n "Aborted: "; date echo - exit 3 + exit 4 fi touch "$PIDFILE" 2>/dev/null if [ $? -ne 0 ]; then @@ -273,7 +338,7 @@ if [ -n "$pre_exec" ]; then echo "Error: pre-exec command failed!"; echo CleanUp echo "Aborting backup."; echo - exit 2 + exit 5 fi sleep 2 echo @@ -332,7 +397,26 @@ for f in $sys; do post_exec="$post_exec_saved" # Validate configuration - [ "$system" = "localhost" -o "$system" = "127.0.0.1" ] && local=1 + if [ "$system" = "localhost" -o "$system" = "127.0.0.1" ]; then + # Local system + local=1 + compress=0 + fi + + # Make sure "source" ends with a slash ("/") + case "$source" in + "*/") + ;; + "*") + source="$source/" + esac + + # Make sure "target" DOESN'T end with a slash ("/") + case "$target" in + "*/") + target=$( echo "$target" | sed -e 's/\/$//g' ) + ;; + esac [ "$system" = "$fname" ] \ && systxt="\"$system\"" \ @@ -407,7 +491,7 @@ for f in $sys; do fi echo "Created new snapshot in \"$snapshot\"." else - echo " *** Trial run, not creating new snapshot in \"$sys_target\"!" + echo " *** Trial run, not creating new snapshot in \"$snapshot\"!" fi else # No old backup found, create new subvolume @@ -473,8 +557,7 @@ for f in $sys; do if [ $ret -eq 20 ]; then echo "Backup of \"$system\" interrupted. Aborting ..." - CleanUp - exit 1 + GotSignal fi echo -n "End date: "; date @@ -555,6 +638,7 @@ echo if [ $count_started -ne $count_ok ]; then echo "-----> THERE HAVE BEEN ERRORS! <-----" echo + exit 6 fi # -eof-