From d946cf27fe7beaa7d4af9b47fb2b0b5a3739db5b Mon Sep 17 00:00:00 2001 From: Carter Li Date: Wed, 28 Aug 2024 10:55:04 +0800 Subject: [PATCH] Zpool: add new module --- CMakeLists.txt | 7 + src/common/modules.c | 1 + src/detection/zpool/libzfs_simplified.h | 140 +++++++++++++++ src/detection/zpool/zpool.h | 16 ++ src/detection/zpool/zpool_linux.c | 72 ++++++++ src/detection/zpool/zpool_nosupport.c | 6 + src/modules/modules.h | 1 + src/modules/options.h | 1 + src/modules/zpool/option.h | 14 ++ src/modules/zpool/zpool.c | 217 ++++++++++++++++++++++++ src/modules/zpool/zpool.h | 9 + src/options/modules.c | 2 + src/options/modules.h | 1 + 13 files changed, 487 insertions(+) create mode 100644 src/detection/zpool/libzfs_simplified.h create mode 100644 src/detection/zpool/zpool.h create mode 100644 src/detection/zpool/zpool_linux.c create mode 100644 src/detection/zpool/zpool_nosupport.c create mode 100644 src/modules/zpool/option.h create mode 100644 src/modules/zpool/zpool.c create mode 100644 src/modules/zpool/zpool.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1abe943d2..beae9f379 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -392,6 +392,7 @@ set(LIBFASTFETCH_SRC src/modules/wifi/wifi.c src/modules/wm/wm.c src/modules/wmtheme/wmtheme.c + src/modules/zpool/zpool.c src/options/display.c src/options/modules.c src/options/logo.c @@ -481,6 +482,7 @@ if(LINUX) src/detection/de/de_linux.c src/detection/wmtheme/wmtheme_linux.c src/detection/camera/camera_linux.c + src/detection/zpool/zpool_linux.c src/util/platform/FFPlatform_unix.c src/util/binary_linux.c ) @@ -543,6 +545,7 @@ elseif(ANDROID) src/detection/de/de_nosupport.c src/detection/wmtheme/wmtheme_nosupport.c src/detection/camera/camera_android.c + src/detection/zpool/zpool_nosupport.c src/util/platform/FFPlatform_unix.c src/util/binary_linux.c ) @@ -622,6 +625,7 @@ elseif(FreeBSD) src/detection/de/de_linux.c src/detection/wmtheme/wmtheme_linux.c src/detection/camera/camera_linux.c + src/detection/zpool/zpool_linux.c src/util/platform/FFPlatform_unix.c src/util/binary_linux.c ) @@ -686,6 +690,7 @@ elseif(APPLE) src/detection/de/de_nosupport.c src/detection/wmtheme/wmtheme_apple.m src/detection/camera/camera_apple.m + src/detection/zpool/zpool_nosupport.c src/util/apple/cf_helpers.c src/util/apple/osascript.m src/util/platform/FFPlatform_unix.c @@ -750,6 +755,7 @@ elseif(WIN32) src/detection/de/de_nosupport.c src/detection/wmtheme/wmtheme_windows.c src/detection/camera/camera_windows.cpp + src/detection/zpool/zpool_nosupport.c src/util/windows/getline.c src/util/windows/com.cpp src/util/windows/registry.c @@ -832,6 +838,7 @@ elseif(SunOS) src/detection/de/de_linux.c src/detection/wmtheme/wmtheme_linux.c src/detection/camera/camera_nosupport.c + src/detection/zpool/zpool_linux.c src/util/platform/FFPlatform_unix.c src/util/binary_linux.c ) diff --git a/src/common/modules.c b/src/common/modules.c index 3cd158984..28f270165 100644 --- a/src/common/modules.c +++ b/src/common/modules.c @@ -169,6 +169,7 @@ static FFModuleBaseInfo* Y[] = { }; static FFModuleBaseInfo* Z[] = { + (void*) &instance.config.modules.zpool, NULL, }; diff --git a/src/detection/zpool/libzfs_simplified.h b/src/detection/zpool/libzfs_simplified.h new file mode 100644 index 000000000..57dfea2f6 --- /dev/null +++ b/src/detection/zpool/libzfs_simplified.h @@ -0,0 +1,140 @@ +#pragma once + +#include "fastfetch.h" + +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; + +typedef enum zpool_errata { + ZPOOL_ERRATA_NONE, + ZPOOL_ERRATA_ZOL_2094_SCRUB, + ZPOOL_ERRATA_ZOL_2094_ASYNC_DESTROY, + ZPOOL_ERRATA_ZOL_6845_ENCRYPTION, + ZPOOL_ERRATA_ZOL_8308_ENCRYPTION, +} zpool_errata_t; + +typedef enum { + /* + * The following correspond to faults as defined in the (fault.fs.zfs.*) + * event namespace. Each is associated with a corresponding message ID. + * This must be kept in sync with the zfs_msgid_table in + * lib/libzfs/libzfs_status.c. + */ + ZPOOL_STATUS_CORRUPT_CACHE, /* corrupt /kernel/drv/zpool.cache */ + ZPOOL_STATUS_MISSING_DEV_R, /* missing device with replicas */ + ZPOOL_STATUS_MISSING_DEV_NR, /* missing device with no replicas */ + ZPOOL_STATUS_CORRUPT_LABEL_R, /* bad device label with replicas */ + ZPOOL_STATUS_CORRUPT_LABEL_NR, /* bad device label with no replicas */ + ZPOOL_STATUS_BAD_GUID_SUM, /* sum of device guids didn't match */ + ZPOOL_STATUS_CORRUPT_POOL, /* pool metadata is corrupted */ + ZPOOL_STATUS_CORRUPT_DATA, /* data errors in user (meta)data */ + ZPOOL_STATUS_FAILING_DEV, /* device experiencing errors */ + ZPOOL_STATUS_VERSION_NEWER, /* newer on-disk version */ + ZPOOL_STATUS_HOSTID_MISMATCH, /* last accessed by another system */ + ZPOOL_STATUS_HOSTID_ACTIVE, /* currently active on another system */ + ZPOOL_STATUS_HOSTID_REQUIRED, /* multihost=on and hostid=0 */ + ZPOOL_STATUS_IO_FAILURE_WAIT, /* failed I/O, failmode 'wait' */ + ZPOOL_STATUS_IO_FAILURE_CONTINUE, /* failed I/O, failmode 'continue' */ + ZPOOL_STATUS_IO_FAILURE_MMP, /* failed MMP, failmode not 'panic' */ + ZPOOL_STATUS_BAD_LOG, /* cannot read log chain(s) */ + ZPOOL_STATUS_ERRATA, /* informational errata available */ + + /* + * If the pool has unsupported features but can still be opened in + * read-only mode, its status is ZPOOL_STATUS_UNSUP_FEAT_WRITE. If the + * pool has unsupported features but cannot be opened at all, its + * status is ZPOOL_STATUS_UNSUP_FEAT_READ. + */ + ZPOOL_STATUS_UNSUP_FEAT_READ, /* unsupported features for read */ + ZPOOL_STATUS_UNSUP_FEAT_WRITE, /* unsupported features for write */ + + /* + * These faults have no corresponding message ID. At the time we are + * checking the status, the original reason for the FMA fault (I/O or + * checksum errors) has been lost. + */ + ZPOOL_STATUS_FAULTED_DEV_R, /* faulted device with replicas */ + ZPOOL_STATUS_FAULTED_DEV_NR, /* faulted device with no replicas */ + + /* + * The following are not faults per se, but still an error possibly + * requiring administrative attention. There is no corresponding + * message ID. + */ + ZPOOL_STATUS_VERSION_OLDER, /* older legacy on-disk version */ + ZPOOL_STATUS_FEAT_DISABLED, /* supported features are disabled */ + ZPOOL_STATUS_RESILVERING, /* device being resilvered */ + ZPOOL_STATUS_OFFLINE_DEV, /* device offline */ + ZPOOL_STATUS_REMOVED_DEV, /* removed device */ + ZPOOL_STATUS_REBUILDING, /* device being rebuilt */ + ZPOOL_STATUS_REBUILD_SCRUB, /* recommend scrubbing the pool */ + ZPOOL_STATUS_NON_NATIVE_ASHIFT, /* (e.g. 512e dev with ashift of 9) */ + ZPOOL_STATUS_COMPATIBILITY_ERR, /* bad 'compatibility' property */ + ZPOOL_STATUS_INCOMPATIBLE_FEAT, /* feature set outside compatibility */ + + /* + * Finally, the following indicates a healthy pool. + */ + ZPOOL_STATUS_OK +} zpool_status_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 uint64_t zpool_get_prop_int(zpool_handle_t *, zpool_prop_t, zprop_source_t *); +extern const char *zpool_get_name(zpool_handle_t *); +extern const char *zpool_get_state_str(zpool_handle_t *); +zpool_status_t zpool_get_status(zpool_handle_t *, const char **, zpool_errata_t *); diff --git a/src/detection/zpool/zpool.h b/src/detection/zpool/zpool.h new file mode 100644 index 000000000..3b4bc5ef2 --- /dev/null +++ b/src/detection/zpool/zpool.h @@ -0,0 +1,16 @@ +#pragma once + +#include "fastfetch.h" + +typedef struct FFZpoolResult +{ + FFstrbuf name; + FFstrbuf state; + FFstrbuf status; + uint64_t used; + uint64_t total; + uint64_t version; + uint64_t fragmentation; +} FFZpoolResult; + +const char* ffDetectZpool(FFlist* result /* list of FFZpoolResult */); diff --git a/src/detection/zpool/zpool_linux.c b/src/detection/zpool/zpool_linux.c new file mode 100644 index 000000000..6df9b2ce0 --- /dev/null +++ b/src/detection/zpool/zpool_linux.c @@ -0,0 +1,72 @@ +#include "zpool.h" +#include "common/library.h" +#include "libzfs_simplified.h" + +typedef struct FFZfsData +{ + FF_LIBRARY_SYMBOL(libzfs_fini) + FF_LIBRARY_SYMBOL(zpool_iter) + FF_LIBRARY_SYMBOL(zpool_get_prop_int) + FF_LIBRARY_SYMBOL(zpool_get_name) + FF_LIBRARY_SYMBOL(zpool_get_state_str) + FF_LIBRARY_SYMBOL(zpool_get_status) + + libzfs_handle_t* handle; + FFlist* result; +} FFZfsData; + +static inline void cleanLibzfs(FFZfsData* data) +{ + if (data->fflibzfs_fini && data->handle) + { + data->fflibzfs_fini(data->handle); + data->handle = NULL; + } +} + +static int enumZpoolCallback(zpool_handle_t* zpool, void* param) +{ + FFZfsData* data = (FFZfsData*) param; + zprop_source_t source; + FFZpoolResult* item = ffListAdd(data->result); + ffStrbufInitS(&item->name, data->ffzpool_get_name(zpool)); + ffStrbufInitS(&item->state, data->ffzpool_get_state_str(zpool)); + const char* msgid = NULL; + zpool_status_t status = data->ffzpool_get_status(zpool, &msgid, NULL); + if (msgid && *msgid) + ffStrbufInitS(&item->status, msgid); + else + ffStrbufInitStatic(&item->status, status == ZPOOL_STATUS_OK ? "OK" : "NOT OK"); + + item->version = data->ffzpool_get_prop_int(zpool, ZPOOL_PROP_VERSION, &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->fragmentation = data->ffzpool_get_prop_int(zpool, ZPOOL_PROP_FRAGMENTATION, &source); + return 0; +} + +const char* ffDetectZpool(FFlist* result /* list of FFZpoolResult */) +{ + FF_LIBRARY_LOAD(libzfs, NULL, "dlopen libzfs" FF_LIBRARY_EXTENSION " failed", "libzfs" FF_LIBRARY_EXTENSION, 4); + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libzfs, libzfs_init); + + libzfs_handle_t* handle = fflibzfs_init(); + if (!handle) return "libzfs_init() failed"; + + __attribute__((__cleanup__(cleanLibzfs))) FFZfsData data = { + .handle = handle, + .result = result, + }; + + 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); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libzfs, data, zpool_get_name); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libzfs, data, zpool_get_state_str); + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libzfs, data, zpool_get_status); + + if (ffzpool_iter(handle, enumZpoolCallback, &data) < 0) + return "zpool_iter() failed"; + + return NULL; +} diff --git a/src/detection/zpool/zpool_nosupport.c b/src/detection/zpool/zpool_nosupport.c new file mode 100644 index 000000000..f7b71a7db --- /dev/null +++ b/src/detection/zpool/zpool_nosupport.c @@ -0,0 +1,6 @@ +#include "zpool.h" + +const char* ffDetectZpool(FF_MAYBE_UNUSED FFlist* result /* list of FFZpoolResult */) +{ + return "Not supported on this platform"; +} diff --git a/src/modules/modules.h b/src/modules/modules.h index dbfebcf31..d6e6f5c14 100644 --- a/src/modules/modules.h +++ b/src/modules/modules.h @@ -70,3 +70,4 @@ #include "modules/wifi/wifi.h" #include "modules/wm/wm.h" #include "modules/wmtheme/wmtheme.h" +#include "modules/zpool/zpool.h" diff --git a/src/modules/options.h b/src/modules/options.h index c705c7500..74ad4c0b4 100644 --- a/src/modules/options.h +++ b/src/modules/options.h @@ -70,3 +70,4 @@ #include "modules/wifi/option.h" #include "modules/wm/option.h" #include "modules/wmtheme/option.h" +#include "modules/zpool/option.h" diff --git a/src/modules/zpool/option.h b/src/modules/zpool/option.h new file mode 100644 index 000000000..3143cf91b --- /dev/null +++ b/src/modules/zpool/option.h @@ -0,0 +1,14 @@ +#pragma once + +// This file will be included in "fastfetch.h", do NOT put unnecessary things here + +#include "common/option.h" +#include "common/percent.h" + +typedef struct FFZpoolOptions +{ + FFModuleBaseInfo moduleInfo; + FFModuleArgs moduleArgs; + + FFColorRangeConfig percent; +} FFZpoolOptions; diff --git a/src/modules/zpool/zpool.c b/src/modules/zpool/zpool.c new file mode 100644 index 000000000..0b3772d0c --- /dev/null +++ b/src/modules/zpool/zpool.c @@ -0,0 +1,217 @@ +#include "common/printing.h" +#include "common/jsonconfig.h" +#include "common/percent.h" +#include "detection/zpool/zpool.h" +#include "modules/zpool/zpool.h" +#include "util/stringUtils.h" + +#define FF_ZPOOL_NUM_FORMAT_ARGS 9 + +static void printZpool(FFZpoolOptions* options, FFZpoolResult* result, uint8_t index) +{ + FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); + if (options->moduleArgs.key.length == 0) + { + if (result->name.length > 0) + ffStrbufSetF(&buffer, "%s (%s)", FF_ZPOOL_MODULE_NAME, result->name.chars); + else + ffStrbufSetS(&buffer, FF_ZPOOL_MODULE_NAME); + } + else + { + ffStrbufClear(&buffer); + FF_PARSE_FORMAT_STRING_CHECKED(&buffer, &options->moduleArgs.key, 2, ((FFformatarg[]){ + {FF_FORMAT_ARG_TYPE_UINT8, &index, "index"}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->name, "name"}, + })); + } + + FF_STRBUF_AUTO_DESTROY usedPretty = ffStrbufCreate(); + ffParseSize(result->used, &usedPretty); + + FF_STRBUF_AUTO_DESTROY totalPretty = ffStrbufCreate(); + ffParseSize(result->total, &totalPretty); + + double bytesPercentage = result->total > 0 ? (double) result->used / (double) result->total * 100.0 : 0; + double fragPercentage = (double) result->fragmentation; + + if(options->moduleArgs.outputFormat.length == 0) + { + ffPrintLogoAndKey(buffer.chars, index, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY); + + ffStrbufClear(&buffer); + ffStrbufSetF(&buffer, "%s / %s (", usedPretty.chars, totalPretty.chars); + ffPercentAppendNum(&buffer, bytesPercentage, options->percent, false, &options->moduleArgs); + ffStrbufAppendS(&buffer, ", "); + ffPercentAppendNum(&buffer, fragPercentage, options->percent, false, &options->moduleArgs); + ffStrbufAppendF(&buffer, " frag) - %s", result->status.chars); + ffStrbufPutTo(&buffer, stdout); + } + else + { + FF_STRBUF_AUTO_DESTROY bytesPercentageNum = ffStrbufCreate(); + ffPercentAppendNum(&bytesPercentageNum, bytesPercentage, options->percent, false, &options->moduleArgs); + FF_STRBUF_AUTO_DESTROY bytesPercentageBar = ffStrbufCreate(); + ffPercentAppendBar(&bytesPercentageBar, bytesPercentage, options->percent, &options->moduleArgs); + + FF_STRBUF_AUTO_DESTROY fragPercentageNum = ffStrbufCreate(); + ffPercentAppendNum(&fragPercentageNum, fragPercentage, options->percent, false, &options->moduleArgs); + FF_STRBUF_AUTO_DESTROY fragPercentageBar = ffStrbufCreate(); + ffPercentAppendBar(&fragPercentageBar, fragPercentage, options->percent, &options->moduleArgs); + + FF_PRINT_FORMAT_CHECKED(buffer.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, FF_ZPOOL_NUM_FORMAT_ARGS, ((FFformatarg[]) { + {FF_FORMAT_ARG_TYPE_STRBUF, &result->name, "name"}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->state, "state"}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->status, "status"}, + {FF_FORMAT_ARG_TYPE_STRBUF, &usedPretty, "size-used"}, + {FF_FORMAT_ARG_TYPE_STRBUF, &totalPretty, "size-total"}, + {FF_FORMAT_ARG_TYPE_STRBUF, &bytesPercentageNum, "size-percentage"}, + {FF_FORMAT_ARG_TYPE_STRBUF, &fragPercentage, "frag-percentage"}, + {FF_FORMAT_ARG_TYPE_STRBUF, &bytesPercentageBar, "size-percentage-bar"}, + {FF_FORMAT_ARG_TYPE_STRBUF, &fragPercentageBar, "frag-percentage-bar"}, + })); + } +} + +void ffPrintZpool(FFZpoolOptions* options) +{ + FF_LIST_AUTO_DESTROY results = ffListCreate(sizeof(FFZpoolResult)); + + const char* error = ffDetectZpool(&results); + + if (error) + { + ffPrintError(FF_ZPOOL_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error); + return; + } + if(results.length == 0) + { + ffPrintError(FF_ZPOOL_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", "No zpool found"); + return; + } + + for(uint32_t i = 0; i < results.length; i++) + { + FFZpoolResult* result = FF_LIST_GET(FFZpoolResult, results, i); + uint8_t index = results.length == 1 ? 0 : (uint8_t) (i + 1); + printZpool(options, result, index); + } + + FF_LIST_FOR_EACH(FFZpoolResult, result, results) + { + ffStrbufDestroy(&result->name); + ffStrbufDestroy(&result->state); + } +} + +bool ffParseZpoolCommandOptions(FFZpoolOptions* options, const char* key, const char* value) +{ + const char* subKey = ffOptionTestPrefix(key, FF_ZPOOL_MODULE_NAME); + if (!subKey) return false; + if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs)) + return true; + + if (ffPercentParseCommandOptions(key, subKey, value, &options->percent)) + return true; + + return false; +} + +void ffParseZpoolJsonObject(FFZpoolOptions* options, yyjson_val* module) +{ + yyjson_val *key_, *val; + size_t idx, max; + yyjson_obj_foreach(module, idx, max, key_, val) + { + const char* key = yyjson_get_str(key_); + if(ffStrEqualsIgnCase(key, "type")) + continue; + + if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) + continue; + + if (ffPercentParseJsonObject(key, val, &options->percent)) + continue; + + ffPrintError(FF_ZPOOL_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", key); + } +} + +void ffGenerateZpoolJsonConfig(FFZpoolOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) +{ + __attribute__((__cleanup__(ffDestroyZpoolOptions))) FFZpoolOptions defaultOptions; + ffInitZpoolOptions(&defaultOptions); + + ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs); + + ffPercentGenerateJsonConfig(doc, module, defaultOptions.percent, options->percent); +} + +void ffGenerateZpoolJsonResult(FF_MAYBE_UNUSED FFZpoolOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) +{ + FF_LIST_AUTO_DESTROY results = ffListCreate(sizeof(FFZpoolResult)); + + const char* error = ffDetectZpool(&results); + if (error) + { + yyjson_mut_obj_add_str(doc, module, "error", error); + return; + } + + yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result"); + + FF_LIST_FOR_EACH(FFZpoolResult, zpool, results) + { + yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr); + yyjson_mut_obj_add_strbuf(doc, obj, "name", &zpool->name); + yyjson_mut_obj_add_strbuf(doc, obj, "state", &zpool->state); + yyjson_mut_obj_add_strbuf(doc, obj, "status", &zpool->status); + yyjson_mut_obj_add_uint(doc, obj, "used", zpool->used); + yyjson_mut_obj_add_uint(doc, obj, "total", zpool->total); + yyjson_mut_obj_add_uint(doc, obj, "version", zpool->version); + yyjson_mut_obj_add_uint(doc, obj, "fragmentation", zpool->fragmentation); + } + + FF_LIST_FOR_EACH(FFZpoolResult, battery, results) + { + ffStrbufDestroy(&battery->name); + ffStrbufDestroy(&battery->state); + } +} + +void ffPrintZpoolHelpFormat(void) +{ + FF_PRINT_MODULE_FORMAT_HELP_CHECKED(FF_ZPOOL_MODULE_NAME, "{3} / {4} ({5}, {6} frag)", FF_ZPOOL_NUM_FORMAT_ARGS, ((const char* []) { + "Zpool name - name", + "Zpool state - state", + "Zpool health status - status", + "Size used - size-used", + "Size total - size-total", + "Size percentage num - size-percentage", + "Fragmentation percentage num - frag-percentage", + "Size percentage bar - size-percentage-bar", + "Fragmentation percentage bar - frag-percentage-bar", + })); +} + +void ffInitZpoolOptions(FFZpoolOptions* options) +{ + ffOptionInitModuleBaseInfo( + &options->moduleInfo, + FF_ZPOOL_MODULE_NAME, + "Print zfs pools", + ffParseZpoolCommandOptions, + ffParseZpoolJsonObject, + ffPrintZpool, + ffGenerateZpoolJsonResult, + ffPrintZpoolHelpFormat, + ffGenerateZpoolJsonConfig + ); + ffOptionInitModuleArg(&options->moduleArgs, "󱑛"); + options->percent = (FFColorRangeConfig) { 50, 80 }; +} + +void ffDestroyZpoolOptions(FFZpoolOptions* options) +{ + ffOptionDestroyModuleArg(&options->moduleArgs); +} diff --git a/src/modules/zpool/zpool.h b/src/modules/zpool/zpool.h new file mode 100644 index 000000000..03623e063 --- /dev/null +++ b/src/modules/zpool/zpool.h @@ -0,0 +1,9 @@ +#pragma once + +#include "fastfetch.h" + +#define FF_ZPOOL_MODULE_NAME "Zpool" + +void ffPrintZpool(FFZpoolOptions* options); +void ffInitZpoolOptions(FFZpoolOptions* options); +void ffDestroyZpoolOptions(FFZpoolOptions* options); diff --git a/src/options/modules.c b/src/options/modules.c index 0bc117e3e..22c6fcf5b 100644 --- a/src/options/modules.c +++ b/src/options/modules.c @@ -71,6 +71,7 @@ void ffOptionsInitModules(FFOptionsModules* options) ffInitWallpaperOptions(&options->wallpaper); ffInitWeatherOptions(&options->weather); ffInitWifiOptions(&options->wifi); + ffInitZpoolOptions(&options->zpool); } void ffOptionsDestroyModules(FFOptionsModules* options) @@ -143,4 +144,5 @@ void ffOptionsDestroyModules(FFOptionsModules* options) ffDestroyWallpaperOptions(&options->wallpaper); ffDestroyWeatherOptions(&options->weather); ffDestroyWifiOptions(&options->wifi); + ffDestroyZpoolOptions(&options->zpool); } diff --git a/src/options/modules.h b/src/options/modules.h index 1768c8c18..27ec92dc4 100644 --- a/src/options/modules.h +++ b/src/options/modules.h @@ -72,6 +72,7 @@ typedef struct FFOptionsModules FFWallpaperOptions wallpaper; FFWeatherOptions weather; FFWifiOptions wifi; + FFZpoolOptions zpool; } FFOptionsModules; void ffOptionsInitModules(FFOptionsModules* options);