+#!/bin/bash
+
+targetHost=$1
+targetHost=${targetHost%/}
+source config
+source "$targetHost/config"
+
+if ! which chunked >/dev/null; then
+ printf "Requires 'chunked' package from deb2.dogcraft.de\n" >&2
+ exit 1
+fi
+
+
+
+backup_target="$targetHost/backups"
+coproc {
+ ssh_target "sudo ./backup"
+ read -r end
+}
+read -r line <&${COPROC[0]} || exit 1;
+if [[ $line != "Backup service ready" ]]; then
+ echo "Backup service did not respond"
+ exit 1
+fi
+function start_backup {
+ ident="$(date "+%Y-%m-%d-%H-%M-%S")"
+ self="$backup_target/$ident"
+ mkdir -p "$self"
+ if [[ -h "$backup_target/last" ]]; then
+ last="$(readlink "$backup_target/last")"
+ ln -s "../$last" "$self/prev"
+ rm "$backup_target/last"
+ fi
+ ln -s "$ident" "$backup_target/last"
+}
+function base {
+ printf "base\n" >&${COPROC[1]}
+ chunked decode <&${COPROC[0]} > "$self/pg_base.tar.gz"
+ ls -alsh -- "$self/pg_base.tar.gz"
+ read -r line <&${COPROC[0]} || exit 1;
+ echo "pg_base done: $line"
+ echo "Backup info: "
+ tar xzO backup_label < "$self/pg_base.tar.gz"
+}
+function incremental {
+ last=
+ hash=
+ if [[ $(find -L "$self" -maxdepth 14 -name "pg_base.tar.gz" | wc -l) -lt 1 ]]; then
+ printf "doing pg_base backup to $self/pg_base.tar.gz:\n"
+ base
+ last="$(tar xzO backup_label < "$self/pg_base.tar.gz" | grep "^START WAL LOCATION: " | sed "s/.*(file \\(.*\\))/\\1/")"
+ hash="-"
+ else
+ last=""
+ folder="$self"
+ while [[ $last == "" ]]; do
+ folder="$folder/prev"
+ last="$(tar tf "$folder/pg_wal.tar.gz" | grep "^[A-Z0-9]*$" | tail -n 1)"
+ done
+ echo "Found last WAL file in backup: $folder"
+ hash=$(tar xfO "$folder/pg_wal.tar.gz" "$last" | sha256sum | cut -d" " -f1)
+ fi
+ printf "Last WAL-name: %s\n" "$last"
+ printf "incremental\n" >&${COPROC[1]}
+ printf "%s\n" "$last" >&${COPROC[1]}
+ printf "%s\n" "$hash" >&${COPROC[1]}
+ read -r line <&${COPROC[0]} || exit 1;
+ if [[ "$line" != "Ready" ]]; then
+ printf "incremental backup didn't start\n"
+ exit 1
+ fi
+ chunked decode <&${COPROC[0]} > "$self/pg_wal.tar.gz"
+ printf "Tar contents\n"
+ tar tf "$self/pg_wal.tar.gz"
+ ls -alsh -- "$self/pg_wal.tar.gz"
+ read -r line <&${COPROC[0]} || exit 1;
+ if [[ $line == "incremental backup done, confirm cleanup!" ]]; then
+ printf "y\n" >&${COPROC[1]}
+ else
+ printf "Done, but got strange line for cleanup confirmation: %s\n" "$line"
+ fi
+ printf "Done incremental backup\n"
+}
+
+if [[ "$2" == "restore" ]]; then
+ sourceHost=$3
+ sourceHost=${sourceHost%/}
+ backup_target="${sourceHost}/backups"
+ folder="$backup_target/last"
+ printf "Restoring backup %s\n" "$(readlink -e -- "$folder")"
+ tar tf "$folder/pg_wal.tar.gz"
+ while ! [[ -f "$folder/pg_base.tar.gz" ]]; do
+ folder="$folder/prev"
+ printf "Requires backup %s\n" "$(readlink -e -- "$folder")"
+ tar tf "$folder/pg_wal.tar.gz"
+ done
+ #tar tf "$folder/pg_base.tar.gz"
+ printf "restore\n" >&${COPROC[1]}
+ read -r reply <&${COPROC[0]} || exit 1;
+ if [[ $reply != "postgres base" ]]; then
+ printf "Service is not ready to receive backup: %s\n" "$reply"
+ exit 1
+ fi
+ echo "sending base"
+ chunked < "$folder/pg_base.tar.gz" >&${COPROC[1]}
+ echo "done sending base"
+ folder="$backup_target/last"
+ while :; do
+ read -r reply <&${COPROC[0]} || exit 1;
+ if [[ $reply != "incremental?" ]]; then
+ printf "Service is not ready to receive backup: %s\n" "$reply"
+ exit 1
+ fi
+ printf "y\n" >&${COPROC[1]}
+ printf "Sending pg_wal from %s\n" "$(readlink -e -- "$folder")"
+ chunked < "$folder/pg_wal.tar.gz" >&${COPROC[1]}
+ if [[ -f "$folder/pg_base.tar.gz" ]]; then
+ break
+ fi
+ folder="$folder/prev"
+ done
+ read -r reply <&${COPROC[0]} || exit 1;
+ if [[ $reply != "incremental?" ]]; then
+ printf "Service is not ready to receive backup: %s\n" "$reply"
+ exit 1
+ fi
+ printf "n\n" >&${COPROC[1]}
+elif [[ "$2" == "backup" ]]; then
+ start_backup
+ incremental
+else
+ printf "Error, unknown sub command: %s\n" "$2" >&2
+fi
+
+
+printf "end\n" >&${COPROC[1]}
+read -r line <&${COPROC[0]} || exit 1;
+printf "END: %s\n" "$line"