diff --git a/AGENTS.md b/AGENTS.md index 74e53b4..bdbc828 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -138,6 +138,8 @@ 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. +- `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` - `tui_show_stage_selection`: Zeigt ein `whiptail` Checklist-Menü zur interaktiven Auswahl der auszuführenden Phasen. diff --git a/README.md b/README.md index cd06f37..2af7587 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ sudo ./setup.sh --stages 04,05 ├── lib/ # Wiederverwendbare Hilfsbibliotheken │ ├── utils.sh # Logging, Error-Traps (set -euo pipefail), Root/User-Erkennung & Abfrage │ ├── apt.sh # APT-Keyring-Management (/etc/apt/keyrings/), Deb822, Pinning -│ ├── btrfs.sh # Btrfs Root- & Subvolume-Erkennung, Migration (@, @home) +│ ├── btrfs.sh # Btrfs Root- & Subvolume-Erkennung, Migration (@, @home), Timeshift-Snapshots │ └── tui.sh # Whiptail-Menüs und Dialoge ├── config/ # Konfigurationsdateien & Paketlisten │ ├── setup.conf # Globale Variablen (Kernel, GRUB-Theme, Plymouth) @@ -106,9 +106,10 @@ sudo ./setup.sh --stages 04,05 2. **Keine gefährlichen Login-Hooks**: - Vollständige Beseitigung unkontrollierter Live-Downloads (`curl | sh`) beim Login. - Standardkonforme Bereitstellung über `/etc/skel` für neue und bestehende Benutzer. -3. **Idempotenz & Backups**: +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. 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 1a16c7c..58eaa03 100644 --- a/config/setup.conf +++ b/config/setup.conf @@ -7,6 +7,9 @@ XANMOD_BRANCH="main" CPU_PSTATE_AUTO=1 +# Backup & System Snapshots (Timeshift Btrfs) +ENABLE_TIMESHIFT_SNAPSHOTS=1 + # Bootloader & Appearance GRUB_THEME="vimix" PLYMOUTH_THEME="solar" diff --git a/lib/btrfs.sh b/lib/btrfs.sh index 1f75d33..eaedac2 100644 --- a/lib/btrfs.sh +++ b/lib/btrfs.sh @@ -261,3 +261,107 @@ check_and_setup_btrfs_subvolumes() { log_success "Btrfs subvolume setup and migration completed successfully." } + +# Ensure Timeshift is configured for Btrfs mode on the root filesystem +ensure_timeshift_btrfs_config() { + local root_uuid + root_uuid="$(get_root_btrfs_uuid)" + + mkdir -p /etc/timeshift + + local config_file="/etc/timeshift/timeshift.json" + local needs_update=0 + + if [[ ! -f "$config_file" ]]; then + needs_update=1 + elif grep -q '"btrfs_mode"[[:space:]]*:[[:space:]]*"false"' "$config_file" 2>/dev/null; then + needs_update=1 + elif grep -q '"backup_device_uuid"[[:space:]]*:[[:space:]]*""' "$config_file" 2>/dev/null && [[ -n "$root_uuid" ]]; then + needs_update=1 + fi + + if [[ "$needs_update" -eq 1 ]]; then + log_info "Initializing Timeshift Btrfs configuration ($config_file)..." + backup_file_or_dir "$config_file" + cat > "$config_file" </dev/null || true + fi + fi +} + +# Create a Btrfs snapshot using Timeshift +create_timeshift_snapshot() { + local comment="${1:-Setup Snapshot}" + local tags="${2:-O}" + + # Check if disabled via configuration + if [[ "${ENABLE_TIMESHIFT_SNAPSHOTS:-1}" != "1" && "${ENABLE_TIMESHIFT_SNAPSHOTS:-1}" != "true" ]]; then + log_info "Timeshift snapshots disabled in configuration. Skipping: '$comment'" + return 0 + fi + + # Dry-run check + if [[ "${FLAG_DRY_RUN:-0}" -eq 1 ]]; then + log_info "[DRY-RUN] Would create Timeshift Btrfs snapshot: '$comment' (Tag: $tags)" + return 0 + fi + + # Check if root is on Btrfs + if ! is_root_btrfs; then + log_info "Root filesystem is not Btrfs. Skipping Timeshift snapshot: '$comment'" + return 0 + fi + + # Ensure timeshift is installed + if ! command_exists timeshift; then + log_info "Timeshift not found. Attempting to install timeshift..." + DEBIAN_FRONTEND=noninteractive apt-get update -y >/dev/null 2>&1 || true + if ! DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends timeshift 2>/dev/null; then + log_warn "Timeshift is not available and could not be installed. Skipping snapshot: '$comment'" + return 0 + fi + fi + + # Ensure Timeshift configuration for Btrfs + ensure_timeshift_btrfs_config + + log_substep "Creating Timeshift Btrfs snapshot: '$comment' (Tag: $tags)..." + + local root_dev + root_dev="$(get_root_btrfs_device)" + + if timeshift --create --scripted --comments "$comment" --tags "$tags" 2>/dev/null || \ + ([[ -n "$root_dev" ]] && timeshift --create --scripted --snapshot-device "$root_dev" --btrfs --comments "$comment" --tags "$tags" 2>/dev/null); then + log_success "Timeshift Btrfs snapshot created: '$comment'" + else + log_warn "Timeshift snapshot could not be created for '$comment' (non-fatal)." + fi +} diff --git a/setup.sh b/setup.sh index d5c8fe9..6f341c5 100755 --- a/setup.sh +++ b/setup.sh @@ -59,6 +59,7 @@ EOF FLAG_ALL=0 FLAG_STAGES="" FLAG_DRY_RUN=0 +export FLAG_DRY_RUN CLI_USER="" # Parse CLI arguments @@ -184,6 +185,9 @@ if [[ "$FLAG_DRY_RUN" -eq 1 ]]; then log_warn "DRY-RUN MODE: No changes will be made to the system." fi +# Create pre-setup baseline Timeshift snapshot if on Btrfs +create_timeshift_snapshot "Pre-Setup Baseline: Before executing stages (${SELECTED_STAGES[*]})" "B" + # Execute Selected Stages for stage in "${SELECTED_STAGES[@]}"; do # Skip 00 if it was manually added since it already ran @@ -208,4 +212,7 @@ for stage in "${SELECTED_STAGES[@]}"; do fi done +# Create final completion Timeshift snapshot if on Btrfs +create_timeshift_snapshot "Post-Setup Final: All stages completed successfully (${SELECTED_STAGES[*]})" "O" + log_step "All selected setup stages completed successfully!" diff --git a/stages/00-preflight.sh b/stages/00-preflight.sh index 1a96cca..3e96c33 100755 --- a/stages/00-preflight.sh +++ b/stages/00-preflight.sh @@ -9,6 +9,11 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" source "$SCRIPT_DIR/lib/utils.sh" source "$SCRIPT_DIR/lib/btrfs.sh" +if [[ -f "$SCRIPT_DIR/config/setup.conf" ]]; then + # shellcheck source=/dev/null + source "$SCRIPT_DIR/config/setup.conf" +fi + setup_err_trap log_step "Running Stage 00: Pre-flight System Checks..." @@ -72,4 +77,7 @@ fi log_substep "Checking Btrfs root volume & subvolume layout..." check_and_setup_btrfs_subvolumes +# 7. Create Timeshift Btrfs Snapshot after preflight & subvolume setup +create_timeshift_snapshot "Stage 00: Pre-flight checks & Btrfs baseline" "B" + log_success "Stage 00: Pre-flight checks passed successfully." diff --git a/stages/01-apt-unstable.sh b/stages/01-apt-unstable.sh index 3f9096d..f98fce9 100755 --- a/stages/01-apt-unstable.sh +++ b/stages/01-apt-unstable.sh @@ -8,6 +8,12 @@ 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 + source "$SCRIPT_DIR/config/setup.conf" +fi setup_err_trap @@ -70,6 +76,8 @@ DEBIAN_FRONTEND=noninteractive apt-get install -y apt-listbugs apt-listchanges # 7. Perform Full Dist-Upgrade log_substep "Performing full distribution upgrade to Debian Sid..." +create_timeshift_snapshot "Stage 01: Pre-dist-upgrade to Debian Sid" "B" apt_dist_upgrade +create_timeshift_snapshot "Stage 01: Post-dist-upgrade to Debian Sid" "O" log_success "Stage 01: Debian Unstable migration and upgrade completed successfully!" diff --git a/stages/02-kernel-hardware.sh b/stages/02-kernel-hardware.sh index befa2a0..8ed2596 100755 --- a/stages/02-kernel-hardware.sh +++ b/stages/02-kernel-hardware.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 @@ -33,6 +34,7 @@ apt_update # 2. Determine XanMod Kernel Package log_substep "Detecting CPU microarchitecture level and XanMod branch..." +create_timeshift_snapshot "Stage 02: Pre-XanMod kernel installation" "B" BRANCH="${XANMOD_BRANCH:-main}" log_info "Configured XanMod branch: $BRANCH" @@ -118,4 +120,6 @@ if compgen -G "$SCRIPT_DIR/data/etc/environment.d/*.conf" > /dev/null; then done fi +create_timeshift_snapshot "Stage 02: Post-kernel and hardware tuning" "O" + log_success "Stage 02: Kernel and Hardware Tuning completed successfully!" diff --git a/stages/04-packages.sh b/stages/04-packages.sh index 00c3456..a976e9b 100755 --- a/stages/04-packages.sh +++ b/stages/04-packages.sh @@ -8,6 +8,12 @@ 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 + source "$SCRIPT_DIR/config/setup.conf" +fi setup_err_trap @@ -22,6 +28,8 @@ if [[ ! -d "$PACKAGES_DIR" ]]; then exit 1 fi +create_timeshift_snapshot "Stage 04: Pre-thematic package installation" "B" + # List of APT package lists to process (excluding flatpaks which are handled in stage 08) APT_LISTS=( "01-base.list" @@ -47,4 +55,6 @@ for list_name in "${APT_LISTS[@]}"; do fi done +create_timeshift_snapshot "Stage 04: Post-thematic package installation" "O" + log_success "Stage 04: Thematic package installation completed successfully!" diff --git a/stages/10-hyprland.sh b/stages/10-hyprland.sh index ed5d80f..a73b918 100755 --- a/stages/10-hyprland.sh +++ b/stages/10-hyprland.sh @@ -8,6 +8,12 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" # shellcheck source=lib/utils.sh source "$SCRIPT_DIR/lib/utils.sh" +source "$SCRIPT_DIR/lib/btrfs.sh" + +if [[ -f "$SCRIPT_DIR/config/setup.conf" ]]; then + # shellcheck source=/dev/null + source "$SCRIPT_DIR/config/setup.conf" +fi setup_err_trap @@ -22,6 +28,7 @@ log_info "Configuring Hyprland Desktop for target user: $TARGET_USER ($TARGET_HO # 1. Execute LinuxBeginnings Debian-Hyprland installer log_substep "Downloading and executing LinuxBeginnings Debian-Hyprland installer..." +create_timeshift_snapshot "Stage 10: Pre-Hyprland desktop installation" "B" if command_exists curl; then log_info "Running Debian-Hyprland installer as target user '$TARGET_USER'..." if run_as_target_user bash -c 'sh <(curl -L https://raw.githubusercontent.com/LinuxBeginnings/Debian-Hyprland/main/auto-install.sh)'; then @@ -68,4 +75,7 @@ log_success "Rudimentary Hyprland configuration deployed:" log_info " - SUPER+ENTER: Kitty Terminal" log_info " - SUPER+Q: Close Active Window" log_info " - Login Prompt: Asks user after login to choose Dotfiles setup & installs JetBrains Junie CLI + AwesomeJunieSkills" + +create_timeshift_snapshot "Stage 10: Post-Hyprland desktop setup" "O" + log_success "Stage 10: Hyprland Desktop installation & configuration completed successfully!"