xref: /aosp_15_r20/external/coreboot/util/smmstoretool/main.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <unistd.h>
4 
5 #include <errno.h>
6 #include <stdbool.h>
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 
11 #include <commonlib/bsd/helpers.h>
12 
13 #include "data.h"
14 #include "guids.h"
15 #include "storage.h"
16 #include "udk2017.h"
17 #include "vs.h"
18 
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[]);
24 };
25 
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[]);
38 
39 static const struct subcommand_t sub_commands[] = {
40 	{
41 		.name = "get",
42 		.description = "display current value of a variable",
43 		.print_help = &help_get,
44 		.process = &process_get,
45 	},
46 	{
47 		.name = "guids",
48 		.description = "show GUID to alias mapping",
49 		.print_help = &help_guids,
50 		.process = &process_guids,
51 	},
52 	{
53 		.name = "help",
54 		.description = "provide built-in help",
55 		.print_help = &help_help,
56 		.process = &process_help,
57 	},
58 	{
59 		.name = "list",
60 		.description = "list variables present in the store",
61 		.print_help = &help_list,
62 		.process = &process_list,
63 	},
64 	{
65 		.name = "remove",
66 		.description = "remove a variable from the store",
67 		.print_help = &help_remove,
68 		.process = &process_remove,
69 	},
70 	{
71 		.name = "set",
72 		.description = "add or updates a variable in the store",
73 		.print_help = &help_set,
74 		.process = &process_set,
75 	},
76 };
77 
78 static const int sub_command_count = ARRAY_SIZE(sub_commands);
79 
80 static const char *USAGE_FMT = "Usage: %s smm-store-file|rom sub-command\n"
81 			       "       %s -h|--help\n";
82 
83 static const char *program_name;
84 
print_program_usage(void)85 static void print_program_usage(void)
86 {
87 	fprintf(stderr, USAGE_FMT, program_name, program_name);
88 	exit(EXIT_FAILURE);
89 }
90 
print_sub_command_usage(const char sub_command[])91 static void print_sub_command_usage(const char sub_command[])
92 {
93 	fprintf(stderr, "\n");
94 	fprintf(stderr, USAGE_FMT, program_name, program_name);
95 	fprintf(stderr, "\n");
96 
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;
101 
102 		cmd->print_help(stderr, cmd);
103 		break;
104 	}
105 
106 	exit(EXIT_FAILURE);
107 }
108 
print_help(void)109 static void print_help(void)
110 {
111 	printf(USAGE_FMT, program_name, program_name);
112 
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);
118 	}
119 }
120 
print_types(FILE * f)121 static void print_types(FILE *f)
122 {
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");
132 }
133 
help_set(FILE * f,const struct subcommand_t * info)134 static void help_set(FILE *f, const struct subcommand_t *info)
135 {
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);
144 }
145 
process_set(int argc,char * argv[],const char store_file[])146 static int process_set(int argc, char *argv[], const char store_file[])
147 {
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;
167 
168 		case '?': /* parsing error */
169 			print_sub_command_usage(argv[0]);
170 		}
171 	}
172 
173 	if (argv[optind] != NULL) {
174 		fprintf(stderr, "First unexpected positional argument: %s\n",
175 			argv[optind]);
176 		print_sub_command_usage(argv[0]);
177 	}
178 
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]);
183 	}
184 
185 	if (name[0] == '\0') {
186 		fprintf(stderr, "Variable name can't be empty\n");
187 		print_sub_command_usage(argv[0]);
188 	}
189 
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;
194 	}
195 
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;
200 	}
201 
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;
208 	}
209 
210 	struct storage_t storage;
211 	if (!storage_open(store_file, &storage, /*rw=*/true)) {
212 		free(data);
213 		return EXIT_FAILURE;
214 	}
215 
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;
227 	}
228 
229 	return storage_write_back(&storage) ? EXIT_SUCCESS : EXIT_FAILURE;
230 }
231 
help_list(FILE * f,const struct subcommand_t * info)232 static void help_list(FILE *f, const struct subcommand_t *info)
233 {
234 	fprintf(f, "List variables in the store:\n");
235 	fprintf(f, "  %s smm-store-file|rom %s\n", program_name, info->name);
236 }
237 
process_list(int argc,char * argv[],const char store_file[])238 static int process_list(int argc, char *argv[], const char store_file[])
239 {
240 	if (argc != 1) {
241 		fprintf(stderr, "Invalid invocation\n");
242 		print_sub_command_usage(argv[0]);
243 	}
244 
245 	struct storage_t storage;
246 	if (!storage_open(store_file, &storage, /*rw=*/false))
247 		return EXIT_FAILURE;
248 
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);
252 
253 		printf("%-*s:%s (%zu %s)\n", GUID_LEN, guid, name, v->data_size,
254 		       v->data_size == 1 ? "byte" : "bytes");
255 
256 		free(name);
257 		free(guid);
258 	}
259 
260 	storage_drop(&storage);
261 	return EXIT_SUCCESS;
262 }
263 
help_get(FILE * f,const struct subcommand_t * info)264 static void help_get(FILE *f, const struct subcommand_t *info)
265 {
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);
273 }
274 
process_get(int argc,char * argv[],const char store_file[])275 static int process_get(int argc, char *argv[], const char store_file[])
276 {
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;
292 
293 		case '?': /* parsing error */
294 			print_sub_command_usage(argv[0]);
295 		}
296 	}
297 
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]);
301 	}
302 
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;
307 	}
308 
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;
313 	}
314 
315 	struct storage_t storage;
316 	if (!storage_open(store_file, &storage, /*rw=*/false))
317 		return EXIT_FAILURE;
318 
319 	int result = EXIT_SUCCESS;
320 
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);
331 	}
332 
333 	storage_drop(&storage);
334 	return result;
335 }
336 
help_help(FILE * f,const struct subcommand_t * info)337 static void help_help(FILE *f, const struct subcommand_t *info)
338 {
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);
345 }
346 
process_help(int argc,char * argv[],const char store_file[])347 static int process_help(int argc, char *argv[], const char store_file[])
348 {
349 	(void)store_file;
350 
351 	if (argc == 1) {
352 		print_help();
353 		return EXIT_SUCCESS;
354 	}
355 
356 	if (argc != 2) {
357 		fprintf(stderr, "Invalid invocation\n");
358 		print_sub_command_usage(argv[0]);
359 		return EXIT_FAILURE;
360 	}
361 
362 	const char *sub_command = argv[1];
363 
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;
368 
369 		cmd->print_help(stdout, cmd);
370 		return EXIT_SUCCESS;
371 	}
372 
373 	fprintf(stderr, "Unknown sub-command: %s\n", sub_command);
374 	print_help();
375 	return EXIT_FAILURE;
376 }
377 
help_remove(FILE * f,const struct subcommand_t * info)378 static void help_remove(FILE *f, const struct subcommand_t *info)
379 {
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");
384 }
385 
process_remove(int argc,char * argv[],const char store_file[])386 static int process_remove(int argc, char *argv[], const char store_file[])
387 {
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;
399 
400 		case '?': /* parsing error */
401 			print_sub_command_usage(argv[0]);
402 		}
403 	}
404 
405 	if (name == NULL || guid_str == NULL) {
406 		fprintf(stderr, "All options are required\n");
407 		print_sub_command_usage(argv[0]);
408 	}
409 
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;
414 	}
415 
416 	struct storage_t storage;
417 	if (!storage_open(store_file, &storage, /*rw=*/true))
418 		return EXIT_FAILURE;
419 
420 	int result = EXIT_SUCCESS;
421 
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);
429 	}
430 
431 	storage_write_back(&storage);
432 	return result;
433 }
434 
help_guids(FILE * f,const struct subcommand_t * info)435 static void help_guids(FILE *f, const struct subcommand_t *info)
436 {
437 	fprintf(f, "List recognized GUIDS:\n");
438 	fprintf(f, "  %s smm-store-file|rom %s\n", program_name, info->name);
439 }
440 
process_guids(int argc,char * argv[],const char store_file[])441 static int process_guids(int argc, char *argv[], const char store_file[])
442 {
443 	(void)store_file;
444 
445 	if (argc != 1) {
446 		fprintf(stderr, "Invalid invocation\n");
447 		print_sub_command_usage(argv[0]);
448 	}
449 
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);
455 	}
456 	return EXIT_SUCCESS;
457 }
458 
main(int argc,char * argv[])459 int main(int argc, char *argv[])
460 {
461 	program_name = argv[0];
462 
463 	if (argc > 1 && (str_eq(argv[1], "-h") || str_eq(argv[1], "--help"))) {
464 		print_help();
465 		exit(EXIT_SUCCESS);
466 	}
467 
468 	if (argc < 3)
469 		print_program_usage();
470 
471 	const char *store_file = argv[1];
472 	const char *sub_command = argv[2];
473 
474 	int sub_command_argc = argc - 2;
475 	char **sub_command_argv = argv + 2;
476 
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;
481 
482 		return cmd->process(sub_command_argc,
483 				    sub_command_argv,
484 				    store_file);
485 	}
486 
487 	fprintf(stderr, "Unknown sub-command: %s\n", sub_command);
488 	print_help();
489 	return EXIT_FAILURE;
490 }
491