"""Laufwerks-Discovery über /sys und ioctls — ehrlich, ohne udev. Warum kein udevadm mehr: Im Container läuft kein udevd, die udev-Datenbank ist leer — `udevadm info` lieferte schlicht nichts (der alte Weg zeigte deshalb nie ein Laufwerk an). /sys/class/block//device/{vendor,model} kommt dagegen direkt vom Kernel und funktioniert überall. """ import glob import os from fcntl import ioctl from detection import ( CDS_DISC_OK, classify, disc_size_bytes, disc_status, drive_status, ) # include/uapi/linux/cdrom.h CDROMEJECT = 0x5309 def eject(device_path: str) -> None: """Wirft die Disc aus (CDROMEJECT-ioctl). Wirft OSError bei Fehlern.""" fd = os.open(device_path, os.O_RDONLY | os.O_NONBLOCK) try: ioctl(fd, CDROMEJECT, 0) finally: os.close(fd) def list_optical_devices() -> list: """Alle optischen Laufwerke, die der Container sieht (devices: in compose).""" return sorted(glob.glob("/dev/sr[0-9]*")) def read_sys_attr(device_name: str, attr: str) -> str: pfad = f"/sys/class/block/{device_name}/device/{attr}" try: with open(pfad, encoding="ascii", errors="replace") as f: return f.read().strip() except OSError: return "" def device_info(device_path: str) -> dict: """Baut den Geräte-Eintrag fürs UI: Name aus /sys, Disc-Status per ioctl.""" name = os.path.basename(device_path) vendor = read_sys_attr(name, "vendor") model = read_sys_attr(name, "model") try: status_code = drive_status(device_path) except OSError: status_code = -1 disc_type = "unknown" status = "empty" if status_code == CDS_DISC_OK: status = "ready" try: disc_type = classify(disc_status(device_path), disc_size_bytes(device_path)) except OSError: disc_type = "unknown" return { "id": name, "name": " ".join(teil for teil in (vendor, model) if teil) or f"Laufwerk {name}", "type": disc_type, "path": device_path, "status": status, "model": model, "serial": read_sys_attr(name, "wwid"), }