diff --git a/src/detection/zpool/libzfs_simplified.h b/src/detection/zpool/libzfs_simplified.h index d1984e220..7bd41cea1 100644 --- a/src/detection/zpool/libzfs_simplified.h +++ b/src/detection/zpool/libzfs_simplified.h @@ -25,65 +25,23 @@ * CDDL HEADER END */ -typedef enum { - ZPOOL_PROP_INVAL = -1, - ZPOOL_PROP_NAME, - ZPOOL_PROP_SIZE, - ZPOOL_PROP_CAPACITY, - ZPOOL_PROP_ALTROOT, - ZPOOL_PROP_HEALTH, - ZPOOL_PROP_GUID, - ZPOOL_PROP_VERSION, - ZPOOL_PROP_BOOTFS, - ZPOOL_PROP_DELEGATION, - ZPOOL_PROP_AUTOREPLACE, - ZPOOL_PROP_CACHEFILE, - ZPOOL_PROP_FAILUREMODE, - ZPOOL_PROP_LISTSNAPS, - ZPOOL_PROP_AUTOEXPAND, - ZPOOL_PROP_DEDUPDITTO, - ZPOOL_PROP_DEDUPRATIO, - ZPOOL_PROP_FREE, - ZPOOL_PROP_ALLOCATED, - ZPOOL_PROP_READONLY, - ZPOOL_PROP_ASHIFT, - ZPOOL_PROP_COMMENT, - ZPOOL_PROP_EXPANDSZ, - ZPOOL_PROP_FREEING, - ZPOOL_PROP_FRAGMENTATION, - ZPOOL_PROP_LEAKED, - ZPOOL_PROP_MAXBLOCKSIZE, - ZPOOL_PROP_TNAME, - ZPOOL_PROP_MAXDNODESIZE, - ZPOOL_PROP_MULTIHOST, - ZPOOL_PROP_CHECKPOINT, - ZPOOL_PROP_LOAD_GUID, - ZPOOL_PROP_AUTOTRIM, - ZPOOL_PROP_COMPATIBILITY, - ZPOOL_PROP_BCLONEUSED, - ZPOOL_PROP_BCLONESAVED, - ZPOOL_PROP_BCLONERATIO, - ZPOOL_NUM_PROPS -} zpool_prop_t; - -typedef enum { - ZPROP_SRC_NONE = 0x1, - ZPROP_SRC_DEFAULT = 0x2, - ZPROP_SRC_TEMPORARY = 0x4, - ZPROP_SRC_LOCAL = 0x8, - ZPROP_SRC_INHERITED = 0x10, - ZPROP_SRC_RECEIVED = 0x20 -} zprop_source_t; - +// zpool_prop_t and zprop_source_t were previously enums in upstream OpenZFS. +// However, the enum values for these types vary greatly between different platforms, +// making it unsafe to use the enum values directly. To ensure portability, +// we define them as simple int typedefs and use zpool_name_to_prop to look up +// the correct value for a property at runtime. +typedef int zpool_prop_t; +typedef int zprop_source_t; typedef bool boolean_t; typedef struct libzfs_handle libzfs_handle_t; typedef struct zpool_handle zpool_handle_t; typedef int (*zpool_iter_f)(zpool_handle_t *, void *); -extern int zpool_iter(libzfs_handle_t *, zpool_iter_f, void *); extern libzfs_handle_t *libzfs_init(void); extern void libzfs_fini(libzfs_handle_t *); +extern int zpool_iter(libzfs_handle_t *, zpool_iter_f, void *); +extern zpool_prop_t zpool_name_to_prop(const char *); // https://github.com/openzfs/zfs/blob/06c73cffabc30b61a695988ec8e290f43cb3768d/lib/libzfs/libzfs_pool.c#L300 extern uint64_t zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *srctype); extern int zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, zprop_source_t *srctype, boolean_t literal); diff --git a/src/detection/zpool/zpool_linux.c b/src/detection/zpool/zpool_linux.c index f902f7484..c74e0bb8c 100644 --- a/src/detection/zpool/zpool_linux.c +++ b/src/detection/zpool/zpool_linux.c @@ -18,6 +18,19 @@ typedef struct FFZfsData FF_LIBRARY_SYMBOL(zpool_get_prop) FF_LIBRARY_SYMBOL(zpool_close) + // The fields in this struct store property IDs returned by `zpool_name_to_prop`, + // not the property values themselves. + struct { + int name; + int health; + int guid; + int size; + int free; + int allocated; + int fragmentation; + int readonly; + } props; + libzfs_handle_t* handle; FFlist* result; } FFZfsData; @@ -37,21 +50,21 @@ static int enumZpoolCallback(zpool_handle_t* zpool, void* param) zprop_source_t source; FFZpoolResult* item = ffListAdd(data->result); char buf[1024]; - if (data->ffzpool_get_prop(zpool, ZPOOL_PROP_NAME, buf, ARRAY_SIZE(buf), &source, false) == 0) + if (data->ffzpool_get_prop(zpool, data->props.name, buf, ARRAY_SIZE(buf), &source, false) == 0) ffStrbufInitS(&item->name, buf); else ffStrbufInitStatic(&item->name, "unknown"); - if (data->ffzpool_get_prop(zpool, ZPOOL_PROP_HEALTH, buf, ARRAY_SIZE(buf), &source, false) == 0) + if (data->ffzpool_get_prop(zpool, data->props.health, buf, ARRAY_SIZE(buf), &source, false) == 0) ffStrbufInitS(&item->state, buf); else ffStrbufInitStatic(&item->state, "unknown"); - item->guid = data->ffzpool_get_prop_int(zpool, ZPOOL_PROP_GUID, &source); - item->total = data->ffzpool_get_prop_int(zpool, ZPOOL_PROP_SIZE, &source); - item->used = item->total - data->ffzpool_get_prop_int(zpool, ZPOOL_PROP_FREE, &source); - item->allocated = data->ffzpool_get_prop_int(zpool, ZPOOL_PROP_ALLOCATED, &source); - uint64_t fragmentation = data->ffzpool_get_prop_int(zpool, ZPOOL_PROP_FRAGMENTATION, &source); + item->guid = data->ffzpool_get_prop_int(zpool, data->props.guid, &source); + item->total = data->ffzpool_get_prop_int(zpool, data->props.size, &source); + item->used = item->total - data->ffzpool_get_prop_int(zpool, data->props.free, &source); + item->allocated = data->ffzpool_get_prop_int(zpool, data->props.allocated, &source); + uint64_t fragmentation = data->ffzpool_get_prop_int(zpool, data->props.fragmentation, &source); item->fragmentation = fragmentation == UINT64_MAX ? -DBL_MAX : (double) fragmentation; - item->readOnly = (bool) data->ffzpool_get_prop_int(zpool, ZPOOL_PROP_READONLY, &source); + item->readOnly = (bool) data->ffzpool_get_prop_int(zpool, data->props.readonly, &source); data->ffzpool_close(zpool); return 0; } @@ -73,6 +86,23 @@ const char* ffDetectZpool(FFlist* result /* list of FFZpoolResult */) .result = result, }; + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libzfs, zpool_name_to_prop); + + #define FF_QUERY_ZPOOL_PROP_FROM_NAME(prop_name) do { \ + data.props.prop_name = ffzpool_name_to_prop(#prop_name); \ + if (data.props.prop_name < 0) \ + return "Failed to query prop: " #prop_name; \ + } while (false) + FF_QUERY_ZPOOL_PROP_FROM_NAME(name); + FF_QUERY_ZPOOL_PROP_FROM_NAME(health); + FF_QUERY_ZPOOL_PROP_FROM_NAME(guid); + FF_QUERY_ZPOOL_PROP_FROM_NAME(size); + FF_QUERY_ZPOOL_PROP_FROM_NAME(free); + FF_QUERY_ZPOOL_PROP_FROM_NAME(allocated); + FF_QUERY_ZPOOL_PROP_FROM_NAME(fragmentation); + FF_QUERY_ZPOOL_PROP_FROM_NAME(readonly); + #undef FF_QUERY_ZPOOL_PROP_FROM_NAME + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libzfs, zpool_iter); FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libzfs, data, libzfs_fini); FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libzfs, data, zpool_get_prop_int);