#!/bin/bash
# Выгрузка бэкапа fr1 для rpi. Forced command в ~rus/.ssh/authorized_keys:
#   restrict,command="/home/rus/bin/backup-export" <ключ server-backup@rpi>
# Клиент передаёт профиль: daily | weekly. В stdout — tar | zstd | age (шифрует ОТКРЫТЫМ
# ключом, закрытый только у владельца вне малины — rpi хранит то, что сама прочитать не может).
# В stderr последней строкой — "SHA256 <hex>" шифротекста: rpi сверяет, что дошло целиком.
#
# Читает root-файлы через docker (rus в группе docker = root-эквивалент), а не через sudo:
# sudo на fr1 по паролю. Монтирование / только read-only.
set -euo pipefail
PUB=age1qfsgzyglv0vmq4kskg888hzgq032mry5kxz9kptkvzsrz0fz0v7q6kxwk2
AGE=/home/rus/bin/age
IMG=debian:stable-slim          # GNU tar: --exclude/--warning, в alpine — busybox
profile="${SSH_ORIGINAL_COMMAND:-daily}"
tmp=$(mktemp -d /tmp/backup-export.XXXXXX)
cleanup() { rm -rf "$tmp"; docker exec gitea rm -f /tmp/gitea-snap.db >/dev/null 2>&1 || true; }
trap cleanup EXIT

case "$profile" in
  daily)
    # Gitea на SQLite: копировать живой gitea.db нельзя (рваная копия) — .backup даёт согласованный снимок
    docker exec -u 1000 gitea sqlite3 /data/gitea.db ".backup '/tmp/gitea-snap.db'"
    docker cp gitea:/tmp/gitea-snap.db "$tmp/gitea.db" >/dev/null
    paths=(host/etc host/srv/gitea host/usr/local host/home/rus host/var/spool/cron host/root snap)
    excl=(--exclude=host/srv/gitea/data/gitea.db --exclude='host/srv/gitea/data/gitea.db-*'
          --exclude=host/home/rus/backups --exclude=host/home/rus/.openclaw
          --exclude=host/home/rus/openclaw --exclude=host/home/rus/openclaw-work
          --exclude=host/home/rus/.cache --exclude=host/home/rus/.claude --exclude='*.bak-*' --exclude='*.tar.gz')
    ;;
  weekly)
    paths=(host/var/lib/docker/volumes/claude-channels_claude-home
           host/var/lib/docker/volumes/monitoring_grafana_data
           host/var/lib/docker/volumes/monitoring_alertmanager_data
           host/var/lib/docker/volumes/monitoring_pushgateway_data
           host/home/tgclaude)
    excl=(--exclude=host/home/tgclaude/backups --exclude=host/home/tgclaude/openclaw-deploy
          --exclude=host/home/tgclaude/.local --exclude=host/home/tgclaude/.cache --exclude=host/home/tgclaude/chrome-libs)
    ;;
  *) echo "профиль: daily|weekly" >&2; exit 2 ;;
esac

# tar exit 1 = «файл изменился при чтении» (живые логи/репо) — не ошибка для бэкапа
docker run --rm --network none -v /:/host:ro -v "$tmp":/snap:ro "$IMG" \
  sh -c 'tar --numeric-owner --ignore-failed-read --warning=no-file-changed -C / -cf - "$@"; rc=$?; [ $rc -le 1 ] || exit $rc' tar "${excl[@]}" "${paths[@]}" \
  | zstd -3 -T0 -q | "$AGE" -r "$PUB" | tee >(sha256sum > "$tmp/sum")
# процесс-подстановка живёт отдельно от конвейера — ждём, пока sha256sum допишет итог
for _ in $(seq 300); do [ -s "$tmp/sum" ] && break; sleep 0.1; done
echo "SHA256 $(cut -d' ' -f1 "$tmp/sum")" >&2
