commit ef07b8e57be96ab79ec84244ee4e0a8e2ba03722 Author: Loic Nageleisen Date: Tue May 18 19:20:51 2021 +0200 Add public-ready version diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d3ea1bb --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Loic Nageleisen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/rsync-backup.sh b/rsync-backup.sh new file mode 100755 index 0000000..8410441 --- /dev/null +++ b/rsync-backup.sh @@ -0,0 +1,110 @@ +#!/bin/bash + +set -e +set -u +set -o pipefail + +# TODO: update from github +# TODO: reexec with caffeinate +# TODO: take arguments: config, verbose, progress +# TODO: purge old backups +# TODO: purge previous progress +# TODO: lock, and unlock on trap exit +# TODO: non-darwin compatibility + +if [[ -z "${HOME}" ]]; then + echo "error: \$HOME unset" 1>&2 + exit 1 +fi + +excluded=() +excluded+=('.DS_Store') + +included=() + +config="${HOME}/.config/rsync-backup/rsync-backup.conf" + +if [[ -f "${config}" ]]; then + # shellcheck disable=SC1090 + source "${config}" +fi + +name="${name:-$(hostname -s)}" + +if [[ -z "${name}" ]]; then + echo "error: \$name unset" 1>&2 + exit 1 +fi + +if [[ -z "${tgt}" ]]; then + echo "error: \$tgt unset" 1>&2 + exit 1 +fi + +src="${src:-${HOME}}" +port="${port:-22}" +ts="${ts:-$(date -u '+%Y-%m-%d-%H%M%S')}" + +ssh=() +if [[ ${tgt} = *:* ]]; then + ssh-add -l > /dev/null || ssh-add -A + ssh+=(ssh -p "${port}" "${tgt%%:*}") +fi + +# TODO: create only when no latest +# TODO: remove after first backup +"${ssh[@]}" mkdir -p "${tgt#*:}/1970-01-01-000000" + +"${ssh[@]}" mkdir -p "${tgt#*:}/${ts}.progress" + +function latest() { + "${ssh[@]}" ls -1 "${tgt#*:}/" | grep -v '\.progress$' | grep -v latest | tail -1 +} +latest="${tgt#*:}/$(latest)" +echo "latest: '${latest}'" + +args=() +args+=(--verbose) +args+=(--progress) +args+=(--compress) +args+=(--rsh "ssh -p ${port}") +args+=(--archive) +args+=(--delete) +args+=(--delete-excluded) + +for inc in "${included[@]}"; do + args+=(--include "${inc}") +done + +for exc in "${excluded[@]}"; do + args+=(--exclude "${exc}") +done + +# TODO: add multiple --link-dest +args+=(--link-dest "${latest}/") +args+=("${src}/") +args+=("${tgt}/${ts}.progress/") + +# TODO: create local snapshot, and delete on trap exit +# tmutil localsnapshot # => Created local snapshot with date: 2021-05-18-184103 +# tmutil listlocalsnapshots / # => com.apple.TimeMachine.2021-05-18-184302.local +# diskutil apfs listvolumesnapshots disk1s2 # => Name: com.apple.TimeMachine.2021-05-18-184302.local +# mkdir -p /tmp/rsync-backup.snapshot.2021-05-18-184302 +# mount_apfs -s com.apple.TimeMachine.2021-05-18-184302.local /Users /tmp/rsync-backup.snapshot.2021-05-18-184302 +# ls /tmp/rsync-backup.snapshot.2021-05-18-184302/Users/ +# diskutil unmount /tmp/rsync-backup.snapshot.2021-05-18-184302 +# tmutil deletelocalsnapshots 2021-05-18-184302 +# tmutil deletelocalsnapshots / + +rc="0" +set -x +rsync "${args[@]}" || rc="$?" +set +x + +case $rc in + 24|0) : ;; + *) exit "$rc" ;; +esac + +"${ssh[@]}" mv -v "${tgt#*:}/${ts}.progress" "${tgt#*:}/${ts}" +"${ssh[@]}" ln -svhf "${tgt#*:}/${ts}" "${tgt#*:}/latest"