Dateisystem-Typ direkt ermitteln statt aus der udev-Datenbank

Auf dem Testhost (Ceph RBD) meldete lsblk fuer jede Partition eines
eingebundenen Snapshots "kein Dateisystem" - auch fuer eine 31,5-GB-
Partition, auf der offensichtlich ext4 liegt. Nichts liess sich einhaengen.

Grund: lsblk nimmt FSTYPE aus der udev-Datenbank, und die ist bei frisch
gemappten rbd-Geraeten leer, weil udev dort keine blkid-Probe faehrt. Ein
direktes "blkid -p" auf denselben Geraeten liefert dagegen sauber vfat und
ext4. Der Typ wird jetzt so ermittelt, wenn lsblk nichts weiss.

Ausserdem: die Auswahl der Dateisysteme zeigte nur abgeschnittene
Mountpfade, die sich alle glichen, und vorausgewaehlt war das erste
gefundene - in der Praxis gern die 200-MB-EFI-Partition. Jetzt stehen dort
Geraet, Typ, Groesse und ein Hinweis ("Linux-Wurzelverzeichnis",
"Startpartition"), und die wahrscheinlichste Wurzel steht oben.

Auf pvetest01 gegen echte Snapshots geprueft: einbinden, alle drei
Dateisysteme mounten, Explorer, Web-Oberflaeche mit Download und ZIP,
Ausbruchversuch abgewiesen, restloses Aufraeumen auch nach hartem Abbruch.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
duffyduck
2026-07-31 09:44:56 +02:00
co-authored by Claude Opus 5
parent da08a81aab
commit 700492391a
3 changed files with 87 additions and 11 deletions
+6 -9
View File
@@ -649,9 +649,7 @@ class Explorer:
if not self.session or len(self.session.mounts) < 2:
message(win, "Es ist nur ein Dateisystem eingebunden.")
return
entries = []
for device, mountpoint in sorted(self.session.mounts.items()):
entries.append((mountpoint, "%s -> %s" % (device, mountpoint)))
entries = self.session.mount_entries()
chosen = choose(win, "Welches Dateisystem?", entries)
if chosen:
self.panes[0].root = chosen
@@ -857,16 +855,15 @@ def _main(stdscr, args):
try:
_show_notes(stdscr, session.notes)
mountpoints = sorted(set(session.mounts.values()))
if not mountpoints:
entries = session.mount_entries()
if not entries:
_show_notes(stdscr,
["Es wurde kein Dateisystem eingehaengt."] + session.notes,
"Nichts zu zeigen")
return 3
start = mountpoints[0]
if len(mountpoints) > 1:
entries = [(m, m) for m in mountpoints]
start = choose(stdscr, "Welches Dateisystem zuerst?", entries) or mountpoints[0]
start = entries[0][0]
if len(entries) > 1:
start = choose(stdscr, "Welches Dateisystem zuerst?", entries) or start
left = Pane(path=start, root=start, readonly=True,
title="%s @ %s" % (guest.label, name))
+79
View File
@@ -505,6 +505,22 @@ class Session:
break
return devices
@staticmethod
def _probe(path):
"""Dateisystem eines Geraets direkt ermitteln: (Typ, Bezeichnung).
Noetig, weil `lsblk` den Typ aus der udev-Datenbank nimmt - und die
ist bei frisch eingebundenen rbd-Geraeten leer. lsblk meldet dann
ueberall "kein Dateisystem", obwohl ext4 und vfat da sind.
`blkid -p` umgeht Datenbank und Zwischenspeicher und schaut nach.
"""
output = run(["blkid", "-p", "-o", "export", path], check=False, timeout=30)
values = {}
for line in output.splitlines():
key, _, value = line.partition("=")
values[key.strip()] = value.strip()
return values.get("TYPE", ""), values.get("LABEL", "")
def _lsblk(self, device_path, volume):
try:
output = run(["lsblk", "-J", "-b", "-o",
@@ -527,6 +543,9 @@ class Session:
volume=volume,
)
children = entry.get("children") or []
if device.path and not device.fstype and not children:
device.fstype, probed_label = self._probe(device.path)
device.label = device.label or probed_label
if device.path:
# Eine Platte mit Partitionen selbst nicht anbieten
if not (children and not device.fstype):
@@ -633,6 +652,66 @@ class Session:
last = exc
raise SnapfsError("%s nicht einhaengbar: %s" % (device.path, last))
# -- Uebersicht fuer die Oberflaechen ---------------------------------
def mount_entries(self):
"""[(Mountpunkt, Beschriftung)] - wahrscheinlichste Wurzel zuerst.
Sonst landet man beim Oeffnen leicht auf der 500-MB-EFI-Partition
statt im eigentlichen System.
"""
by_mount = {}
for device in self.devices:
mountpoint = self.mounts.get(device.path)
if mountpoint:
by_mount[mountpoint] = device
for mountpoint in self.mounts.values():
by_mount.setdefault(mountpoint, None)
scored = [(self._score(mountpoint, device), mountpoint, device)
for mountpoint, device in by_mount.items()]
scored.sort(key=lambda item: -item[0])
return [(mountpoint, self._describe_mount(mountpoint, device))
for _score, mountpoint, device in scored]
@staticmethod
def _score(mountpoint, device):
try:
names = set(os.listdir(mountpoint))
except OSError:
names = set()
score = 0
if {"etc", "usr"} <= names:
score += 1000 # Linux-Wurzel
elif "etc" in names or "Windows" in names:
score += 500
elif {"EFI"} & names:
score -= 200 # reine Startpartition
score += int((device.size if device else 0) / (1024 ** 3))
return score
@staticmethod
def _describe_mount(mountpoint, device):
try:
names = set(os.listdir(mountpoint))
except OSError:
names = set()
if {"etc", "usr"} <= names:
hint = "Linux-Wurzelverzeichnis"
elif "Windows" in names:
hint = "Windows"
elif "EFI" in names or "bootmgr" in names:
hint = "Startpartition"
elif "vmlinuz" in names or "grub" in names:
hint = "Boot"
else:
hint = ", ".join(sorted(names)[:3]) or "leer"
if device is None:
return "%s (%s)" % (os.path.basename(mountpoint), hint)
return "%-12s %-6s %8s %s%s" % (
os.path.basename(device.path), device.fstype or "?",
device.human_size, ('"%s" ' % device.label) if device.label else "", hint)
# -- aufraeumen -------------------------------------------------------
def _remember(self, kind, value):
+2 -2
View File
@@ -84,8 +84,8 @@ class AppState:
self.guest = guest
self.snapname = snapname
self.notes = list(session.notes)
self.roots = [(mountpoint, mountpoint)
for mountpoint in sorted(set(session.mounts.values()))]
self.roots = [(label, mountpoint)
for mountpoint, label in session.mount_entries()]
def close_locked(self):
if self.session: