xref: /aosp_15_r20/external/vboot_reference/futility/futility.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1 /* Copyright 2013 The ChromiumOS Authors
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  */
5 
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <getopt.h>
9 #include <limits.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
16 
17 #include "futility.h"
18 
19 const char *ft_print_header = NULL;
20 const char *ft_print_header2 = NULL;
21 
22 /******************************************************************************/
23 
24 static const char *const usage = "\n"
25 "Usage: " MYNAME " [options] COMMAND [args...]\n"
26 "\n"
27 "This is the unified firmware utility, which contains various of distinct\n"
28 "verified boot tools as subcommands.\n"
29 "\n"
30 "See the README file for more information about the available commands\n";
31 
32 static const char *const options =
33 "Global options:\n"
34 "\n"
35 "  --vb1        Use only vboot v1.0 binary formats\n"
36 "  --vb21       Use only vboot v2.1 binary formats\n"
37 "  --debug      Be noisy about what's going on\n"
38 "\n";
39 
find_command(const char * name)40 static const struct futil_cmd_t *find_command(const char *name)
41 {
42 	const struct futil_cmd_t *const *cmd;
43 
44 	for (cmd = futil_cmds; *cmd; cmd++)
45 		if (((*cmd)->version & vboot_version) &&
46 		    !strcmp((*cmd)->name, name))
47 			return *cmd;
48 
49 	return NULL;
50 }
51 
list_commands(void)52 static void list_commands(void)
53 {
54 	const struct futil_cmd_t *const *cmd;
55 
56 	for (cmd = futil_cmds; *cmd; cmd++)
57 		if (vboot_version & (*cmd)->version)
58 			printf("  %-20s %s\n",
59 			       (*cmd)->name, (*cmd)->shorthelp);
60 }
61 
run_command(const struct futil_cmd_t * cmd,int argc,char * argv[])62 static int run_command(const struct futil_cmd_t *cmd, int argc, char *argv[])
63 {
64 	int i;
65 	VB2_DEBUG("\"%s\" ...\n", cmd->name);
66 	for (i = 0; i < argc; i++)
67 		VB2_DEBUG("  argv[%d] = \"%s\"\n", i, argv[i]);
68 
69 	return cmd->handler(argc, argv);
70 }
71 
do_help(int argc,char * argv[])72 static int do_help(int argc, char *argv[])
73 {
74 	const struct futil_cmd_t *cmd;
75 	const char *vstr = "";
76 
77 	/* Help about a known command? */
78 	if (argc > 1) {
79 		cmd = find_command(argv[1]);
80 		if (cmd) {
81 			/* Let the command provide its own help */
82 			argv[0] = argv[1];
83 			argv[1] = (char *)"--help";
84 			return run_command(cmd, argc, argv);
85 		}
86 	}
87 
88 	fputs(usage, stdout);
89 
90 	if (vboot_version == VBOOT_VERSION_ALL)
91 		fputs(options, stdout);
92 
93 	switch (vboot_version) {
94 	case VBOOT_VERSION_1_0:
95 		vstr = "version 1.0 ";
96 		break;
97 	case VBOOT_VERSION_2_1:
98 		vstr = "version 2.1 ";
99 		break;
100 	case VBOOT_VERSION_ALL:
101 		vstr = "";
102 		break;
103 	}
104 	printf("The following %scommands are built-in:\n\n", vstr);
105 	list_commands();
106 	printf("\nUse \"" MYNAME " help COMMAND\" for more information.\n\n");
107 
108 	return 0;
109 }
110 
111 DECLARE_FUTIL_COMMAND(help, do_help, VBOOT_VERSION_ALL,
112 		      "Show a bit of help (you're looking at it)");
113 
114 static const char ver_help[] =
115 	"Show the futility source revision and build date";
do_version(int argc,char * argv[])116 static int do_version(int argc, char *argv[])
117 {
118 	if (argc > 1)
119 		printf("%s - %s\n", argv[0], ver_help);
120 	else
121 		printf("%s\n", futility_version);
122 	return 0;
123 }
124 
125 DECLARE_FUTIL_COMMAND(version, do_version, VBOOT_VERSION_ALL,
126 		      ver_help);
127 
simple_basename(char * str)128 static char *simple_basename(char *str)
129 {
130 	char *s = strrchr(str, '/');
131 	if (s)
132 		s++;
133 	else
134 		s = str;
135 	return s;
136 }
137 
138 /* Here we go */
139 #define OPT_HELP 1000
140 test_mockable
main(int argc,char * argv[],char * envp[])141 int main(int argc, char *argv[], char *envp[])
142 {
143 	char *progname;
144 	const struct futil_cmd_t *cmd;
145 	int i, errorcnt = 0;
146 	int vb_ver = VBOOT_VERSION_ALL;
147 	int helpind = 0;
148 	struct option long_opts[] = {
149 		{"debug", 0, &debugging_enabled, 1},
150 		{"vb1" ,  0, &vb_ver, VBOOT_VERSION_1_0},
151 		{"vb21",  0, &vb_ver, VBOOT_VERSION_2_1},
152 		{"help",  0, 0, OPT_HELP},
153 		{ 0, 0, 0, 0},
154 	};
155 
156 	/* How were we invoked? */
157 	progname = simple_basename(argv[0]);
158 
159 	/* See if the program name is a command we recognize */
160 	cmd = find_command(progname);
161 	if (cmd) {
162 		/* Yep, just do that */
163 		return !!run_command(cmd, argc, argv);
164 	}
165 
166 	/* Parse the global options, stopping at the first non-option. */
167 	opterr = 0;				/* quiet, you. */
168 	while ((i = getopt_long(argc, argv, "+:", long_opts, NULL)) != -1) {
169 		switch (i) {
170 		case OPT_HELP:
171 			/* Remember where we found this option */
172 			/* Note: this might be GNU-specific */
173 			helpind = optind - 1;
174 			break;
175 		case '?':
176 			if (optopt)
177 				fprintf(stderr, "Unrecognized option: -%c\n",
178 					optopt);
179 			else
180 				fprintf(stderr, "Unrecognized option: %s\n",
181 					argv[optind - 1]);
182 			errorcnt++;
183 			break;
184 		case ':':
185 			fprintf(stderr, "Missing argument to -%c\n", optopt);
186 			errorcnt++;
187 			break;
188 		case 0:				/* handled option */
189 			break;
190 		default:
191 			FATAL("Unrecognized getopt output: %d\n", i);
192 		}
193 	}
194 	vboot_version = vb_ver;
195 
196 	/*
197 	 * Translate "--help" in the args to "help" as the first parameter,
198 	 * by rearranging argv[].
199 	 */
200 	if (helpind) {
201 		int j;
202 		optind--;
203 		for (j = helpind; j < optind; j++)
204 			argv[j] = argv[j + 1];
205 		argv[j] = (char *)"help";
206 	}
207 
208 	/* We require a command name. */
209 	if (errorcnt || argc == optind) {
210 		do_help(1, argv);
211 		return 1;
212 	}
213 
214 	/* For reasons I've forgotten, treat /blah/blah/CMD the same as CMD */
215 	argv[optind] = simple_basename(argv[optind]);
216 
217 	/* Do we recognize the command? */
218 	cmd = find_command(argv[optind]);
219 	if (cmd) {
220 		/* Reset so commands can parse their own options */
221 		argc -= optind;
222 		argv += optind;
223 		optind = 0;
224 		return !!run_command(cmd, argc, argv);
225 	}
226 
227 	/* Nope. We've no clue what we're being asked to do. */
228 	do_help(1, argv);
229 	return 1;
230 }
231