1 /* SPDX-License-Identifier: GPL-2.0-or-later */
11 #include <commonlib/bsd/helpers.h>
21 const char *description
;
22 void (*print_help
)(FILE *f
, const struct subcommand_t
*info
);
23 int (*process
)(int argc
, char *argv
[], const char store_file
[]);
26 static void help_get(FILE *f
, const struct subcommand_t
*info
);
27 static void help_guids(FILE *f
, const struct subcommand_t
*info
);
28 static void help_help(FILE *f
, const struct subcommand_t
*info
);
29 static void help_list(FILE *f
, const struct subcommand_t
*info
);
30 static void help_remove(FILE *f
, const struct subcommand_t
*info
);
31 static void help_set(FILE *f
, const struct subcommand_t
*info
);
32 static int process_get(int argc
, char *argv
[], const char store_file
[]);
33 static int process_guids(int argc
, char *argv
[], const char store_file
[]);
34 static int process_help(int argc
, char *argv
[], const char store_file
[]);
35 static int process_list(int argc
, char *argv
[], const char store_file
[]);
36 static int process_remove(int argc
, char *argv
[], const char store_file
[]);
37 static int process_set(int argc
, char *argv
[], const char store_file
[]);
39 static const struct subcommand_t sub_commands
[] = {
42 .description
= "display current value of a variable",
43 .print_help
= &help_get
,
44 .process
= &process_get
,
48 .description
= "show GUID to alias mapping",
49 .print_help
= &help_guids
,
50 .process
= &process_guids
,
54 .description
= "provide built-in help",
55 .print_help
= &help_help
,
56 .process
= &process_help
,
60 .description
= "list variables present in the store",
61 .print_help
= &help_list
,
62 .process
= &process_list
,
66 .description
= "remove a variable from the store",
67 .print_help
= &help_remove
,
68 .process
= &process_remove
,
72 .description
= "add or updates a variable in the store",
73 .print_help
= &help_set
,
74 .process
= &process_set
,
78 static const int sub_command_count
= ARRAY_SIZE(sub_commands
);
80 static const char *USAGE_FMT
= "Usage: %s smm-store-file|rom sub-command\n"
83 static const char *program_name
;
85 static void print_program_usage(void)
87 fprintf(stderr
, USAGE_FMT
, program_name
, program_name
);
91 static void print_sub_command_usage(const char sub_command
[])
93 fprintf(stderr
, "\n");
94 fprintf(stderr
, USAGE_FMT
, program_name
, program_name
);
95 fprintf(stderr
, "\n");
97 for (int i
= 0; i
< sub_command_count
; ++i
) {
98 const struct subcommand_t
*cmd
= &sub_commands
[i
];
99 if (!str_eq(cmd
->name
, sub_command
))
102 cmd
->print_help(stderr
, cmd
);
109 static void print_help(void)
111 printf(USAGE_FMT
, program_name
, program_name
);
114 printf("Sub-commands:\n");
115 for (int i
= 0; i
< sub_command_count
; ++i
) {
116 const struct subcommand_t
*cmd
= &sub_commands
[i
];
117 printf(" * %-6s - %s\n", cmd
->name
, cmd
->description
);
121 static void print_types(FILE *f
)
123 fprintf(f
, "Types and their values:\n");
124 fprintf(f
, " * bool (true, false)\n");
125 fprintf(f
, " * uint8 (0..255)\n");
126 fprintf(f
, " * uint16 (0..65535)\n");
127 fprintf(f
, " * uint32 (0..4294967295)\n");
128 fprintf(f
, " * uint64 (0..2^64-1)\n");
129 fprintf(f
, " * ascii (NUL-terminated)\n");
130 fprintf(f
, " * unicode (widened and NUL-terminated)\n");
131 fprintf(f
, " * raw (output only; raw bytes on output)\n");
134 static void help_set(FILE *f
, const struct subcommand_t
*info
)
136 fprintf(f
, "Create or update a variable:\n");
137 fprintf(f
, " %s smm-store-file|rom %s \\\n", program_name
, info
->name
);
138 fprintf(f
, " -g vendor-guid \\\n");
139 fprintf(f
, " -n variable-name \\\n");
140 fprintf(f
, " -t variable-type \\\n");
141 fprintf(f
, " -v value\n");
146 static int process_set(int argc
, char *argv
[], const char store_file
[])
148 const char *name
= NULL
;
149 const char *value
= NULL
;
150 const char *type_str
= NULL
;
151 const char *guid_str
= NULL
;
153 while ((opt
= getopt(argc
, argv
, "n:t:v:g:")) != -1) {
168 case '?': /* parsing error */
169 print_sub_command_usage(argv
[0]);
173 if (argv
[optind
] != NULL
) {
174 fprintf(stderr
, "First unexpected positional argument: %s\n",
176 print_sub_command_usage(argv
[0]);
179 if (name
== NULL
|| value
== NULL
|| type_str
== NULL
||
181 fprintf(stderr
, "All options are required\n");
182 print_sub_command_usage(argv
[0]);
185 if (name
[0] == '\0') {
186 fprintf(stderr
, "Variable name can't be empty\n");
187 print_sub_command_usage(argv
[0]);
191 if (!parse_guid(guid_str
, &guid
)) {
192 fprintf(stderr
, "Failed to parse GUID: %s\n", guid_str
);
197 if (!parse_data_type(type_str
, &type
)) {
198 fprintf(stderr
, "Failed to parse type: %s\n", type_str
);
203 void *data
= make_data(value
, &data_size
, type
);
205 fprintf(stderr
, "Failed to parse value \"%s\" as %s\n",
210 struct storage_t storage
;
211 if (!storage_open(store_file
, &storage
, /*rw=*/true)) {
216 struct var_t
*var
= vs_find(&storage
.vs
, name
, &guid
);
218 var
= vs_new_var(&storage
.vs
);
219 var
->name
= to_uchars(name
, &var
->name_size
);
221 var
->data_size
= data_size
;
226 var
->data_size
= data_size
;
229 return storage_write_back(&storage
) ? EXIT_SUCCESS
: EXIT_FAILURE
;
232 static void help_list(FILE *f
, const struct subcommand_t
*info
)
234 fprintf(f
, "List variables in the store:\n");
235 fprintf(f
, " %s smm-store-file|rom %s\n", program_name
, info
->name
);
238 static int process_list(int argc
, char *argv
[], const char store_file
[])
241 fprintf(stderr
, "Invalid invocation\n");
242 print_sub_command_usage(argv
[0]);
245 struct storage_t storage
;
246 if (!storage_open(store_file
, &storage
, /*rw=*/false))
249 for (struct var_t
*v
= storage
.vs
.vars
; v
!= NULL
; v
= v
->next
) {
250 char *name
= to_chars(v
->name
, v
->name_size
);
251 char *guid
= format_guid(&v
->guid
, /*use_alias=*/true);
253 printf("%-*s:%s (%zu %s)\n", GUID_LEN
, guid
, name
, v
->data_size
,
254 v
->data_size
== 1 ? "byte" : "bytes");
260 storage_drop(&storage
);
264 static void help_get(FILE *f
, const struct subcommand_t
*info
)
266 fprintf(f
, "Read variable's value:\n");
267 fprintf(f
, " %s smm-store-file|rom %s \\\n", program_name
, info
->name
);
268 fprintf(f
, " -g vendor-guid \\\n");
269 fprintf(f
, " -n variable-name \\\n");
270 fprintf(f
, " -t variable-type\n");
275 static int process_get(int argc
, char *argv
[], const char store_file
[])
277 const char *name
= NULL
;
278 const char *type_str
= NULL
;
279 const char *guid_str
= NULL
;
281 while ((opt
= getopt(argc
, argv
, "n:g:t:")) != -1) {
293 case '?': /* parsing error */
294 print_sub_command_usage(argv
[0]);
298 if (name
== NULL
|| type_str
== NULL
|| guid_str
== NULL
) {
299 fprintf(stderr
, "All options are required\n");
300 print_sub_command_usage(argv
[0]);
304 if (!parse_guid(guid_str
, &guid
)) {
305 fprintf(stderr
, "Failed to parse GUID: %s\n", guid_str
);
310 if (!parse_data_type(type_str
, &type
)) {
311 fprintf(stderr
, "Failed to parse type: %s\n", type_str
);
315 struct storage_t storage
;
316 if (!storage_open(store_file
, &storage
, /*rw=*/false))
319 int result
= EXIT_SUCCESS
;
321 struct var_t
*var
= vs_find(&storage
.vs
, name
, &guid
);
323 result
= EXIT_FAILURE
;
324 fprintf(stderr
, "Couldn't find variable \"%s:%s\"\n",
326 } else if (var
->data_size
== 0) {
327 fprintf(stderr
, "There is no data to show.\n");
328 result
= EXIT_FAILURE
;
330 print_data(var
->data
, var
->data_size
, type
);
333 storage_drop(&storage
);
337 static void help_help(FILE *f
, const struct subcommand_t
*info
)
339 fprintf(f
, "Display generic help:\n");
340 fprintf(f
, " %s smm-store-file|rom %s\n", program_name
, info
->name
);
342 fprintf(f
, "Display sub-command help:\n");
343 fprintf(f
, " %s smm-store-file|rom %s sub-command\n",
344 program_name
, info
->name
);
347 static int process_help(int argc
, char *argv
[], const char store_file
[])
357 fprintf(stderr
, "Invalid invocation\n");
358 print_sub_command_usage(argv
[0]);
362 const char *sub_command
= argv
[1];
364 for (int i
= 0; i
< sub_command_count
; ++i
) {
365 const struct subcommand_t
*cmd
= &sub_commands
[i
];
366 if (!str_eq(cmd
->name
, sub_command
))
369 cmd
->print_help(stdout
, cmd
);
373 fprintf(stderr
, "Unknown sub-command: %s\n", sub_command
);
378 static void help_remove(FILE *f
, const struct subcommand_t
*info
)
380 fprintf(f
, "Remove a variable:\n");
381 fprintf(f
, " %s smm-store-file|rom %s \\\n", program_name
, info
->name
);
382 fprintf(f
, " -g vendor-guid \\\n");
383 fprintf(f
, " -n variable-name\n");
386 static int process_remove(int argc
, char *argv
[], const char store_file
[])
388 const char *name
= NULL
;
389 const char *guid_str
= NULL
;
391 while ((opt
= getopt(argc
, argv
, "n:g:")) != -1) {
400 case '?': /* parsing error */
401 print_sub_command_usage(argv
[0]);
405 if (name
== NULL
|| guid_str
== NULL
) {
406 fprintf(stderr
, "All options are required\n");
407 print_sub_command_usage(argv
[0]);
411 if (!parse_guid(guid_str
, &guid
)) {
412 fprintf(stderr
, "Failed to parse GUID: %s\n", guid_str
);
416 struct storage_t storage
;
417 if (!storage_open(store_file
, &storage
, /*rw=*/true))
420 int result
= EXIT_SUCCESS
;
422 struct var_t
*var
= vs_find(&storage
.vs
, name
, &guid
);
424 result
= EXIT_FAILURE
;
425 fprintf(stderr
, "Couldn't find variable \"%s:%s\"\n",
428 vs_delete(&storage
.vs
, var
);
431 storage_write_back(&storage
);
435 static void help_guids(FILE *f
, const struct subcommand_t
*info
)
437 fprintf(f
, "List recognized GUIDS:\n");
438 fprintf(f
, " %s smm-store-file|rom %s\n", program_name
, info
->name
);
441 static int process_guids(int argc
, char *argv
[], const char store_file
[])
446 fprintf(stderr
, "Invalid invocation\n");
447 print_sub_command_usage(argv
[0]);
450 for (int i
= 0; i
< known_guid_count
; ++i
) {
451 char *guid
= format_guid(&known_guids
[i
].guid
,
452 /*use_alias=*/false);
453 printf("%-10s -> %s\n", known_guids
[i
].alias
, guid
);
459 int main(int argc
, char *argv
[])
461 program_name
= argv
[0];
463 if (argc
> 1 && (str_eq(argv
[1], "-h") || str_eq(argv
[1], "--help"))) {
469 print_program_usage();
471 const char *store_file
= argv
[1];
472 const char *sub_command
= argv
[2];
474 int sub_command_argc
= argc
- 2;
475 char **sub_command_argv
= argv
+ 2;
477 for (int i
= 0; i
< sub_command_count
; ++i
) {
478 const struct subcommand_t
*cmd
= &sub_commands
[i
];
479 if (!str_eq(cmd
->name
, sub_command
))
482 return cmd
->process(sub_command_argc
,
487 fprintf(stderr
, "Unknown sub-command: %s\n", sub_command
);