. ${BUILDFILE%/*}/common.sh pkgver=20181224.2 package() { preamble depends+=(duplicity) add-file -m755 etc/systemd/system/backup <<'EOF' #!/usr/bin/env bash { set -euE mkdir -p /var/lib/backup/{private,public} export GNUPGHOME=/var/lib/backup/private/gnupg gpgconf --kill all trap 'gpgconf --kill all' EXIT ###################################################################### # Signing key if ! [[ -d "$GNUPGHOME" ]]; then install -d -m 700 "$GNUPGHOME" printf '%s\n' \ '%no-protection' \ 'Key-Type: default' \ 'Subkey-Type: default' \ 'Name-Real: Backup' \ "Name-Email: backup@$HOSTNAME" \ 'Expire-Date: 0' \ | gpg --gen-key --batch fi key_sign="$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/{print $5}')" key_sign_pass='' # Encryption keys keys_encrypt=( '99195DD3BB6FE10A2F36ED8445698744D4FFBFC9' # Luke Shumaker ) gpg --recv-keys "${keys_encrypt[@]}" || true keys_encrypt+=("$key_sign") key_encrypt_pass='' ###################################################################### backup_args=( "${keys_encrypt[@]/#/--encrypt-key=}" --sign-key="$key_sign" --gpg-options='--always-trust' # Trust that keys_encrypt is verified before putting it in this script --exclude-other-filesystems #--progress # seems broken? ) prune_args=( remove-all-but-n-full 2 --force ) declare -A backups backups['srv']='--exclude=/srv/repo/main /srv' # trust mirrors to backup /srv/repo main for us backups['etc']='/etc' backups['home']='/home' backups['home_root']='/root' backups['pkg']='--no-compression /var/cache/pacman/pkg' # already heavily compressed backups['log']='/var/log' ###################################################################### export PASSPHRASE="${key_encrypt_pass}" export SIGN_PASSPHRASE="${key_sign_pass}" declare -i r=0 for backup in "${!backups[@]}"; do duplicity=( duplicity --archive-dir='/var/lib/backup/private/duplicity' --name="$backup" ) printf '======================> %s <======================\n' "$backup" primary_chain_size=$("$(dirname -- "${BASH_SOURCE[0]}")/duplicity-primary-chain-size" "$backup") || { r=$?; continue; } IFS=+ read -r full inc <<<"$primary_chain_size" if (( inc >= full )); then action=full else action=inc fi "${duplicity[@]}" "$action" "${backup_args[@]}" ${backups[$backup]} "file:///var/lib/backup/public/$backup" || r=$? chmod 644 "/var/lib/backup/public/$backup"/*.gpg || r=$? "${duplicity[@]}" "${prune_args[@]}" "file:///var/lib/backup/public/$backup" || r=$? done exit $r } EOF add-file -m755 etc/systemd/system/duplicity-primary-chain-size <<'EOF' #!/usr/bin/env bash shopt -s extglob nullglob glob_date='[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]T[0-9][0-9][0-9][0-9][0-9][0-9]Z' glob_n='+([0-9])' die() { printf '%s: ' "$0" >&2 printf "$@" >&2 exit 1 } { name=$1 dir="/var/lib/backup/public/$name" declare -A snap_parent declare -A snap_files for file in "$dir"/*; do if [[ ! -f $file ]] || [[ -L $file ]]; then die "unexpected non-file: %q" "$file" fi case "${file##*/}" in duplicity-full-signatures.${glob_date}.sigtar.gpg) type=full;; duplicity-full.${glob_date}.manifest.gpg) type=full;; duplicity-full.${glob_date}.vol${glob_n}.difftar.gpg) type=full;; duplicity-inc.${glob_date}.to.${glob_date}.manifest.gpg) type=inc;; duplicity-inc.${glob_date}.to.${glob_date}.vol${glob_n}.difftar.gpg) type=inc;; duplicity-new-signatures.${glob_date}.to.${glob_date}.sigtar.gpg) type=inc;; *) die "unexpected file name: %q" "$file";; esac declare date= parent= case "$type" in full) IFS=. read -r _ date _ <<<"${file##*/}" parent=full ;; inc) IFS=. read -r _ parent _ date _<<<"${file##*/}" ;; esac if [[ -n ${snap_parent[$date]} && ${snap_parent[$date]} != "$parent" ]]; then die "multiple parents for %q: %s %q" "$date" "${snap_parent[$date]}" "$parent" fi snap_parent[$date]="$parent" snap_files[$date]+="${file@Q} " done if (( ${#snap_parent[@]} == 0 )); then echo "0+0" exit 0 fi last=$(printf '%s\0' "${!snap_parent[@]}" | LC_COLLATE=C sort -z | tail -z -n1 | xargs -0) declare -i inc_size=0 declare -i full_size=0 while [[ $last != full ]]; do declare -i size=0 eval "files=(${snap_files[$last]})" for file in "${files[@]}"; do size+=$(stat -c '%s' -- "$file") done if [[ ${snap_parent[$last]} != full ]]; then inc_size+=$size else full_size=$size fi last=${snap_parent[$last]} done printf '%s+%s\n' "$full_size" "$inc_size" } EOF mkdir -p var/lib/backup add-file -m644 etc/systemd/system/backup.service <