master ohmu/fastfetch-openbsd / src / modules / zpool / zpool.c
ohmu  ·  2026-10-15
  1#include "common/printing.h"
  2#include "common/jsonconfig.h"
  3#include "common/percent.h"
  4#include "common/size.h"
  5#include "common/FFstrbuf.h"
  6#include "common/strutil.h"
  7#include "detection/zpool/zpool.h"
  8#include "modules/zpool/zpool.h"
  9
 10static void printZpool(FFZpoolOptions* options, FFZpoolResult* result, uint8_t index) {
 11    FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
 12    if (options->moduleArgs.key.length == 0) {
 13        if (result->name.length > 0) {
 14            ffStrbufSetF(&buffer, "%s (%s)", FF_MODULE_GET_DISPLAY_NAME(Zpool), result->name.chars);
 15        } else {
 16            ffStrbufSetS(&buffer, FF_MODULE_GET_DISPLAY_NAME(Zpool));
 17        }
 18    } else {
 19        ffStrbufClear(&buffer);
 20        FF_PARSE_FORMAT_STRING_CHECKED(&buffer, &options->moduleArgs.key, ((FFformatarg[]) {
 21                                                                              FF_ARG(index, "index"),
 22                                                                              FF_ARG(result->name, "name"),
 23                                                                              FF_ARG(result->guid, "guid"),
 24                                                                              FF_ARG(options->moduleArgs.keyIcon, "icon"),
 25                                                                              FF_ARG(FF_MODULE_GET_DISPLAY_NAME(Zpool), "module-name"),
 26                                                                          }));
 27    }
 28
 29    FF_STRBUF_AUTO_DESTROY usedPretty = ffStrbufCreate();
 30    ffSizeAppendNum(result->used, &usedPretty);
 31
 32    FF_STRBUF_AUTO_DESTROY allocatedPretty = ffStrbufCreate();
 33    ffSizeAppendNum(result->allocated, &allocatedPretty);
 34
 35    FF_STRBUF_AUTO_DESTROY totalPretty = ffStrbufCreate();
 36    ffSizeAppendNum(result->total, &totalPretty);
 37
 38    double usedPercentage = result->total > 0 ? (double) result->used / (double) result->total * 100.0 : 0;
 39    double allocatedPercentage = result->total > 0 ? (double) result->allocated / (double) result->total * 100.0 : 0;
 40    FFPercentageTypeFlags percentType = options->percent.type == 0 ? instance.config.display.percentType : options->percent.type;
 41
 42    if (options->moduleArgs.outputFormat.length == 0) {
 43        ffPrintLogoAndKey(buffer.chars, index, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY);
 44
 45        ffStrbufClear(&buffer);
 46        ffStrbufSetF(&buffer, "%s / %s (", usedPretty.chars, totalPretty.chars);
 47        ffPercentAppendNum(&buffer, usedPercentage, options->percent, false, &options->moduleArgs);
 48        ffStrbufAppendS(&buffer, ", ");
 49        ffPercentAppendNum(&buffer, allocatedPercentage, options->percent, false, &options->moduleArgs);
 50        ffStrbufAppendS(&buffer, " allocated, ");
 51        ffPercentAppendNum(&buffer, result->fragmentation, options->percent, false, &options->moduleArgs);
 52        ffStrbufAppendF(&buffer, " frag) - %s", result->state.chars);
 53        if (result->readOnly) {
 54            ffStrbufAppendS(&buffer, " [Read-only]");
 55        }
 56        ffStrbufPutTo(&buffer, stdout);
 57    } else {
 58        FF_STRBUF_AUTO_DESTROY usedPercentageNum = ffStrbufCreate();
 59        if (percentType & FF_PERCENTAGE_TYPE_NUM_BIT) {
 60            ffPercentAppendNum(&usedPercentageNum, usedPercentage, options->percent, false, &options->moduleArgs);
 61        }
 62        FF_STRBUF_AUTO_DESTROY usedPercentageBar = ffStrbufCreate();
 63        if (percentType & FF_PERCENTAGE_TYPE_BAR_BIT) {
 64            ffPercentAppendBar(&usedPercentageBar, usedPercentage, options->percent, &options->moduleArgs);
 65        }
 66
 67        FF_STRBUF_AUTO_DESTROY allocatedPercentageNum = ffStrbufCreate();
 68        if (percentType & FF_PERCENTAGE_TYPE_NUM_BIT) {
 69            ffPercentAppendNum(&allocatedPercentageNum, allocatedPercentage, options->percent, false, &options->moduleArgs);
 70        }
 71        FF_STRBUF_AUTO_DESTROY allocatedPercentageBar = ffStrbufCreate();
 72        if (percentType & FF_PERCENTAGE_TYPE_BAR_BIT) {
 73            ffPercentAppendBar(&allocatedPercentageBar, allocatedPercentage, options->percent, &options->moduleArgs);
 74        }
 75
 76        FF_STRBUF_AUTO_DESTROY fragPercentageNum = ffStrbufCreate();
 77        if (percentType & FF_PERCENTAGE_TYPE_NUM_BIT) {
 78            ffPercentAppendNum(&fragPercentageNum, result->fragmentation, options->percent, false, &options->moduleArgs);
 79        }
 80        FF_STRBUF_AUTO_DESTROY fragPercentageBar = ffStrbufCreate();
 81        if (percentType & FF_PERCENTAGE_TYPE_BAR_BIT) {
 82            ffPercentAppendBar(&fragPercentageBar, result->fragmentation, options->percent, &options->moduleArgs);
 83        }
 84
 85        FF_PRINT_FORMAT_CHECKED(buffer.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, ((FFformatarg[]) {
 86                                                                                                        FF_ARG(result->name, "name"),
 87                                                                                                        FF_ARG(result->guid, "guid"),
 88                                                                                                        FF_ARG(result->state, "state"),
 89                                                                                                        FF_ARG(usedPretty, "size-used"),
 90                                                                                                        FF_ARG(allocatedPretty, "size-allocated"),
 91                                                                                                        FF_ARG(totalPretty, "size-total"),
 92                                                                                                        FF_ARG(usedPercentageNum, "used-percentage"),
 93                                                                                                        FF_ARG(allocatedPercentageNum, "allocated-percentage"),
 94                                                                                                        FF_ARG(fragPercentageNum, "frag-percentage"),
 95                                                                                                        FF_ARG(usedPercentageBar, "used-percentage-bar"),
 96                                                                                                        FF_ARG(allocatedPercentageBar, "allocated-percentage-bar"),
 97                                                                                                        FF_ARG(fragPercentageBar, "frag-percentage-bar"),
 98                                                                                                        FF_ARG(result->readOnly, "is-readonly"),
 99                                                                                                    }));
100    }
101}
102
103bool ffPrintZpool(FFZpoolOptions* options) {
104    FF_LIST_AUTO_DESTROY results = ffListCreate();
105
106    const char* error = ffDetectZpool(&results);
107
108    if (error) {
109        ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Zpool), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
110        return false;
111    }
112    if (results.length == 0) {
113        ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Zpool), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", "No zpool found");
114        return false;
115    }
116
117    for (uint32_t i = 0; i < results.length; i++) {
118        FFZpoolResult* result = FF_LIST_GET(FFZpoolResult, results, i);
119        uint8_t index = results.length == 1 ? 0 : (uint8_t) (i + 1);
120        printZpool(options, result, index);
121    }
122
123    FF_LIST_FOR_EACH (FFZpoolResult, result, results) {
124        ffStrbufDestroy(&result->name);
125        ffStrbufDestroy(&result->state);
126    }
127    return true;
128}
129
130void ffParseZpoolJsonObject(FFZpoolOptions* options, yyjson_val* module) {
131    yyjson_val *key, *val;
132    size_t idx, max;
133    yyjson_obj_foreach (module, idx, max, key, val) {
134        if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) {
135            continue;
136        }
137
138        if (ffPercentParseJsonObject(key, val, &options->percent)) {
139            continue;
140        }
141
142        ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Zpool), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
143    }
144}
145
146[[gnu::cold]]
147void ffGenerateZpoolJsonConfig(FFZpoolOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
148    ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
149
150    ffPercentGenerateJsonConfig(doc, module, options->percent);
151}
152
153bool ffGenerateZpoolJsonResult([[maybe_unused]] FFZpoolOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
154    FF_LIST_AUTO_DESTROY results = ffListCreate();
155
156    const char* error = ffDetectZpool(&results);
157    if (error) {
158        yyjson_mut_obj_add_str(doc, module, "error", error);
159        return false;
160    }
161
162    yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result");
163
164    FF_LIST_FOR_EACH (FFZpoolResult, zpool, results) {
165        yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
166        yyjson_mut_obj_add_strbuf(doc, obj, "name", &zpool->name);
167        yyjson_mut_obj_add_strbuf(doc, obj, "state", &zpool->state);
168        yyjson_mut_obj_add_uint(doc, obj, "guid", zpool->guid);
169        yyjson_mut_obj_add_uint(doc, obj, "used", zpool->used);
170        yyjson_mut_obj_add_uint(doc, obj, "allocated", zpool->allocated);
171        yyjson_mut_obj_add_uint(doc, obj, "total", zpool->total);
172        if (zpool->fragmentation != -DBL_MAX) {
173            yyjson_mut_obj_add_real(doc, obj, "fragmentation", zpool->fragmentation);
174        } else {
175            yyjson_mut_obj_add_null(doc, obj, "fragmentation");
176        }
177        yyjson_mut_obj_add_bool(doc, obj, "readOnly", zpool->readOnly);
178    }
179
180    FF_LIST_FOR_EACH (FFZpoolResult, zpool, results) {
181        ffStrbufDestroy(&zpool->name);
182        ffStrbufDestroy(&zpool->state);
183    }
184    return true;
185}
186
187void ffInitZpoolOptions(FFZpoolOptions* options) {
188    ffOptionInitModuleArg(&options->moduleArgs, "󱑛");
189    options->percent = (FFPercentageModuleConfig) { 50, 80, 0 };
190}
191
192void ffDestroyZpoolOptions(FFZpoolOptions* options) {
193    ffOptionDestroyModuleArg(&options->moduleArgs);
194}
195
196FFModuleBaseInfo ffZpoolModuleInfo = {
197    .name = "Zpool",
198    .description = "Print ZFS storage pools",
199    .displayName = {
200        .en = "Zpool",
201        .ar = "Zpool",
202        .cs = "Zpool",
203        .de = "Zpool",
204        .es = "Zpool",
205        .fi = "Zpool",
206        .fr = "Zpool",
207        .gl = "Zpool",
208        .he = "Zpool",
209        .id = "Zpool",
210        .it = "Zpool",
211        .ja = "Zpool",
212        .ko = "Zpool",
213        .pl = "Zpool",
214        .pt = "Zpool",
215        .ru = "Zpool",
216        .tr = "Zpool",
217        .uk = "Zpool",
218        .vi = "Zpool",
219        .zh_CN = "Zpool",
220        .zh_TW = "Zpool",
221    },
222    .initOptions = (void*) ffInitZpoolOptions,
223    .destroyOptions = (void*) ffDestroyZpoolOptions,
224    .parseJsonObject = (void*) ffParseZpoolJsonObject,
225    .printModule = (void*) ffPrintZpool,
226    .generateJsonResult = (void*) ffGenerateZpoolJsonResult,
227    .generateJsonConfig = (void*) ffGenerateZpoolJsonConfig,
228    .formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) {
229        { "Zpool name *", "name" },
230        { "Zpool guid *", "guid" },
231        { "Zpool state", "state" },
232        { "Size used", "size-used" },
233        { "Size allocated", "size-allocated" },
234        { "Size total", "size-total" },
235        { "Size used percentage num", "used-percentage" },
236        { "Size allocated percentage num", "allocated-percentage" },
237        { "Fragmentation percentage num", "frag-percentage" },
238        { "Size used percentage bar", "used-percentage-bar" },
239        { "Size allocated percentage bar", "allocated-percentage-bar" },
240        { "Fragmentation percentage bar", "frag-percentage-bar" },
241        { "Is read-only", "is-readonly" },
242    })),
243    .defaultOrder = 44,
244};