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};