treewide: Move device_tree to commonlib
[coreboot2.git] / util / smmstoretool / main.c
blob89d58d619aaf1ed29173cdb0f76c3da7d6268aeb
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include <unistd.h>
5 #include <errno.h>
6 #include <stdbool.h>
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
11 #include <commonlib/bsd/helpers.h>
13 #include "data.h"
14 #include "guids.h"
15 #include "storage.h"
16 #include "udk2017.h"
17 #include "vs.h"
19 struct subcommand_t {
20 const char *name;
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[] = {
41 .name = "get",
42 .description = "display current value of a variable",
43 .print_help = &help_get,
44 .process = &process_get,
47 .name = "guids",
48 .description = "show GUID to alias mapping",
49 .print_help = &help_guids,
50 .process = &process_guids,
53 .name = "help",
54 .description = "provide built-in help",
55 .print_help = &help_help,
56 .process = &process_help,
59 .name = "list",
60 .description = "list variables present in the store",
61 .print_help = &help_list,
62 .process = &process_list,
65 .name = "remove",
66 .description = "remove a variable from the store",
67 .print_help = &help_remove,
68 .process = &process_remove,
71 .name = "set",
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"
81 " %s -h|--help\n";
83 static const char *program_name;
85 static void print_program_usage(void)
87 fprintf(stderr, USAGE_FMT, program_name, program_name);
88 exit(EXIT_FAILURE);
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))
100 continue;
102 cmd->print_help(stderr, cmd);
103 break;
106 exit(EXIT_FAILURE);
109 static void print_help(void)
111 printf(USAGE_FMT, program_name, program_name);
113 printf("\n");
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");
142 fprintf(f, "\n");
143 print_types(f);
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;
152 int opt;
153 while ((opt = getopt(argc, argv, "n:t:v:g:")) != -1) {
154 switch (opt) {
155 case 'n':
156 name = optarg;
157 break;
158 case 't':
159 type_str = optarg;
160 break;
161 case 'v':
162 value = optarg;
163 break;
164 case 'g':
165 guid_str = optarg;
166 break;
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",
175 argv[optind]);
176 print_sub_command_usage(argv[0]);
179 if (name == NULL || value == NULL || type_str == NULL ||
180 guid_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]);
190 EFI_GUID guid;
191 if (!parse_guid(guid_str, &guid)) {
192 fprintf(stderr, "Failed to parse GUID: %s\n", guid_str);
193 return EXIT_FAILURE;
196 enum data_type type;
197 if (!parse_data_type(type_str, &type)) {
198 fprintf(stderr, "Failed to parse type: %s\n", type_str);
199 return EXIT_FAILURE;
202 size_t data_size;
203 void *data = make_data(value, &data_size, type);
204 if (data == NULL) {
205 fprintf(stderr, "Failed to parse value \"%s\" as %s\n",
206 value, type_str);
207 return EXIT_FAILURE;
210 struct storage_t storage;
211 if (!storage_open(store_file, &storage, /*rw=*/true)) {
212 free(data);
213 return EXIT_FAILURE;
216 struct var_t *var = vs_find(&storage.vs, name, &guid);
217 if (var == NULL) {
218 var = vs_new_var(&storage.vs);
219 var->name = to_uchars(name, &var->name_size);
220 var->data = data;
221 var->data_size = data_size;
222 var->guid = guid;
223 } else {
224 free(var->data);
225 var->data = data;
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[])
240 if (argc != 1) {
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))
247 return EXIT_FAILURE;
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");
256 free(name);
257 free(guid);
260 storage_drop(&storage);
261 return EXIT_SUCCESS;
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");
271 fprintf(f, "\n");
272 print_types(f);
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;
280 int opt;
281 while ((opt = getopt(argc, argv, "n:g:t:")) != -1) {
282 switch (opt) {
283 case 'n':
284 name = optarg;
285 break;
286 case 'g':
287 guid_str = optarg;
288 break;
289 case 't':
290 type_str = optarg;
291 break;
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]);
303 EFI_GUID guid;
304 if (!parse_guid(guid_str, &guid)) {
305 fprintf(stderr, "Failed to parse GUID: %s\n", guid_str);
306 return EXIT_FAILURE;
309 enum data_type type;
310 if (!parse_data_type(type_str, &type)) {
311 fprintf(stderr, "Failed to parse type: %s\n", type_str);
312 return EXIT_FAILURE;
315 struct storage_t storage;
316 if (!storage_open(store_file, &storage, /*rw=*/false))
317 return EXIT_FAILURE;
319 int result = EXIT_SUCCESS;
321 struct var_t *var = vs_find(&storage.vs, name, &guid);
322 if (var == NULL) {
323 result = EXIT_FAILURE;
324 fprintf(stderr, "Couldn't find variable \"%s:%s\"\n",
325 guid_str, name);
326 } else if (var->data_size == 0) {
327 fprintf(stderr, "There is no data to show.\n");
328 result = EXIT_FAILURE;
329 } else {
330 print_data(var->data, var->data_size, type);
333 storage_drop(&storage);
334 return result;
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);
341 fprintf(f, "\n");
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[])
349 (void)store_file;
351 if (argc == 1) {
352 print_help();
353 return EXIT_SUCCESS;
356 if (argc != 2) {
357 fprintf(stderr, "Invalid invocation\n");
358 print_sub_command_usage(argv[0]);
359 return EXIT_FAILURE;
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))
367 continue;
369 cmd->print_help(stdout, cmd);
370 return EXIT_SUCCESS;
373 fprintf(stderr, "Unknown sub-command: %s\n", sub_command);
374 print_help();
375 return EXIT_FAILURE;
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;
390 int opt;
391 while ((opt = getopt(argc, argv, "n:g:")) != -1) {
392 switch (opt) {
393 case 'n':
394 name = optarg;
395 break;
396 case 'g':
397 guid_str = optarg;
398 break;
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]);
410 EFI_GUID guid;
411 if (!parse_guid(guid_str, &guid)) {
412 fprintf(stderr, "Failed to parse GUID: %s\n", guid_str);
413 return EXIT_FAILURE;
416 struct storage_t storage;
417 if (!storage_open(store_file, &storage, /*rw=*/true))
418 return EXIT_FAILURE;
420 int result = EXIT_SUCCESS;
422 struct var_t *var = vs_find(&storage.vs, name, &guid);
423 if (var == NULL) {
424 result = EXIT_FAILURE;
425 fprintf(stderr, "Couldn't find variable \"%s:%s\"\n",
426 guid_str, name);
427 } else {
428 vs_delete(&storage.vs, var);
431 storage_write_back(&storage);
432 return result;
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[])
443 (void)store_file;
445 if (argc != 1) {
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);
454 free(guid);
456 return EXIT_SUCCESS;
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"))) {
464 print_help();
465 exit(EXIT_SUCCESS);
468 if (argc < 3)
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))
480 continue;
482 return cmd->process(sub_command_argc,
483 sub_command_argv,
484 store_file);
487 fprintf(stderr, "Unknown sub-command: %s\n", sub_command);
488 print_help();
489 return EXIT_FAILURE;