diff --git a/AGENTS.md b/AGENTS.md index bdbc828..b3d9190 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -138,7 +138,9 @@ Dieses Repository ist ein modulares, automatisiertes Setup- und Konfigurations-F - `is_root_subvolume_configured`: Prüft, ob Root bereits in einem Subvolume (`@`) läuft. - `update_btrfs_fstab "fstab_file" "root_id"`: Aktualisiert Mount-Optionen in `/etc/fstab` für `@` und `@home`. - `check_and_setup_btrfs_subvolumes`: Erkennt flache Btrfs-Root-Volumes und migriert `/` und `/home` transparent in Subvolumes `@` und `@home`. -- `ensure_timeshift_btrfs_config`: Erstellt bzw. initialisiert die Timeshift-Btrfs-Konfiguration (`/etc/timeshift/timeshift.json`) für die Root-UUID. +- `ensure_timeshift_btrfs_config`: Erstellt bzw. initialisiert die Timeshift-Btrfs-Konfiguration (`/etc/timeshift/timeshift.json`, automatische Boot-Snapshots, Retention auf 5 Snapshots) für die Root-UUID. +- `ensure_timeshift_boot_service`: Richtet den `timeshift-boot.service` und Cron-Einträge für automatische Boot-Snapshots ein. +- `ensure_timeshift_apt_hook`: Richtet einen DPkg/APT-Hook (`/etc/apt/apt.conf.d/80timeshift-auto-snapshot` und `/usr/local/bin/timeshift-apt-hook`) für automatische Snapshots vor System-Updates ein. - `create_timeshift_snapshot "comment" [tags]`: Erstellt einen Timeshift-Btrfs-Snapshot an kritischen Setup-Meilensteinen (idempotent, steuerbar über `ENABLE_TIMESHIFT_SNAPSHOTS` in `config/setup.conf`). ### `lib/tui.sh` diff --git a/README.md b/README.md index 2af7587..483fa19 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ sudo ./setup.sh --stages 04,05 3. **Idempotenz, Backups & Timeshift Btrfs-Snapshots**: - Alle Phasen können beliebig oft wiederholt werden. - Vorhandene Dotfiles (`~/.zshrc`) und Konfigurationen (`/etc/default/grub`) werden vor Änderungen automatisch mit Zeitstempel (`.backup_YYYYMMDD_HHMMSS`) gesichert. - - Auf Btrfs-Systemen werden mit Timeshift automatisch Rollback-Punkte vor und nach kritischen Operationen (Dist-Upgrade, Kernel-Installation, Paketinstallation, Desktop-Setup) erstellt. + - Auf Btrfs-Systemen werden mit Timeshift automatisch Rollback-Punkte vor und nach kritischen Operationen (Dist-Upgrade, Kernel-Installation, Paketinstallation, Desktop-Setup), bei jedem System-Update (automatischer APT/DPkg-Pre-Invoke-Hook) sowie bei jedem Systemstart (`timeshift-boot.service`) erstellt, wobei standardmäßig die letzten 5 Snapshots vorgehalten werden. 4. **Debian Unstable Absicherung**: - Moderne Deb822-Quellen und dedizierte Keyrings in `/etc/apt/keyrings/`. - Installation von `apt-listbugs` und `apt-listchanges` vor dem `dist-upgrade` schützt vor bekannten kritischen Paketproblemen. diff --git a/config/setup.conf b/config/setup.conf index 58eaa03..66465c7 100644 --- a/config/setup.conf +++ b/config/setup.conf @@ -9,6 +9,9 @@ CPU_PSTATE_AUTO=1 # Backup & System Snapshots (Timeshift Btrfs) ENABLE_TIMESHIFT_SNAPSHOTS=1 +TIMESHIFT_COUNT_BOOT=5 +TIMESHIFT_SCHEDULE_BOOT="true" +TIMESHIFT_SNAPSHOT_ON_UPDATE="true" # Bootloader & Appearance GRUB_THEME="vimix" diff --git a/lib/btrfs.sh b/lib/btrfs.sh index eaedac2..19223ce 100644 --- a/lib/btrfs.sh +++ b/lib/btrfs.sh @@ -262,14 +262,159 @@ check_and_setup_btrfs_subvolumes() { log_success "Btrfs subvolume setup and migration completed successfully." } +# Ensure Timeshift APT hook is configured for automatic snapshots on system updates +ensure_timeshift_apt_hook() { + local root_prefix="${ROOT_PREFIX:-}" + local snapshot_on_update="${TIMESHIFT_SNAPSHOT_ON_UPDATE:-true}" + local apt_conf_file="${root_prefix}/etc/apt/apt.conf.d/80timeshift-auto-snapshot" + local hook_script="${root_prefix}/usr/local/bin/timeshift-apt-hook" + + # If disabled in configuration, remove hook if present + if [[ "$snapshot_on_update" != "1" && "$snapshot_on_update" != "true" ]]; then + if [[ -f "$apt_conf_file" || -f "$hook_script" ]]; then + log_info "Disabling Timeshift APT update snapshot hook..." + rm -f "$apt_conf_file" "$hook_script" + fi + return 0 + fi + + mkdir -p "${root_prefix}/usr/local/bin" "${root_prefix}/etc/apt/apt.conf.d" + + # Create hook script + log_info "Configuring Timeshift APT update hook ($hook_script)..." + cat > "$hook_script" <<'EOF' +#!/usr/bin/env bash +# ============================================================================== +# /usr/local/bin/timeshift-apt-hook - Automatic Timeshift Snapshot on APT updates +# ============================================================================== +set -euo pipefail + +# Check if timeshift binary is available +if ! command -v timeshift >/dev/null 2>&1; then + exit 0 +fi + +# Check if timeshift configuration exists +if [[ ! -f /etc/timeshift/timeshift.json && ! -f /etc/timeshift.json ]]; then + exit 0 +fi + +# Check if root filesystem is Btrfs +if command -v findmnt >/dev/null 2>&1; then + if [[ "$(findmnt -n -o FSTYPE / 2>/dev/null || true)" != "btrfs" ]]; then + exit 0 + fi +fi + +# Prevent duplicate snapshots within 60 seconds (rate limiting) +STAMP_FILE="/run/timeshift-apt-hook.stamp" +if [[ -f "$STAMP_FILE" ]]; then + LAST_RUN="$(stat -c %Y "$STAMP_FILE" 2>/dev/null || stat -f %m "$STAMP_FILE" 2>/dev/null || echo 0)" + CURRENT_TIME="$(date +%s)" + if (( CURRENT_TIME - LAST_RUN < 60 )); then + exit 0 + fi +fi + +echo ">> [Timeshift] Creating automatic pre-update system snapshot..." +if timeshift --create --scripted --tags O --comments "Automatic snapshot before system update (APT)" 2>&1; then + touch "$STAMP_FILE" 2>/dev/null || true + echo ">> [Timeshift] Pre-update snapshot created successfully." +else + echo ">> [Timeshift] Warning: Automatic snapshot could not be created (continuing update)." +fi + +exit 0 +EOF + chmod 755 "$hook_script" + + # Create APT configuration hook + cat > "$apt_conf_file" <<'EOF' +// Automatic Timeshift snapshot before APT package operations / updates +DPkg::Pre-Invoke { "[ -x /usr/local/bin/timeshift-apt-hook ] && /usr/local/bin/timeshift-apt-hook || true"; }; +EOF + chmod 644 "$apt_conf_file" + + log_success "Timeshift APT update hook configured: $apt_conf_file" +} + +# Ensure Timeshift systemd boot service and cron jobs are configured and enabled +ensure_timeshift_boot_service() { + local root_prefix="${ROOT_PREFIX:-}" + local service_file="${root_prefix}/etc/systemd/system/timeshift-boot.service" + local timeshift_bin + timeshift_bin="$(command -v timeshift || echo "/usr/bin/timeshift")" + + mkdir -p "${root_prefix}/etc/systemd/system" + + local needs_service_update=0 + if [[ ! -f "$service_file" ]]; then + needs_service_update=1 + fi + + if [[ "$needs_service_update" -eq 1 ]]; then + log_info "Creating Timeshift boot snapshot service ($service_file)..." + cat > "$service_file" </dev/null || true + systemctl enable timeshift-boot.service 2>/dev/null || true + fi + + # Also install cron entries if cron directory exists + if [[ -d "${root_prefix}/etc/cron.d" ]]; then + local cron_boot="${root_prefix}/etc/cron.d/timeshift-boot" + local cron_hourly="${root_prefix}/etc/cron.d/timeshift-hourly" + + if [[ ! -f "$cron_boot" ]]; then + cat > "$cron_boot" < "$cron_hourly" </dev/null && [[ -n "$root_uuid" ]]; then needs_update=1 + elif ! grep -q "\"schedule_boot\"[[:space:]]*:[[:space:]]*\"${schedule_boot}\"" "$config_file" 2>/dev/null; then + needs_update=1 + elif ! grep -q "\"count_boot\"[[:space:]]*:[[:space:]]*\"${count_boot}\"" "$config_file" 2>/dev/null; then + needs_update=1 fi if [[ "$needs_update" -eq 1 ]]; then @@ -296,12 +445,12 @@ ensure_timeshift_btrfs_config() { "schedule_weekly" : "false", "schedule_daily" : "false", "schedule_hourly" : "false", - "schedule_boot" : "false", + "schedule_boot" : "${schedule_boot}", "count_monthly" : "2", "count_weekly" : "3", "count_daily" : "5", "count_hourly" : "6", - "count_boot" : "5", + "count_boot" : "${count_boot}", "snapshot_size" : "0", "snapshot_count" : "0", "exclude" : [ @@ -311,10 +460,13 @@ ensure_timeshift_btrfs_config() { } EOF chmod 644 "$config_file" - if [[ ! -e /etc/timeshift.json ]]; then - ln -sf /etc/timeshift/timeshift.json /etc/timeshift.json 2>/dev/null || true + if [[ ! -e "${root_prefix}/etc/timeshift.json" ]]; then + ln -sf /etc/timeshift/timeshift.json "${root_prefix}/etc/timeshift.json" 2>/dev/null || true fi fi + + ensure_timeshift_boot_service + ensure_timeshift_apt_hook } # Create a Btrfs snapshot using Timeshift diff --git a/stages/06-services.sh b/stages/06-services.sh index 291608a..5c322e3 100755 --- a/stages/06-services.sh +++ b/stages/06-services.sh @@ -8,6 +8,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" source "$SCRIPT_DIR/lib/utils.sh" source "$SCRIPT_DIR/lib/apt.sh" +source "$SCRIPT_DIR/lib/btrfs.sh" if [[ -f "$SCRIPT_DIR/config/setup.conf" ]]; then # shellcheck source=/dev/null @@ -135,7 +136,16 @@ if command_exists systemctl; then log_success "Ollama systemd service configured and enabled." fi -# 6. User Group Memberships +# 6. Timeshift Boot Snapshot Service & APT Update Hook (if on Btrfs) +log_substep "Configuring Timeshift Boot Snapshot Service and APT Update Hook..." +if command_exists timeshift && is_root_btrfs; then + ensure_timeshift_btrfs_config + log_success "Timeshift Boot Snapshot Service and APT Update Hook configured and enabled." +elif is_root_btrfs; then + log_info "Timeshift will be configured when installed." +fi + +# 7. User Group Memberships log_substep "Updating user group memberships for $TARGET_USER..." groupadd -f sudo groupadd -f docker