59 lines
1.8 KiB
Bash
Executable File
59 lines
1.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Konsistentes SQLite-Backup über die Python-Backup-API. Sichert NICHT master.key (separat aufbewahren).
|
|
set -euo pipefail
|
|
|
|
SELF=$(readlink -f "${BASH_SOURCE[0]}")
|
|
# shellcheck source=lib/common.sh
|
|
source "$(dirname "$SELF")/lib/common.sh"
|
|
|
|
KEEP=${CHECKBOT_BACKUP_KEEP:-14}
|
|
[[ $KEEP =~ ^[1-9][0-9]*$ ]] || die "CHECKBOT_BACKUP_KEEP muss eine positive Zahl sein."
|
|
|
|
# Als root würden WAL-Dateien der Datenbank root-gehörig entstehen; daher immer als checkbot arbeiten.
|
|
if [[ $EUID -eq 0 ]]; then
|
|
exec runuser -u "$APP_USER" -- "$BASH" "$SELF" "$@"
|
|
fi
|
|
|
|
BACKUP_PY='
|
|
import os, sqlite3, sys
|
|
src, dst = sys.argv[1:3]
|
|
source = sqlite3.connect(src)
|
|
target = sqlite3.connect(dst)
|
|
try:
|
|
source.backup(target)
|
|
if target.execute("PRAGMA integrity_check").fetchone()[0] != "ok":
|
|
raise SystemExit("Integritätsprüfung der Sicherung fehlgeschlagen")
|
|
finally:
|
|
target.close()
|
|
source.close()
|
|
'
|
|
|
|
prune_old() {
|
|
local file
|
|
while IFS= read -r file; do
|
|
rm -f -- "$file"
|
|
done < <(find "$BACKUP_DIR" -maxdepth 1 -type f -name 'checkbot-*.db' | sort -r | tail -n +$((KEEP + 1)))
|
|
}
|
|
|
|
main() {
|
|
local db target partial
|
|
db=$(db_file)
|
|
[[ -f $db ]] || die "Datenbank $db nicht gefunden."
|
|
[[ -d $BACKUP_DIR && -w $BACKUP_DIR ]] || die "Backup-Verzeichnis $BACKUP_DIR fehlt oder ist nicht beschreibbar."
|
|
umask 077
|
|
target=$BACKUP_DIR/checkbot-$(date +%Y%m%d-%H%M%S).db
|
|
partial=$target.part
|
|
rm -f -- "$partial"
|
|
if ! python3 -I -c "$BACKUP_PY" "$db" "$partial"; then
|
|
rm -f -- "$partial"
|
|
die "Backup fehlgeschlagen."
|
|
fi
|
|
chmod 0600 "$partial"
|
|
mv -- "$partial" "$target"
|
|
prune_old
|
|
log "Backup angelegt: $target (aufbewahrt: bis zu $KEEP)."
|
|
log "Hinweis: master.key und session.secret sind nicht enthalten und müssen separat gesichert werden."
|
|
}
|
|
|
|
main "$@"
|