Nicole Portas преди 3 седмици
ревизия
fbc7cc91f6
променени са 2 файла, в които са добавени 225 реда и са изтрити 0 реда
  1. 14 0
      README.md
  2. 211 0
      gnome-backup

+ 14 - 0
README.md

@@ -0,0 +1,14 @@
+# GNOME Settings Backup & Restore
+
+[cite_start]This script is a specialized utility designed to backup, archive, and restore a complete GNOME desktop environment to another user profile[cite: 1, 16]. [cite_start]It handles the migration of themes, extensions, and low-level dconf settings while ensuring that file ownership is correctly mapped to the target user[cite: 10, 30].
+
+---
+
+## Features
+
+* [cite_start]**Complete Profile Capture**: Backs up dconf databases, shell extensions, icons, themes, and fonts[cite: 4, 10].
+* [cite_start]**Security Focused**: Explicitly scrubs `keyrings` and `kwalletd` data to ensure your sensitive credentials aren't leaked in the archive.
+* [cite_start]**Cross-User Migration**: Designed to restore a profile to a different username and home directory with automatic ownership fixes[cite: 16, 30].
+* [cite_start]**Headless dconf Loading**: Generates a helper script (`load_gnome_settings.sh`) that can load settings even without an active graphical session by spawning a temporary D-Bus[cite: 31, 32].
+* [cite_start]**Dry Run Support**: Includes a simulation mode to see exactly what files will be affected before any changes are made[cite: 2, 5, 23].
+

+ 211 - 0
gnome-backup

@@ -0,0 +1,211 @@
+#!/usr/bin/env bash
+
+# Exit immediately if a command exits with a non-zero status
+set -e
+
+function show_usage() {
+    echo "Usage:"
+    echo "  $0 [--dry-run] backup <archive_name.tgz>"
+    echo "  $0 [--dry-run] restore <archive_name.tgz> <target_home_directory> <target_username>"
+    echo ""
+    echo "Options:"
+    echo "  --dry-run    Show what would be copied/extracted without making any actual changes."
+    echo ""
+    echo "Example:"
+    echo "  $0 --dry-run backup /tmp/my_gnome_setup.tgz"
+    echo "  sudo $0 restore /tmp/my_gnome_setup.tgz /home/guest guest"
+    exit 1
+}
+
+# Check for dry-run flag
+DRY_RUN=0
+if [[ "$1" == "--dry-run" ]]; then
+    DRY_RUN=1
+    shift
+fi
+
+if [ "$#" -lt 2 ]; then
+    show_usage
+fi
+
+ACTION="$1"
+ARCHIVE="$2"
+
+# Define the exact paths we care about (relative to the home directory)
+GNOME_PATHS=(
+    ".config/monitors.xml"
+    ".config/mimeapps.list"
+    ".config/gtk-3.0"
+    ".config/gtk-4.0"
+    ".config/fontconfig"
+    ".config/user-dirs.dirs"
+    ".config/autostart"
+    ".local/share/gnome-shell/extensions"
+    ".local/share/backgrounds"
+    ".local/share/fonts"
+    ".local/share/themes"
+    ".local/share/icons"
+    ".themes"
+    ".icons"
+    ".fonts"
+)
+
+if [ "$ACTION" == "backup" ]; then
+    if [ "$DRY_RUN" -eq 1 ]; then
+        echo "==> [DRY RUN] Starting GNOME backup simulation..."
+        echo "--> [DRY RUN] Would dump dconf database to dconf_backup.ini"
+        echo "--> [DRY RUN] Would copy the following paths from $HOME:"
+        
+        for path in "${GNOME_PATHS[@]}"; do
+            if [ -e "$HOME/$path" ]; then
+                echo "    [DRY RUN] MATCH: $path"
+            else
+                echo "    [DRY RUN] MISSING (Skipping): $path"
+            fi
+        done
+        
+        echo "--> [DRY RUN] Would aggressively scrub any 'keyrings' directories."
+        echo "--> [DRY RUN] Would compress all matched files to: $ARCHIVE"
+        echo "==> [DRY RUN] Backup simulation complete. No files were actually touched."
+        exit 0
+    fi
+
+    echo "==> Starting GNOME backup..."
+    
+    # Create a staging area in /tmp
+    STAGING_DIR="/tmp/gnome_backup_$$"
+    mkdir -p "$STAGING_DIR"
+
+    echo "--> Dumping dconf database..."
+    dconf dump / > "$STAGING_DIR/dconf_backup.ini"
+
+    echo "--> Gathering visual assets and system configs..."
+    for path in "${GNOME_PATHS[@]}"; do
+        if [ -e "$HOME/$path" ]; then
+            # Create the parent directory structure in the staging area
+            mkdir -p "$STAGING_DIR/$(dirname "$path")"
+            # Copy the files over, preserving their structure
+            cp -a "$HOME/$path" "$STAGING_DIR/$(dirname "$path")/"
+            echo "    Saved: $path"
+        fi
+    done
+
+    echo "--> Scrubbing keyrings and password data..."
+    # Explicitly find and annihilate any keyrings that managed to sneak into the staging area
+    find "$STAGING_DIR" -type d \( -name "keyrings" -o -name "kwalletd" \) -exec rm -rf {} + 2>/dev/null || true
+
+    echo "--> Compressing to $ARCHIVE..."
+    # Pack it all up from the staging directory
+    tar -czf "$ARCHIVE" -C "$STAGING_DIR" .
+    
+    # Clean up the bloody mess in /tmp
+    rm -rf "$STAGING_DIR"
+    
+    echo "==> Backup complete! Your setup is safe at $ARCHIVE"
+
+elif [ "$ACTION" == "restore" ]; then
+    TARGET_DIR="$3"
+    TARGET_USER="$4"
+    
+    if [ -z "$TARGET_DIR" ] || [ ! -d "$TARGET_DIR" ]; then
+        echo "Error: You must provide a valid target directory."
+        show_usage
+    fi
+
+    if [ -z "$TARGET_USER" ]; then
+        echo "Error: You must provide the exact target username as the 4th argument."
+        show_usage
+    fi
+
+    # We need root to properly chown the files to the new user
+    if [ "$EUID" -ne 0 ] && [ "$DRY_RUN" -eq 0 ]; then
+        echo "Warning: You must run the 'restore' command with sudo,"
+        echo "otherwise fixing the file ownership for the new profile will fail."
+        exit 1
+    fi
+
+    # Deduce the primary group for the target user (usually matches the username)
+    TARGET_GROUP=$(id -gn "$TARGET_USER" 2>/dev/null || echo "$TARGET_USER")
+
+    if [ "$DRY_RUN" -eq 1 ]; then
+        echo "==> [DRY RUN] Starting GNOME restore simulation to $TARGET_DIR..."
+        
+        if [ ! -f "$ARCHIVE" ]; then
+            echo "Error: Backup archive $ARCHIVE does not exist. Cannot simulate restore."
+            exit 1
+        fi
+
+        echo "--> [DRY RUN] Target user explicitly set to: $TARGET_USER:$TARGET_GROUP"
+        echo "--> [DRY RUN] Would extract the following contents from $ARCHIVE to $TARGET_DIR:"
+        tar -tf "$ARCHIVE" | sed 's/^/    [DRY RUN] /'
+        
+        echo "--> [DRY RUN] Would exclude 'keyrings' and 'dconf_backup.ini' from file sync."
+        echo "--> [DRY RUN] Would scaffold standard XDG user directories (Desktop, Downloads, etc.)"
+        echo "--> [DRY RUN] Would run a blanket chown on $TARGET_DIR to $TARGET_USER:$TARGET_GROUP"
+        echo "--> [DRY RUN] Would deploy helper script $TARGET_DIR/load_gnome_settings.sh"
+        echo "==> [DRY RUN] Restore simulation complete. No files were actually deployed or altered."
+        exit 0
+    fi
+
+    echo "==> Starting GNOME restore to $TARGET_DIR..."
+
+    STAGING_DIR="/tmp/gnome_restore_$$"
+    mkdir -p "$STAGING_DIR"
+
+    echo "--> Extracting archive..."
+    tar -xzf "$ARCHIVE" -C "$STAGING_DIR"
+
+    echo "--> Deploying files into $TARGET_DIR..."
+    # Copy everything EXCEPT the dconf dump and any leftover keyrings into the target directory
+    rsync -a "$STAGING_DIR/" "$TARGET_DIR/" --exclude "dconf_backup.ini" --exclude "keyrings" --exclude "kwalletd"
+
+    echo "--> Scaffolding standard XDG user directories..."
+    # Create the empty default folders so GNOME doesn't shit a brick
+    for dir in Desktop Documents Downloads Music Pictures Public Templates Videos; do
+        mkdir -p "$TARGET_DIR/$dir"
+    done
+
+    echo "--> Ensuring .cache/dconf exists..."
+    # Pre-create the dconf cache directory so the helper script never throws a 'Permission denied'
+    mkdir -p "$TARGET_DIR/.cache/dconf"
+
+    echo "--> Running a blanket ownership fix across the entire home directory to $TARGET_USER:$TARGET_GROUP..."
+    # Force absolute ownership of every single file and folder in the home directory to the new user
+    chown -R "$TARGET_USER:$TARGET_GROUP" "$TARGET_DIR"
+
+    echo "--> Prepping the headless dconf restore script..."
+    DCONF_SCRIPT="$TARGET_DIR/load_gnome_settings.sh"
+    cp "$STAGING_DIR/dconf_backup.ini" "$TARGET_DIR/"
+    
+    cat << 'EOF' > "$DCONF_SCRIPT"
+#!/usr/bin/env bash
+echo "Loading GNOME settings into dconf..."
+
+# If there is no active display/Wayland session, we spawn a temporary headless D-Bus
+# so dconf can write the local database file without throwing a fit.
+if [ -z "$DBUS_SESSION_BUS_ADDRESS" ]; then
+    echo "No graphical D-Bus session detected. Firing up a headless session..."
+    dbus-run-session dconf load / < "$HOME/dconf_backup.ini"
+else
+    dconf load / < "$HOME/dconf_backup.ini"
+fi
+
+echo "Done! You can safely delete this script and dconf_backup.ini."
+EOF
+
+    chmod +x "$DCONF_SCRIPT"
+    chown "$TARGET_USER:$TARGET_GROUP" "$DCONF_SCRIPT" "$TARGET_DIR/dconf_backup.ini"
+
+    # Clean up /tmp
+    rm -rf "$STAGING_DIR"
+
+    echo "==> Files restored successfully!"
+    echo "====================================================================="
+    echo "IMPORTANT: Log into the new profile ($TARGET_USER) or switch to a TTY."
+    echo "Run: ./load_gnome_settings.sh"
+    echo "====================================================================="
+
+else
+    echo "Error: Invalid action. Use 'backup' or 'restore'."
+    show_usage
+fi