From 7282153c2720e211884f3b9e66db169f6a334df6 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Thu, 22 Oct 2026 12:48:42 +0200 Subject: [PATCH] GUI: Power-Menu (Beenden, Neustarten, Herunterfahren) Haengt vor Reboot/Shutdown alle Datentraeger sauber aus. Verwendet systemctl mit Fallback auf reboot/poweroff/shutdown. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 6 ++++++ app/pc_unlocker.py | 39 +++++++++++++++++++++++++++++++++++++++ app/puk/__init__.py | 2 +- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9610b1f..838c040 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ Versionierung nach [SemVer](https://semver.org/lang/de/). ## [Unreleased] +### Added +- GUI: Einträge „Beenden", „Neustarten" und „Herunterfahren" (hängt vorher + alle Datenträger sauber aus). + +## [0.1.1] - 2026-10-22 + ### Added - GUI (tkinter) zum Auflisten, Mounten und Aushängen von Partitionen. - Linux-Backend: Passwort leeren, neues SHA-512-Passwort setzen, Konto entsperren. diff --git a/app/pc_unlocker.py b/app/pc_unlocker.py index 418eb35..7e840ef 100755 --- a/app/pc_unlocker.py +++ b/app/pc_unlocker.py @@ -12,6 +12,8 @@ Benoetigt root und ein X-Display (laeuft im Live-System automatisch). from __future__ import annotations import os +import shutil +import subprocess import sys import threading import tkinter as tk @@ -81,6 +83,15 @@ class App(tk.Tk): self.log = tk.Text(logf, height=8, state="disabled", wrap="word") self.log.pack(fill="both", expand=True, padx=4, pady=4) + power = ttk.Frame(self) + power.pack(fill="x", **pad) + ttk.Button(power, text="Herunterfahren", + command=self.do_shutdown).pack(side="right", padx=4) + ttk.Button(power, text="Neustarten", + command=self.do_reboot).pack(side="right", padx=4) + ttk.Button(power, text="Beenden", + command=self._on_close).pack(side="right", padx=4) + self._log("PC-Unlocker gestartet. Datentraeger auswaehlen und mounten.") def _log(self, msg: str) -> None: @@ -298,6 +309,34 @@ class App(tk.Tk): disks.unmount_all(self.parts) self.destroy() + def _power(self, action: str, label: str, cmds: list[list[str]]) -> None: + """Alles aushaengen und System herunterfahren/neustarten.""" + if not messagebox.askyesno("Bestaetigen", f"System jetzt {label}?"): + return + disks.unmount_all(self.parts) + self._log(f"Alle Datentraeger ausgehaengt. System wird {label}...") + self.update_idletasks() + for cmd in cmds: + if shutil.which(cmd[0]) is None: + continue + try: + subprocess.Popen(cmd) + self.destroy() + return + except Exception: # noqa: BLE001 + continue + messagebox.showerror( + "Fehler", f"Konnte nicht {label} (kein passendes Kommando gefunden).") + + def do_reboot(self) -> None: + self._power("reboot", "neu starten", + [["systemctl", "reboot"], ["reboot"]]) + + def do_shutdown(self) -> None: + self._power("poweroff", "herunterfahren", + [["systemctl", "poweroff"], ["poweroff"], + ["shutdown", "-h", "now"]]) + def main() -> int: if os.geteuid() != 0: diff --git a/app/puk/__init__.py b/app/puk/__init__.py index 2775084..9b22955 100644 --- a/app/puk/__init__.py +++ b/app/puk/__init__.py @@ -1,3 +1,3 @@ """PC-Unlocker: Offline-Recovery fuer lokale Linux- und Windows-Konten.""" -__version__ = "0.1.0" +__version__ = "0.1.1"