#!/bin/bash set -euo pipefail # Pfade BOOTC="/usr/bin/bootc" FLATPAK="/usr/bin/flatpak" LOGGER="/usr/bin/logger" LOGINCTL="/usr/bin/loginctl" NOTIFY="/usr/bin/notify-send" SUDO="/usr/bin/sudo" SYSTEMCTL="/usr/bin/systemctl" TAG="bootc-timer" # ============================================================================= # Flatpaks im Hintergrund aktualisieren # ============================================================================= $LOGGER -t "$TAG" "Suche nach Flatpak-Updates..." # || true verhindert den Abbruch, falls Flatpak temporär Netzwerkfehler hat $FLATPAK update -y --noninteractive || $LOGGER -t "$TAG" "Flatpak-Update fehlgeschlagen oder keine Updates vorhanden." # ============================================================================= # 1. Bootc Upgrade ausführen # ============================================================================= $LOGGER -t "$TAG" "Suche nach System-Updates (bootc)..." # || true ist hier ESSENZIELL, da bootc upgrade bei "keine Updates" je nach Version # einen Exit-Code ungleich 0 zurückgeben kann, was set -e triggern würde. $BOOTC upgrade || $LOGGER -t "$TAG" "bootc upgrade beendet (System möglicherweise bereits aktuell)." # ============================================================================= # 2. Status-Check (Sicherer Umgang mit jq) # ============================================================================= # Wir lesen den Status aus und fangen den Wert direkt ab. # Wenn 'staged' gleich null ist, liefert jq den Text "null". STAGED_STATUS=$( $BOOTC status --json | jq -r '.status.staged' 2>/dev/null || echo "null" ) if [[ "$STAGED_STATUS" == "null" ]]; then # KEIN Update gefunden $LOGGER -t "$TAG" "System aktuell (keine gestageden Updates vorhanden)." exit 0 else $LOGGER -t "$TAG" "Update gefunden und gestaged. Suche aktiven Desktop-User..." # ============================================================================= # 3. Robust den User der AKTIVEN grafischen Sitzung (seat0) ermitteln # ============================================================================= # Wir vermeiden die Standard-Pipeline | while read, um Subshell-Probleme zu umgehen. # Stattdessen nutzen wir ein Process Substitution (< <(...)) USER_ID="" while read -r sid rest; do if [[ -n "$sid" ]]; then SEAT=$( $LOGINCTL show-session "$sid" -p Seat --value 2>/dev/null || echo "" ) STATE=$( $LOGINCTL show-session "$sid" -p State --value 2>/dev/null || echo "" ) if [[ "$SEAT" == "seat0" ]] && [[ "$STATE" == "active" ]]; then USER_ID=$( $LOGINCTL show-session "$sid" -p UID --value 2>/dev/null || echo "" ) break fi fi done < <($LOGINCTL list-sessions --no-legend) if [[ -z "$USER_ID" ]]; then $LOGGER -t "$TAG" "Update bereit, aber kein aktiver Desktop-User auf seat0 gefunden." exit 0 fi $LOGGER -t "$TAG" "Sende Benachrichtigung an User-ID: $USER_ID" # ============================================================================= # 4. Benachrichtigung senden # ============================================================================= # Wenn der User die Benachrichtigung ignoriert/schließt, gibt notify-send einen # Exit-Code > 0 zurück. Das "|| echo 'closed'" fängt das sauber ab. ACTION=$( $SUDO -u "#$USER_ID" env \ DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$USER_ID/bus \ XDG_RUNTIME_DIR=/run/user/$USER_ID \ $NOTIFY "System-Update bereit" \ "Ein neues Image wurde heruntergeladen. Jetzt neu starten?" \ --app-name="System-Update" \ --icon=software-update-available \ --urgency=critical \ --action="reboot=Jetzt neu starten" \ --wait || echo "closed" ) # ============================================================================= # 5. Auswertung der User-Aktion # ============================================================================= if [[ "$ACTION" == "reboot" ]]; then $LOGGER -t "$TAG" "User hat Reboot gewählt. Starte System neu..." $SYSTEMCTL reboot else $LOGGER -t "$TAG" "Benachrichtigung wurde geschlossen, ignoriert oder Timeout ($ACTION)." fi fi