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