So far BLOCKDEV_LIST_IGNORE_VIRTUAL filtered out everything below
/sys/devices/virtual/, which includes loopback devices. Loopback devices
are frequently used as stand-ins for real disks though (in tests, and
when installing to disk images), hence it's useful to be able to control
them independently of the other virtual devices (dm, md, zram, …).
Introduce a separate BLOCKDEV_LIST_IGNORE_LOOP flag for loopback
devices, and make BLOCKDEV_LIST_IGNORE_VIRTUAL only cover the non-loop
virtual devices. The only existing user (systemd-report) is updated to
pass both flags, so that its behaviour stays unchanged.
Subscribers to block-device uevents need to apply the same filter set
blockdev_list() uses over the bulk enumeration, one device at a time.
Pull the per-device body out as blockdev_list_one(), expose
blockdev_list_get_root_devnos() so callers can compute the IGNORE_ROOT
devnos once up-front, and introduce a 4-valued return code so callers
can distinguish:
MATCH_NO - fails a static filter (subsystem, ZRAM, IGNORE_ROOT,
REQUIRE_PARTITION_SCANNING, REQUIRE_LUKS)
MATCH_YES - fully matches
MATCH_FILTERED - passes static filters but fails a dynamic one
(IGNORE_EMPTY, IGNORE_READ_ONLY) - useful to surface
as "device just became invisible" transitions when
the kernel flips size/ro at runtime
MATCH_SKIPPED - soft error during filter evaluation; callers should
treat this like MATCH_FILTERED, but the distinct code
makes the soft failure visible rather than silently
swallowed inside blockdev_list_one()
*ret is initialized on every non-negative return (BLOCK_DEVICE_NULL for
MATCH_NO / MATCH_SKIPPED, fully populated for MATCH_YES / MATCH_FILTERED),
and untouched on negative return. blockdev_list() itself collapses
everything except MATCH_YES back into "skip", so existing callers see
no behavior change.
FOREACH_ARRAY declares 'i' as the iterator but the body passed 'd' (the
array base) to block_device_done(). Since mfree() leaves the field NULL
after the first call, element 0 is freed repeatedly while elements
1..N-1 leak their node, symlinks strv, model, vendor and subsystem.
The bug predates the sanitizer-instrumented callers. PR #41776's new
systemd-storage-block daemon runs blockdev_list() under ASan/LSan in
TEST-87-AUX-UTILS-VM and exposes it (15 allocs / 804 bytes leaked per
ListVolumes request). The fix also benefits repart and blockdev_list's
internal CLEANUP_ARRAY cleanup.
Follow-up for 9f6b2745ea
There are various definitions of the root disk, let's suppress them all if
the flag is set. So far only the outermost is suppressed, which is a bit
weird, given it's "further away" from the rootfs.
Block devices with removable media (e.g. SD card readers) indicate a
missing medium with a zero size. Optionally ignore such block devices
that carry no medium currently.
This is a lot of stuff, and sometimes quite wild, let's turn this into
its own header.
All stuff color-related that just generates sequences is now in
ansi-color.h (no .c file!), and everything more complex that
probes/ineracts with terminals remains in termina-util.[ch]
Various of our tools operate on block devices, and it's not always
obvious to know which block devices are actually appropriate for use.
Hence, let's add a helper that allows to list block devices, and
supports some limited filtering.