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.
67 lines
3.3 KiB
C
67 lines
3.3 KiB
C
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||
#pragma once
|
||
|
||
#include "basic-forward.h"
|
||
#include "shared-forward.h"
|
||
|
||
typedef enum BlockDevListFlags {
|
||
BLOCKDEV_LIST_SHOW_SYMLINKS = 1 << 0, /* Pick up symlinks to block devices too */
|
||
BLOCKDEV_LIST_REQUIRE_PARTITION_SCANNING = 1 << 1, /* Only consider block devices with partition scanning */
|
||
BLOCKDEV_LIST_IGNORE_ZRAM = 1 << 2, /* Ignore ZRAM */
|
||
BLOCKDEV_LIST_REQUIRE_LUKS = 1 << 3, /* Only consider block devices with LUKS superblocks */
|
||
BLOCKDEV_LIST_IGNORE_ROOT = 1 << 4, /* Ignore the block device we are currently booted from */
|
||
BLOCKDEV_LIST_IGNORE_EMPTY = 1 << 5, /* Ignore disks of zero size (usually drives without a medium) */
|
||
BLOCKDEV_LIST_METADATA = 1 << 6, /* Fill in model, vendor, subsystem, read_only */
|
||
BLOCKDEV_LIST_IGNORE_READ_ONLY = 1 << 7, /* Ignore read-only block devices */
|
||
} BlockDevListFlags;
|
||
|
||
/* The "dynamic" filters – ones the kernel can flip at runtime via sysattrs on a live device.
|
||
* Useful for callers that want to distinguish "device is hard-filtered (never interesting)" from
|
||
* "device just transitioned in or out of the candidate set". */
|
||
#define BLOCKDEV_LIST_DYNAMIC_FILTERS_MASK \
|
||
(BLOCKDEV_LIST_IGNORE_EMPTY | BLOCKDEV_LIST_IGNORE_READ_ONLY)
|
||
|
||
typedef struct BlockDevice {
|
||
char *node;
|
||
char **symlinks;
|
||
char *model;
|
||
char *vendor;
|
||
char *subsystem;
|
||
uint64_t diskseq;
|
||
uint64_t size; /* in bytes */
|
||
int read_only;
|
||
} BlockDevice;
|
||
|
||
#define BLOCK_DEVICE_NULL (BlockDevice) { \
|
||
.diskseq = UINT64_MAX, \
|
||
.size = UINT64_MAX, \
|
||
.read_only = -1, \
|
||
}
|
||
|
||
/* Return values of blockdev_list_one(). Not its own type – returned as int. */
|
||
enum {
|
||
BLOCKDEV_LIST_MATCH_NO, /* Hard-filtered out by a static filter (subsystem, ZRAM,
|
||
* IGNORE_ROOT, REQUIRE_PARTITION_SCANNING, REQUIRE_LUKS, …). */
|
||
BLOCKDEV_LIST_MATCH_YES, /* Passes all filters. */
|
||
BLOCKDEV_LIST_MATCH_FILTERED, /* Passes the static filters; fails at least one dynamic filter
|
||
* (IGNORE_EMPTY, IGNORE_READ_ONLY). */
|
||
BLOCKDEV_LIST_MATCH_SKIPPED, /* Filter evaluation hit an unexpected error (failed sysattr
|
||
* read, missing devname, …). Callers should typically treat
|
||
* this like _FILTERED (device not currently a candidate),
|
||
* but distinguishing it makes the soft failure visible
|
||
* rather than silently swallowed inside blockdev_list_one(). */
|
||
};
|
||
|
||
void block_device_done(BlockDevice *d);
|
||
void block_device_array_free(BlockDevice *d, size_t n_devices);
|
||
|
||
int blockdev_list_get_root_devnos(BlockDevListFlags flags, dev_t *ret_root, dev_t *ret_whole_root);
|
||
int blockdev_list_one(
|
||
sd_device *dev,
|
||
BlockDevListFlags flags,
|
||
dev_t root_devno,
|
||
dev_t whole_root_devno,
|
||
BlockDevice *ret);
|
||
|
||
int blockdev_list(BlockDevListFlags flags, BlockDevice **ret_devices, size_t *ret_n_devices);
|