Resume Automation & KeePassXC Sync

Overview

This system automates post-resume maintenance tasks, including Bluetooth reconnection, hardware daemon synchronization (tccd), and a conditional, rolling KeePassXC database backup. Architecture

To resolve udisksctl authentication failures and ensure proper session environment inheritance, the implementation uses a decoupled "Trigger/Worker" architecture.

  • Trigger (System Level): A root-owned service monitors system sleep targets. Upon wake, it initiates the user-level worker.

  • Worker (User Level): A user-owned service executes the script with full access to the display session, D-Bus, and user permissions.

Implementation Details

  1. System Trigger (/etc/systemd/system/resume-fix.service)

This service acts as the kernel-level listener. It does not run the script directly but initiates the user service.


[Unit]
Description=Trigger User Resume Scripts
After=suspend.target hibernate.target hybrid-sleep.target

[Service]
Type=oneshot
ExecStart=/usr/bin/su - simon -c "XDG_RUNTIME_DIR=/run/user/1000 systemctl --user start resume-worker.service"

[Install]
WantedBy=suspend.target hibernate.target hybrid-sleep.target
  1. User Worker (~/.config/systemd/user/resume-worker.service)

This service runs the script contextually within the active user session.

[Unit]
Description=User Resume Worker
After=graphical-session.target

[Service]
Type=oneshot
ExecStart=/home/simon/bin/resume.sh

[Install]
WantedBy=default.target

The file (/home/simon/bin/resume.sh) contains:

#!/usr/bin/fish

# --- 1. Delay & Environment Setup ---
sleep 5
set TARGET_USER "simon"
set DEVICE "4E:E7:34:D0:AA:6A"
set DISK "HPV222W"
set MOUNTS "/run/media/$TARGET_USER"
set KEEPASSFILE "/home/$TARGET_USER/Documents/Computer/SimonPasswords.kdbx"

# --- 2. Bluetooth Management ---
set STATE (rfkill | string match -r '.*bluetooth.*\\bblocked\\b')

if test -n "$STATE"
    set ADAPTOR (rfkill | string match -r '.*bluetooth.*\\bblocked\\b' | awk '{print $1}')
    rfkill unblock $ADAPTOR
    sleep 2
end

expect -c "
set timeout 60
spawn bluetoothctl
send -- \"connect $DEVICE\r\"
expect \"Connection successful\"
send -- \"exit\r\"
expect eof
"

# --- 3. Hardware Daemon Sync ---
# Running directly as root from the service, this functions perfectly
sleep 2
if systemctl is-active --quiet tccd
    systemctl restart tccd
end

# --- 4. KeePassXC Once-Per-Day Rolling Backup ---
if test -e /dev/disk/by-label/$DISK
    # Mount using the target user session to avoid root ownership conflicts
    if not test -d "$MOUNTS/$DISK"
        udisksctl mount -b /dev/disk/by-label/$DISK
    end

    if test -d "$MOUNTS/$DISK"
        set TODAY (date +%Y%m%d)

        # Check if a backup matching today's date stamp already exists
        set TODAY_CHECK (ls -1 "$MOUNTS/$DISK/" | string match -r "SimonPasswords_$TODAY\_\\d{6}\\.kdbx")

        if test -z "$TODAY_CHECK"
            # No backup found for today, proceed with backup
            set TIMESTAMP (date +%Y%m%d_%H%M%S)
            set BACKUP_NAME "SimonPasswords_$TIMESTAMP.kdbx"

            cp "$KEEPASSFILE" "$MOUNTS/$DISK/$BACKUP_NAME"
            chown $TARGET_USER:$TARGET_USER "$MOUNTS/$DISK/$BACKUP_NAME"

            # Manage rolling backups: keep only 5 total matching the pattern
            set ALL_BACKUPS (ls -1 "$MOUNTS/$DISK/" | string match -r '^SimonPasswords_\\d{8}_\\d{6}\\.kdbx$' | sort)
            set TOTAL_BACKUPS (count $ALL_BACKUPS)

            if test $TOTAL_BACKUPS -gt 5
                set TO_REMOVE_COUNT (math $TOTAL_BACKUPS - 5)
                for i in (seq 1 $TO_REMOVE_COUNT)
                    rm -f "$MOUNTS/$DISK/$ALL_BACKUPS[$i]"
                end
            end

            sync

            if udisksctl unmount -b /dev/disk/by-label/$DISK
                notify-send --icon drive-harddisk "Security Key Synced" "Database updated (Daily copy created) and $DISK safely unmounted."
            else
               notify-send --icon error "Unmount Failed" "Database updated, but $DISK is still busy."
            end
        else
            # Backup already exists for today, unmount safely without writing
            echo "Backup for today ($TODAY) already exists. Skipping sync."
            udisksctl unmount -b /dev/disk/by-label/$DISK
        end
    end
else
    echo "Bootkey $DISK not found. Skipping sync."
end


Posted

16:30 01/06/2026