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]>
72 lines
3.4 KiB
Bash
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"
|