Files
dogfather-universe/tools/sicherung-holen.sh
T
DogFatherGitandClaude Opus 5 3f18e1bd69 Sicherung: Kopie auf den PC, Dateien mit dabei, Wiederherstellungs-Anleitung
Eine Sicherung, die auf derselben Platte liegt wie das Original, ist keine
-- sie hilft gegen versehentliches Loeschen, nicht gegen einen
Plattenausfall. tools/sicherung-holen.sh holt sie deshalb auf den
Arbeitsrechner.

Dabei ist gleich eine zweite Luecke aufgefallen und mitgeschlossen: Die
Datenbank kennt hochgeladene Dateien und die PDFs der Bibliothek nur ueber
ihren Namen -- die Dateien selbst liegen daneben im Dateisystem und
stecken NICHT in der Datenbanksicherung. Nach einem Plattenausfall haette
man eine Bibliothek voller Verweise auf PDFs, die es nicht mehr gibt.
Werden jetzt mitgeholt.

Bewusst nur auf dem PC und nicht zusaetzlich auf dem Server: Eine zweite
Kopie auf derselben Platte haette gegen nichts geholfen, was die erste
nicht schon ueberlebt haette. Und weil scp nie loescht, bleibt ein einmal
geholtes PDF hier erhalten, auch wenn es auf dem Server verschwindet.

Geprueft wird mit Node statt mit dem sqlite3-Programm: Node bringt SQLite
selbst mit, auf diesem Windows-Rechner ist sqlite3 gar nicht da -- die
erste Fassung gab nur Fragezeichen aus und meldete trotzdem "fertig".

WIEDERHERSTELLUNG.md beschreibt drei Faelle (aus Versehen geloescht /
Datenbank zurueckspielen / Server ganz weg), jeweils als EIN Block zum
Kopieren. Der Ruecklauf legt den kaputten Stand mit mv zur Seite statt
ihn zu loeschen -- falls die Sicherung aelter war als gedacht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-31 18:24:32 +02:00

72 lines
3.4 KiB
Bash

#!/usr/bin/env bash
# ===================================================================
# Holt die Server-Sicherungen auf diesen Rechner und prueft sie.
#
# Eine Sicherung, die auf derselben Platte liegt wie das Original, ist
# keine Sicherung -- sie hilft gegen versehentliches Loeschen, aber nicht
# gegen einen Plattenausfall. Deshalb dieser Schritt.
#
# Einfach ausfuehren: bash tools/sicherung-holen.sh
# ===================================================================
set -euo pipefail
ZIEL="$HOME/Documents/Obelix/Sicherungen/workspace"
mkdir -p "$ZIEL"
echo "Hole Sicherungen vom Server ..."
scp -q dogfather-server:/home/dogiweb/workspace-daten/sicherungen/*.db "$ZIEL/"
# Die Datenbank kennt hochgeladene Dateien und PDFs nur ueber ihren
# Namen -- die Dateien selbst liegen daneben im Dateisystem und stecken
# NICHT in der Datenbanksicherung. Ohne diesen Schritt haette man nach
# einem Plattenausfall eine Bibliothek voller Verweise auf PDFs, die es
# nicht mehr gibt.
#
# Bewusst nur hier auf dem PC und nicht zusaetzlich auf dem Server: Eine
# zweite Kopie auf derselben Platte hilft gegen nichts, was die erste
# nicht schon ueberlebt haette.
#
# scp loescht nie etwas. Wer auf dem Server versehentlich ein PDF
# entfernt, hat es hier weiterhin -- das ist Absicht, nicht Nachlaessigkeit.
echo "Hole hochgeladene Dateien und die Bibliothek ..."
mkdir -p "$ZIEL/dateien" "$ZIEL/wissen"
scp -qr dogfather-server:/home/dogiweb/workspace-daten/dateien/. "$ZIEL/dateien/" 2>/dev/null || true
scp -qr dogfather-server:/home/dogiweb/workspace-daten/wissen/. "$ZIEL/wissen/" 2>/dev/null || true
echo " Dateien: $(find "$ZIEL/dateien" -type f 2>/dev/null | wc -l | tr -d " ") Stueck"
echo " Bibliothek: $(find "$ZIEL/wissen" -type f 2>/dev/null | wc -l | tr -d " ") Stueck"
# Geprueft wird mit Node, nicht mit dem sqlite3-Programm: Node bringt
# SQLite seit Fassung 22 selbst mit, und auf diesem Windows-Rechner ist
# sqlite3 gar nicht vorhanden -- die Pruefung haette dann nur
# Fragezeichen ausgegeben und trotzdem "fertig" gemeldet.
node -e '
const { DatabaseSync } = require("node:sqlite");
const { readdirSync, statSync } = require("node:fs");
const { join } = require("node:path");
const ziel = process.argv[1];
const dateien = readdirSync(ziel).filter((n) => n.endsWith(".db")).sort();
if (!dateien.length) { console.log("\nKeine Sicherung gefunden!"); process.exit(1); }
console.log("\nAuf diesem Rechner liegen jetzt:");
let schlecht = 0;
for (const name of dateien) {
const pfad = join(ziel, name);
const kb = Math.round(statSync(pfad).size / 1024);
let zeile;
try {
const d = new DatabaseSync(pfad, { readOnly: true });
const heil = Object.values(d.prepare("PRAGMA integrity_check").get())[0];
const p = d.prepare("SELECT COUNT(*) AS n FROM personen").get().n;
const t = d.prepare(
"SELECT COUNT(*) AS n FROM sqlite_master WHERE type = \x27table\x27").get().n;
d.close();
const gut = heil === "ok" && p > 0;
if (!gut) schlecht++;
zeile = `${gut ? "ok " : "FEHL"} ${heil}, ${p} Personen, ${t} Tabellen`;
} catch (f) { schlecht++; zeile = "FEHL nicht lesbar: " + f.message; }
console.log(` ${name.padEnd(28)} ${String(kb + " KB").padStart(8)} ${zeile}`);
}
console.log(schlecht ? `\n${schlecht} Sicherung(en) sind unbrauchbar!`
: "\nAlle Sicherungen sind lesbar und enthalten Daten.");
process.exit(schlecht ? 1 : 0);
' "$ZIEL"