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:
co-authored by
Claude Opus 5
parent
da08a81aab
commit
700492391a
+6
-9
@@ -649,9 +649,7 @@ class Explorer:
|
|||||||
if not self.session or len(self.session.mounts) < 2:
|
if not self.session or len(self.session.mounts) < 2:
|
||||||
message(win, "Es ist nur ein Dateisystem eingebunden.")
|
message(win, "Es ist nur ein Dateisystem eingebunden.")
|
||||||
return
|
return
|
||||||
entries = []
|
entries = self.session.mount_entries()
|
||||||
for device, mountpoint in sorted(self.session.mounts.items()):
|
|
||||||
entries.append((mountpoint, "%s -> %s" % (device, mountpoint)))
|
|
||||||
chosen = choose(win, "Welches Dateisystem?", entries)
|
chosen = choose(win, "Welches Dateisystem?", entries)
|
||||||
if chosen:
|
if chosen:
|
||||||
self.panes[0].root = chosen
|
self.panes[0].root = chosen
|
||||||
@@ -857,16 +855,15 @@ def _main(stdscr, args):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
_show_notes(stdscr, session.notes)
|
_show_notes(stdscr, session.notes)
|
||||||
mountpoints = sorted(set(session.mounts.values()))
|
entries = session.mount_entries()
|
||||||
if not mountpoints:
|
if not entries:
|
||||||
_show_notes(stdscr,
|
_show_notes(stdscr,
|
||||||
["Es wurde kein Dateisystem eingehaengt."] + session.notes,
|
["Es wurde kein Dateisystem eingehaengt."] + session.notes,
|
||||||
"Nichts zu zeigen")
|
"Nichts zu zeigen")
|
||||||
return 3
|
return 3
|
||||||
start = mountpoints[0]
|
start = entries[0][0]
|
||||||
if len(mountpoints) > 1:
|
if len(entries) > 1:
|
||||||
entries = [(m, m) for m in mountpoints]
|
start = choose(stdscr, "Welches Dateisystem zuerst?", entries) or start
|
||||||
start = choose(stdscr, "Welches Dateisystem zuerst?", entries) or mountpoints[0]
|
|
||||||
|
|
||||||
left = Pane(path=start, root=start, readonly=True,
|
left = Pane(path=start, root=start, readonly=True,
|
||||||
title="%s @ %s" % (guest.label, name))
|
title="%s @ %s" % (guest.label, name))
|
||||||
|
|||||||
@@ -505,6 +505,22 @@ class Session:
|
|||||||
break
|
break
|
||||||
return devices
|
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):
|
def _lsblk(self, device_path, volume):
|
||||||
try:
|
try:
|
||||||
output = run(["lsblk", "-J", "-b", "-o",
|
output = run(["lsblk", "-J", "-b", "-o",
|
||||||
@@ -527,6 +543,9 @@ class Session:
|
|||||||
volume=volume,
|
volume=volume,
|
||||||
)
|
)
|
||||||
children = entry.get("children") or []
|
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:
|
if device.path:
|
||||||
# Eine Platte mit Partitionen selbst nicht anbieten
|
# Eine Platte mit Partitionen selbst nicht anbieten
|
||||||
if not (children and not device.fstype):
|
if not (children and not device.fstype):
|
||||||
@@ -633,6 +652,66 @@ class Session:
|
|||||||
last = exc
|
last = exc
|
||||||
raise SnapfsError("%s nicht einhaengbar: %s" % (device.path, last))
|
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 -------------------------------------------------------
|
# -- aufraeumen -------------------------------------------------------
|
||||||
|
|
||||||
def _remember(self, kind, value):
|
def _remember(self, kind, value):
|
||||||
|
|||||||
@@ -84,8 +84,8 @@ class AppState:
|
|||||||
self.guest = guest
|
self.guest = guest
|
||||||
self.snapname = snapname
|
self.snapname = snapname
|
||||||
self.notes = list(session.notes)
|
self.notes = list(session.notes)
|
||||||
self.roots = [(mountpoint, mountpoint)
|
self.roots = [(label, mountpoint)
|
||||||
for mountpoint in sorted(set(session.mounts.values()))]
|
for mountpoint, label in session.mount_entries()]
|
||||||
|
|
||||||
def close_locked(self):
|
def close_locked(self):
|
||||||
if self.session:
|
if self.session:
|
||||||
|
|||||||
Reference in New Issue
Block a user