Last active
August 23, 2022 06:54
-
-
Save JonathonReinhart/b89f4f93bd16fcbf9f833fdcb65955b2 to your computer and use it in GitHub Desktop.
Linux NBD (Network Block Device) info
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# Show Linux NBD (Network Block Device) info | |
# Requires Python 3.7+ | |
# Author: Jonathon Reinhart | |
# License: MIT | |
from dataclasses import dataclass | |
from pathlib import Path | |
class NotConnected(Exception): | |
pass | |
def read_int_file(p, base=10): | |
return int(p.read_text(), base=base) | |
def human_size(s): | |
prefixes = ("", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei") | |
for pref in prefixes: | |
if s < 1024: | |
return f"{s} {pref}B" | |
s /= 1024 | |
return f"{s} {pref}B" | |
def pid_comm(pid): | |
p = Path(f'/proc/{pid}/comm') | |
return p.read_text().strip() | |
def get_nbd_params(): | |
paramdir = Path('/sys/module/nbd/parameters/') | |
results = {} | |
for name in ('nbds_max', 'max_part'): | |
results[name] = read_int_file(paramdir / name) | |
return results | |
def get_qemu_nbd_image(pid): | |
p = Path(f'/proc/{pid}/fd') | |
files = [fd for fd in p.iterdir() if fd.is_file()] | |
if len(files) == 1: | |
# NOTE: We assume that qemu-nbd only has one normal file open | |
return files[0].readlink() | |
raise Exception("forky says I dunno") | |
@dataclass | |
class NbdInfo: | |
pid: int | |
size: int | |
ro: bool | |
def infostr(self): | |
procdesc = self.get_procname() | |
try: | |
procdesc += " " + str(self.get_srcfile()) | |
except (PermissionError, NotImplementedError): | |
pass | |
s = f"PID {self.pid} ({procdesc}), {human_size(self.size)}, " | |
s += "read-only" if self.ro else "read/write" | |
return s | |
def get_procname(self): | |
return pid_comm(self.pid) | |
def get_srcfile(self): | |
if self.get_procname() == "qemu-nbd": | |
return get_qemu_nbd_image(self.pid) | |
raise NotImplementedError(f"Don't know how to get srcfile for {self.get_procname()}") | |
def get_nbd_info(name): | |
p = Path('/sys/class/block') / name | |
try: | |
pid = read_int_file(p / "pid") | |
except FileNotFoundError: | |
raise NotConnected | |
return NbdInfo( | |
pid = pid, | |
size = read_int_file(p / "size"), | |
ro = bool(read_int_file(p / "ro")), | |
) | |
def main(): | |
params = get_nbd_params() | |
for i in range(params['nbds_max']): | |
name = f'nbd{i}' | |
try: | |
info = get_nbd_info(name) | |
except NotConnected: | |
print(f"{name}: (not connected)") | |
continue | |
print(f"{name}: {info.infostr()}") | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Install into
/usr/local/bin/nbdinfo
.Example output: