|
| 1 | +#!/bin/bash |
| 2 | + |
| 3 | +# _ _ _ ___ ____ |
| 4 | +# | | | | __ _ ___| | _____ _ __ / _ \/ ___| |
| 5 | +# | |_| |/ _` |/ __| |/ / _ \ '__| | | \___ \ |
| 6 | +# | _ | (_| | (__| < __/ | | |_| |___) | |
| 7 | +# |_| |_|\__,_|\___|_|\_\___|_| \___/|____/ _ |
| 8 | +# | | | |_ __ __| | __ _| |_ ___ / ___| |__ ___ ___| | __ |
| 9 | +# | | | | '_ \ / _` |/ _` | __/ _ \ | | | '_ \ / _ \/ __| |/ / |
| 10 | +# | |_| | |_) | (_| | (_| | || __/ | |___| | | | __/ (__| < |
| 11 | +# \___/| .__/ \__,_|\__,_|\__\___| \____|_| |_|\___|\___|_|\_\ |
| 12 | +# |_| |
| 13 | + |
| 14 | +LOGFILE="/tmp/hackeros-update-check.log" |
| 15 | +UPDATE_SCRIPT="/usr/share/HackerOS/Scripts/Bin/update_system.sh" |
| 16 | +AUTOSTART_FILE="/etc/xdg/autostart/hackeros-update-check.desktop" |
| 17 | + |
| 18 | +# Proste logowanie (bez błędów jeśli brak praw) |
| 19 | +log() { |
| 20 | + echo "$(date --iso-8601=seconds) - $1" >> "$LOGFILE" 2>/dev/null || true |
| 21 | +} |
| 22 | + |
| 23 | +command_exists() { command -v "$1" >/dev/null 2>&1; } |
| 24 | + |
| 25 | +log "=== START check_updates_gui.sh ===" |
| 26 | + |
| 27 | +# --------------------------- |
| 28 | +# BACKEND: tylko sprawdzenia (BEZ GUI) |
| 29 | +# --------------------------- |
| 30 | + |
| 31 | +# APT |
| 32 | +if command_exists apt; then |
| 33 | + APT_UPDATES=$(apt list --upgradable 2>/dev/null | sed '/^Listing.../d;/^$/d' | wc -l) |
| 34 | + : $((APT_UPDATES=APT_UPDATES+0)) |
| 35 | +else |
| 36 | + APT_UPDATES=0 |
| 37 | +fi |
| 38 | + |
| 39 | +# Flatpak |
| 40 | +if command_exists flatpak; then |
| 41 | + # remote-ls --updates może nie istnieć wszędzie; próbujemy i liczymy linie |
| 42 | + FLATPAK_UPDATES=$(flatpak remote-ls --updates 2>/dev/null | sed '/^$/d' | wc -l) |
| 43 | + : $((FLATPAK_UPDATES=FLATPAK_UPDATES+0)) |
| 44 | +else |
| 45 | + FLATPAK_UPDATES=0 |
| 46 | +fi |
| 47 | + |
| 48 | +# Snap |
| 49 | +if command_exists snap; then |
| 50 | + SNAP_UPDATES=$(snap refresh --list 2>/dev/null | tail -n +2 | sed '/^$/d' | wc -l) |
| 51 | + : $((SNAP_UPDATES=SNAP_UPDATES+0)) |
| 52 | +else |
| 53 | + SNAP_UPDATES=0 |
| 54 | +fi |
| 55 | + |
| 56 | +# Firmware (fwupd) |
| 57 | +if command_exists fwupdmgr; then |
| 58 | + FWUPD_UPDATES=$(fwupdmgr get-updates 2>/dev/null | sed '/^$/d' | grep -c -E "Update|Device" || true) |
| 59 | + : $((FWUPD_UPDATES=FWUPD_UPDATES+0)) |
| 60 | +else |
| 61 | + FWUPD_UPDATES=0 |
| 62 | +fi |
| 63 | + |
| 64 | +TOTAL_UPDATES=$((APT_UPDATES + FLATPAK_UPDATES + SNAP_UPDATES + FWUPD_UPDATES)) |
| 65 | +log "Sprawdzenie zakończone: APT=$APT_UPDATES, Flatpak=$FLATPAK_UPDATES, Snap=$SNAP_UPDATES, FWUPD=$FWUPD_UPDATES, SUMA=$TOTAL_UPDATES" |
| 66 | + |
| 67 | +# Jeśli brak aktualizacji -> kompletnie ciche wyjście (nic nie uruchamiamy) |
| 68 | +if [ "$TOTAL_UPDATES" -le 0 ]; then |
| 69 | + log "Brak aktualizacji. Nic nie pokazuję. KONIEC." |
| 70 | + exit 0 |
| 71 | +fi |
| 72 | + |
| 73 | +# --------------------------- |
| 74 | +# Przygotowanie tekstu do GUI |
| 75 | +# --------------------------- |
| 76 | +UPDATE_DETAILS="<b>Dostępne aktualizacje:</b>\n\n" |
| 77 | +UPDATE_DETAILS+="• <b>APT</b>: $APT_UPDATES aktualizacji\n" |
| 78 | +UPDATE_DETAILS+="• <b>Flatpak</b>: $FLATPAK_UPDATES aktualizacji\n" |
| 79 | +UPDATE_DETAILS+="• <b>Snap</b>: $SNAP_UPDATES aktualizacji\n" |
| 80 | +UPDATE_DETAILS+="• <b>Firmware</b>: $FWUPD_UPDATES aktualizacji\n\n" |
| 81 | +UPDATE_DETAILS+="<b>Łącznie</b>: $TOTAL_UPDATES aktualizacji\n\n" |
| 82 | +UPDATE_DETAILS+="Wybierz akcję:" |
| 83 | + |
| 84 | +# --------------------------- |
| 85 | +# Funkcje akcji |
| 86 | +# --------------------------- |
| 87 | +action_close() { |
| 88 | + log "Akcja: Zamknij" |
| 89 | + exit 0 |
| 90 | +} |
| 91 | + |
| 92 | +action_run_update_script_as_user() { |
| 93 | + local target_user="$1" |
| 94 | + local uid="$2" |
| 95 | + |
| 96 | + log "Akcja: Zaktualizuj teraz (uruchamiam update script w kontekście $target_user UID=$uid)" |
| 97 | + |
| 98 | + if [ ! -f "$UPDATE_SCRIPT" ]; then |
| 99 | + log "BŁĄD: Skrypt aktualizacji nie znaleziony: $UPDATE_SCRIPT" |
| 100 | + return 1 |
| 101 | + fi |
| 102 | + |
| 103 | + # Uruchom skrypt jako ten użytkownik z sudo (jeżeli wymagane) w tle, aby nie blokować GUI. |
| 104 | + # Najpierw spróbuj uruchomić z prawami użytkownika (jeśli update_script nie wymaga sudo) |
| 105 | + # Jeśli potrzebujesz sudo, skrypt będzie uruchamiany z sudo przez użytkownika. |
| 106 | + # Używamy runuser aby zachować środowisko użytkownika (bez tworzenia okien przed checkiem). |
| 107 | + if command_exists runuser; then |
| 108 | + # Uruchom z przekazanymi zmiennymi środowiskowymi (DISPLAY i DBUS) |
| 109 | + local envfile="/tmp/hackeros_update_env_${uid}.sh" |
| 110 | + # Utwórz envfile z potrzebnymi zmiennymi (jeżeli istnieją) |
| 111 | + echo "export DISPLAY='${DISPLAY_OVERRIDE:-:0}'" > "$envfile" |
| 112 | + if [ -n "$DBUS_OVERRIDE" ]; then |
| 113 | + echo "export DBUS_SESSION_BUS_ADDRESS='$DBUS_OVERRIDE'" >> "$envfile" |
| 114 | + fi |
| 115 | + chmod 600 "$envfile" 2>/dev/null || true |
| 116 | + |
| 117 | + # Uruchom skrypt przez runuser w tle |
| 118 | + runuser -u "$target_user" -- bash -lc "source '$envfile' >/dev/null 2>&1; nohup sudo '$UPDATE_SCRIPT' >/dev/null 2>&1 & disown" >/dev/null 2>&1 || true |
| 119 | + rm -f "$envfile" 2>/dev/null || true |
| 120 | + log "Skrypt update uruchomiony (nohup) przez $target_user." |
| 121 | + else |
| 122 | + # Fallback: spróbuj zwykłego sudo w tle |
| 123 | + nohup sudo "$UPDATE_SCRIPT" >/dev/null 2>&1 & disown |
| 124 | + log "Skrypt update uruchomiony (nohup sudo fallback)." |
| 125 | + fi |
| 126 | + return 0 |
| 127 | +} |
| 128 | + |
| 129 | +action_disable_notifications() { |
| 130 | + log "Akcja: Nie pokazuj więcej -> usuwam: $AUTOSTART_FILE" |
| 131 | + if [ -f "$AUTOSTART_FILE" ]; then |
| 132 | + if sudo rm -f "$AUTOSTART_FILE" >/dev/null 2>&1; then |
| 133 | + log "Usunięto plik autostartu: $AUTOSTART_FILE" |
| 134 | + else |
| 135 | + log "Nie udało się usunąć autostartu (brak uprawnień?): $AUTOSTART_FILE" |
| 136 | + fi |
| 137 | + else |
| 138 | + log "Plik autostartu nie istniał: $AUTOSTART_FILE" |
| 139 | + fi |
| 140 | + exit 0 |
| 141 | +} |
| 142 | + |
| 143 | +# --------------------------- |
| 144 | +# Uruchomienie Zenity w kontekście sesji graficznej użytkownika |
| 145 | +# --------------------------- |
| 146 | +# Cel: wywołać Zenity tylko teraz (po wykryciu aktualizacji) w sesji graficznej zalogowanego użytkownika, |
| 147 | +# by okno należało do tej sesji i nie tworzyło "niewidzialnego" wpisu innego procesu na pasku zadań. |
| 148 | + |
| 149 | +# Znajdź aktywną sesję użytkownika (preferuj aktywną sesję local) |
| 150 | +find_graphical_session() { |
| 151 | + # Preferuj loginctl (systemd) — zwraca USER:UID i SESSION |
| 152 | + if command_exists loginctl; then |
| 153 | + while IFS= read -r line; do |
| 154 | + # line: SESSION UID USER SEAT TTY |
| 155 | + session_id=$(echo "$line" | awk '{print $1}') |
| 156 | + # sprawdź czy sesja aktywna i ma Display |
| 157 | + active=$(loginctl show-session "$session_id" -p Active --value 2>/dev/null || echo "no") |
| 158 | + state=$(loginctl show-session "$session_id" -p State --value 2>/dev/null || echo "") |
| 159 | + user=$(loginctl show-session "$session_id" -p Name --value 2>/dev/null || echo "") |
| 160 | + uid=$(loginctl show-session "$session_id" -p Remote --value 2>/dev/null || true) |
| 161 | + # choose active local session |
| 162 | + if [ "$active" = "yes" ] || [ "$state" = "active" ]; then |
| 163 | + # Resolve user and uid |
| 164 | + USERNAME="$user" |
| 165 | + USERID=$(id -u "$USERNAME" 2>/dev/null || true) |
| 166 | + echo "$USERNAME:$USERID:$session_id" |
| 167 | + return 0 |
| 168 | + fi |
| 169 | + done < <(loginctl list-sessions --no-legend 2>/dev/null | awk '{print $1}') |
| 170 | + fi |
| 171 | + |
| 172 | + # Fallback: wybierz pierwszy użytkownika z procesem typu gnome-session/plasma-session/Xorg/Xwayland |
| 173 | + for p in gnome-session plasma-session startplasma-x11 Xorg Xwayland; do |
| 174 | + pid=$(pgrep -u "$(logname 2>/dev/null || echo $USER)" -x "$p" | head -n1) |
| 175 | + if [ -n "$pid" ]; then |
| 176 | + USERNAME=$(ps -o user= -p "$pid" | awk '{print $1}') |
| 177 | + USERID=$(id -u "$USERNAME" 2>/dev/null || true) |
| 178 | + echo "$USERNAME:$USERID:na" |
| 179 | + return 0 |
| 180 | + fi |
| 181 | + done |
| 182 | + |
| 183 | + # Ostatecznie zwróć bieżącego użytkownika procesu wykonującego (jeśli to nie root) |
| 184 | + if [ -n "$SUDO_USER" ]; then |
| 185 | + USERNAME="$SUDO_USER" |
| 186 | + else |
| 187 | + USERNAME="$(logname 2>/dev/null || echo $USER)" |
| 188 | + fi |
| 189 | + USERID=$(id -u "$USERNAME" 2>/dev/null || true) |
| 190 | + echo "$USERNAME:$USERID:na" |
| 191 | + return 0 |
| 192 | +} |
| 193 | + |
| 194 | +session_info=$(find_graphical_session) |
| 195 | +USERNAME="$(echo "$session_info" | cut -d: -f1)" |
| 196 | +USERID="$(echo "$session_info" | cut -d: -f2)" |
| 197 | + |
| 198 | +log "Wybrana sesja użytkownika: USER=$USERNAME UID=$USERID" |
| 199 | + |
| 200 | +# Przygotuj zmienne środowiskowe dla sesji użytkownika (DISPLAY i DBUS) |
| 201 | +# Najczęściej DISPLAY=:0 i DBUS pod /run/user/$UID/bus |
| 202 | +DISPLAY_OVERRIDE="" |
| 203 | +DBUS_OVERRIDE="" |
| 204 | + |
| 205 | +# Jeśli XDISPLAY jest ustawiony w środowisku aktualnego użytkownika (próba odczytu), użyj go |
| 206 | +# Spróbuj odczytać DISPLAY i DBUS z plików w /proc dla procesu sesji (jeśli możliwe) |
| 207 | +if [ -n "$USERID" ] && [ "$USERID" != "0" ]; then |
| 208 | + # Najpierw ustaw domyślnie DISPLAY=:0 |
| 209 | + DISPLAY_OVERRIDE=":0" |
| 210 | + # DBUS session bus |
| 211 | + if [ -e "/run/user/${USERID}/bus" ]; then |
| 212 | + DBUS_OVERRIDE="unix:path=/run/user/${USERID}/bus" |
| 213 | + fi |
| 214 | +fi |
| 215 | + |
| 216 | +# Jeśli mamy DBUS_OVERRIDE i DISPLAY_OVERRIDE to spróbuj uruchomić zenity jako ten user |
| 217 | +if command_exists zenity && [ -n "$DISPLAY_OVERRIDE" ]; then |
| 218 | + # Zbuduj polecenie zenity (radiolist) |
| 219 | + ZEN_CMD="zenity --list --radiolist --title='Aktualizacje systemu' --text='$UPDATE_DETAILS' --column='' --column='Akcja' TRUE 'Zamknij' FALSE 'Zaktualizuj teraz' FALSE 'Nie pokazuj więcej' --width=520 --height=300" |
| 220 | + |
| 221 | + # Uruchom w kontekście użytkownika, przekazując potrzebne env |
| 222 | + # Najpierw sprawdź czy runuser istnieje i możemy go użyć |
| 223 | + if command_exists runuser; then |
| 224 | + # Eksportujemy DISPLAY i DBUS w linii poleceń, aby zenity należał do sesji tego użytkownika |
| 225 | + if [ -n "$DBUS_OVERRIDE" ]; then |
| 226 | + # Zapisz je w zmiennej i uruchom |
| 227 | + log "Uruchamiam Zenity jako $USERNAME z DISPLAY=$DISPLAY_OVERRIDE i DBUS=$DBUS_OVERRIDE" |
| 228 | + runuser -u "$USERNAME" -- bash -lc "export DISPLAY='$DISPLAY_OVERRIDE'; export DBUS_SESSION_BUS_ADDRESS='$DBUS_OVERRIDE'; $ZEN_CMD" >/tmp/hackeros_zenity_out.$$ 2>/tmp/hackeros_zenity_err.$$ || true |
| 229 | + CHOICE=$(cat /tmp/hackeros_zenity_out.$$ 2>/dev/null || true) |
| 230 | + rm -f /tmp/hackeros_zenity_out.$$ /tmp/hackeros_zenity_err.$$ 2>/dev/null || true |
| 231 | + else |
| 232 | + # Brak DBUS, uruchom jedynie z DISPLAY |
| 233 | + log "Uruchamiam Zenity jako $USERNAME z DISPLAY=$DISPLAY_OVERRIDE (brak DBUS)" |
| 234 | + runuser -u "$USERNAME" -- bash -lc "export DISPLAY='$DISPLAY_OVERRIDE'; $ZEN_CMD" >/tmp/hackeros_zenity_out.$$ 2>/tmp/hackeros_zenity_err.$$ || true |
| 235 | + CHOICE=$(cat /tmp/hackeros_zenity_out.$$ 2>/dev/null || true) |
| 236 | + rm -f /tmp/hackeros_zenity_out.$$ /tmp/hackeros_zenity_err.$$ 2>/dev/null || true |
| 237 | + fi |
| 238 | + else |
| 239 | + # fallback: uruchom bez runuser ale z env (może pojawić się w kontekście tego procesu) |
| 240 | + log "Brak runuser — uruchamiam Zenity w bieżącym kontekście (fallback)" |
| 241 | + export DISPLAY="$DISPLAY_OVERRIDE" |
| 242 | + [ -n "$DBUS_OVERRIDE" ] && export DBUS_SESSION_BUS_ADDRESS="$DBUS_OVERRIDE" |
| 243 | + CHOICE=$(bash -c "$ZEN_CMD" 2>/dev/null) || true |
| 244 | + fi |
| 245 | +else |
| 246 | + # Brak zenity lub brak DISPLAY info -> fallback tekstowy w terminalu (jeśli ktoś uruchamia ręcznie) |
| 247 | + log "Zenity niedostępny lub brak informacji o DISPLAY/DBUS -> fallback terminal" |
| 248 | + echo -e "$UPDATE_DETAILS" |
| 249 | + echo "1) Zamknij" |
| 250 | + echo "2) Zaktualizuj teraz" |
| 251 | + echo "3) Nie pokazuj więcej" |
| 252 | + read -rp "Wybór: " choice |
| 253 | + case $choice in |
| 254 | + 1) action_close ;; |
| 255 | + 2) action_run_update_script_as_user "$USERNAME" "$USERID"; exit 0 ;; |
| 256 | + 3) action_disable_notifications ;; |
| 257 | + *) action_close ;; |
| 258 | + esac |
| 259 | +fi |
| 260 | + |
| 261 | +# Jeżeli CHOICE jest puste oznacza że użytkownik zamknął okno -> nic do zrobienia |
| 262 | +if [ -z "${CHOICE:-}" ]; then |
| 263 | + log "Brak wyboru (okno zamknięte lub anulowane). Kończę." |
| 264 | + exit 0 |
| 265 | +fi |
| 266 | + |
| 267 | +# Znormalizuj możliwe wyniki (Zenity może zwracać etykietę) |
| 268 | +case "$CHOICE" in |
| 269 | + "Zamknij"|"Zamknij\n"|"Zamknij\r") |
| 270 | + action_close |
| 271 | + ;; |
| 272 | + "Zaktualizuj teraz"|"Zaktualizuj teraz\n") |
| 273 | + # Uruchom update script w kontekście użytkownika, by okno postępu (jeśli będą) pojawiło się w sesji |
| 274 | + # Przekaż username i uid |
| 275 | + action_run_update_script_as_user "$USERNAME" "$USERID" |
| 276 | + ;; |
| 277 | + "Nie pokazuj więcej"|"Nie pokazuj więcej\n") |
| 278 | + action_disable_notifications |
| 279 | + ;; |
| 280 | + *) |
| 281 | + # W niektórych środowiskach zenity może zwracać wynik w innym formacie - porównaj fragmenty |
| 282 | + if echo "$CHOICE" | grep -qi "Zaktualizuj"; then |
| 283 | + action_run_update_script_as_user "$USERNAME" "$USERID" |
| 284 | + elif echo "$CHOICE" | grep -qi "Nie pokazuj"; then |
| 285 | + action_disable_notifications |
| 286 | + else |
| 287 | + action_close |
| 288 | + fi |
| 289 | + ;; |
| 290 | +esac |
| 291 | + |
| 292 | +# Koniec |
| 293 | +log "Koniec działania skryptu." |
| 294 | +exit 0 |
0 commit comments