blob: 02f61af98fcd8522de02312c60047bd19399c5ba [file] [log] [blame]
Bill Richardsonfeb25182013-03-07 12:54:29 -08001/*
Bill Richardson6f396152014-07-15 12:52:19 -07002 * Copyright 2013 The Chromium OS Authors. All rights reserved.
Bill Richardsonfeb25182013-03-07 12:54:29 -08003 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
Bill Richardsonfeb25182013-03-07 12:54:29 -08007#include <errno.h>
8#include <fcntl.h>
Bill Richardson1eae8732015-02-05 12:36:15 -08009#include <getopt.h>
Bill Richardsonfeb25182013-03-07 12:54:29 -080010#include <limits.h>
11#include <stdint.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <sys/stat.h>
16#include <unistd.h>
17
18#include "futility.h"
19
Bill Richardson779796f2014-09-23 11:47:40 -070020
21/******************************************************************************/
22/* Logging stuff */
Bill Richardsonfeb25182013-03-07 12:54:29 -080023
24/* File to use for logging, if present */
25#define LOGFILE "/tmp/futility.log"
26
27/* Normally logging will only happen if the logfile already exists. Uncomment
28 * this to force log file creation (and thus logging) always. */
Bill Richardson779796f2014-09-23 11:47:40 -070029
Bill Richardsonfeb25182013-03-07 12:54:29 -080030/* #define FORCE_LOGGING_ON */
31
Bill Richardsonfeb25182013-03-07 12:54:29 -080032static int log_fd = -1;
33
34/* Write the string and a newline. Silently give up on errors */
Bill Richardsonee53d652014-09-04 16:18:15 -070035static void log_str(char *prefix, char *str)
Bill Richardsonfeb25182013-03-07 12:54:29 -080036{
Bill Richardson31d95c22014-08-24 22:07:17 -070037 int len, done, n;
Bill Richardsonfeb25182013-03-07 12:54:29 -080038
Bill Richardson31d95c22014-08-24 22:07:17 -070039 if (log_fd < 0)
40 return;
Bill Richardsonfeb25182013-03-07 12:54:29 -080041
Bill Richardson31d95c22014-08-24 22:07:17 -070042 if (!str)
43 str = "(NULL)";
Bill Richardsonfeb25182013-03-07 12:54:29 -080044
Bill Richardsonee53d652014-09-04 16:18:15 -070045 if (prefix && *prefix) {
46 len = strlen(prefix);
47 for (done = 0; done < len; done += n) {
48 n = write(log_fd, prefix + done, len - done);
49 if (n < 0)
50 return;
51 }
52 }
53
Bill Richardson31d95c22014-08-24 22:07:17 -070054 len = strlen(str);
55 if (len == 0) {
56 str = "(EMPTY)";
57 len = strlen(str);
58 }
Bill Richardsonfeb25182013-03-07 12:54:29 -080059
Bill Richardson31d95c22014-08-24 22:07:17 -070060 for (done = 0; done < len; done += n) {
61 n = write(log_fd, str + done, len - done);
62 if (n < 0)
63 return;
64 }
Bill Richardsonfeb25182013-03-07 12:54:29 -080065
Bill Richardson31d95c22014-08-24 22:07:17 -070066 if (write(log_fd, "\n", 1) < 0)
67 return;
Bill Richardsonfeb25182013-03-07 12:54:29 -080068}
69
70static void log_close(void)
71{
Bill Richardson31d95c22014-08-24 22:07:17 -070072 struct flock lock;
Bill Richardsonfeb25182013-03-07 12:54:29 -080073
Bill Richardson31d95c22014-08-24 22:07:17 -070074 if (log_fd >= 0) {
75 memset(&lock, 0, sizeof(lock));
76 lock.l_type = F_UNLCK;
77 lock.l_whence = SEEK_SET;
78 if (fcntl(log_fd, F_SETLKW, &lock))
79 perror("Unable to unlock log file");
Bill Richardsonfeb25182013-03-07 12:54:29 -080080
Bill Richardson31d95c22014-08-24 22:07:17 -070081 close(log_fd);
82 log_fd = -1;
83 }
Bill Richardsonfeb25182013-03-07 12:54:29 -080084}
85
86static void log_open(void)
87{
Bill Richardson31d95c22014-08-24 22:07:17 -070088 struct flock lock;
89 int ret;
Bill Richardsonfeb25182013-03-07 12:54:29 -080090
91#ifdef FORCE_LOGGING_ON
Bill Richardson31d95c22014-08-24 22:07:17 -070092 log_fd = open(LOGFILE, O_WRONLY | O_APPEND | O_CREAT, 0666);
Bill Richardsonfeb25182013-03-07 12:54:29 -080093#else
Bill Richardson31d95c22014-08-24 22:07:17 -070094 log_fd = open(LOGFILE, O_WRONLY | O_APPEND);
Bill Richardsonfeb25182013-03-07 12:54:29 -080095#endif
Bill Richardson31d95c22014-08-24 22:07:17 -070096 if (log_fd < 0) {
Bill Richardsonfeb25182013-03-07 12:54:29 -080097
Bill Richardson31d95c22014-08-24 22:07:17 -070098 if (errno != EACCES)
99 return;
Bill Richardsonfeb25182013-03-07 12:54:29 -0800100
Bill Richardson31d95c22014-08-24 22:07:17 -0700101 /* Permission problems should improve shortly ... */
102 sleep(1);
103 log_fd = open(LOGFILE, O_WRONLY | O_APPEND | O_CREAT, 0666);
104 if (log_fd < 0) /* Nope, they didn't */
105 return;
106 }
Bill Richardsonfeb25182013-03-07 12:54:29 -0800107
Bill Richardson31d95c22014-08-24 22:07:17 -0700108 /* Let anyone have a turn */
109 fchmod(log_fd, 0666);
Bill Richardsonfeb25182013-03-07 12:54:29 -0800110
Bill Richardson31d95c22014-08-24 22:07:17 -0700111 /* But only one at a time */
112 memset(&lock, 0, sizeof(lock));
113 lock.l_type = F_WRLCK;
114 lock.l_whence = SEEK_END;
Bill Richardsonfeb25182013-03-07 12:54:29 -0800115
Bill Richardson31d95c22014-08-24 22:07:17 -0700116 ret = fcntl(log_fd, F_SETLKW, &lock); /* this blocks */
117 if (ret < 0)
118 log_close();
Bill Richardsonfeb25182013-03-07 12:54:29 -0800119}
120
Bill Richardsonfeb25182013-03-07 12:54:29 -0800121static void log_args(int argc, char *argv[])
122{
Bill Richardson31d95c22014-08-24 22:07:17 -0700123 int i;
124 ssize_t r;
125 pid_t parent;
126 char buf[80];
Bill Richardsonee53d652014-09-04 16:18:15 -0700127 FILE *fp;
128 char caller_buf[PATH_MAX];
Bill Richardsonfeb25182013-03-07 12:54:29 -0800129
Bill Richardson31d95c22014-08-24 22:07:17 -0700130 log_open();
Bill Richardsonfeb25182013-03-07 12:54:29 -0800131
Bill Richardson31d95c22014-08-24 22:07:17 -0700132 /* delimiter */
Bill Richardson6df3e332014-10-02 18:50:33 -0700133 log_str(NULL, "##### LOG #####");
Bill Richardsonfeb25182013-03-07 12:54:29 -0800134
Bill Richardson31d95c22014-08-24 22:07:17 -0700135 /* Can we tell who called us? */
136 parent = getppid();
137 snprintf(buf, sizeof(buf), "/proc/%d/exe", parent);
Bill Richardsonee53d652014-09-04 16:18:15 -0700138 r = readlink(buf, caller_buf, sizeof(caller_buf) - 1);
Bill Richardson31d95c22014-08-24 22:07:17 -0700139 if (r >= 0) {
Bill Richardsonee53d652014-09-04 16:18:15 -0700140 caller_buf[r] = '\0';
141 log_str("CALLER:", caller_buf);
142 }
143
144 /* From where? */
145 snprintf(buf, sizeof(buf), "/proc/%d/cwd", parent);
146 r = readlink(buf, caller_buf, sizeof(caller_buf) - 1);
147 if (r >= 0) {
148 caller_buf[r] = '\0';
149 log_str("DIR:", caller_buf);
150 }
151
152 /* And maybe the args? */
153 snprintf(buf, sizeof(buf), "/proc/%d/cmdline", parent);
154 fp = fopen(buf, "r");
155 if (fp) {
156 memset(caller_buf, 0, sizeof(caller_buf));
157 r = fread(caller_buf, 1, sizeof(caller_buf) - 1, fp);
158 if (r > 0) {
159 char *s = caller_buf;
160 for (i = 0; i < r && *s; ) {
161 log_str("CMDLINE:", s);
162 while (i < r && *s)
163 i++, s++;
164 i++, s++;
165 }
166 }
167 fclose(fp);
Bill Richardson31d95c22014-08-24 22:07:17 -0700168 }
Bill Richardsonfeb25182013-03-07 12:54:29 -0800169
Bill Richardson31d95c22014-08-24 22:07:17 -0700170 /* Now log the stuff about ourselves */
171 for (i = 0; i < argc; i++)
Bill Richardsonee53d652014-09-04 16:18:15 -0700172 log_str(NULL, argv[i]);
Bill Richardsonfeb25182013-03-07 12:54:29 -0800173
Bill Richardson31d95c22014-08-24 22:07:17 -0700174 log_close();
Bill Richardsonfeb25182013-03-07 12:54:29 -0800175}
176
Bill Richardsonfeb25182013-03-07 12:54:29 -0800177/******************************************************************************/
Bill Richardson779796f2014-09-23 11:47:40 -0700178
Bill Richardson1eae8732015-02-05 12:36:15 -0800179/* Default is to support everything we can */
180enum vboot_version vboot_version = VBOOT_VERSION_ALL;
181
Bill Richardson779796f2014-09-23 11:47:40 -0700182static const char *const usage = "\n"
Bill Richardson1eae8732015-02-05 12:36:15 -0800183"Usage: " MYNAME " [options] COMMAND [args...]\n"
Bill Richardson779796f2014-09-23 11:47:40 -0700184"\n"
185"This is the unified firmware utility, which will eventually replace\n"
186"most of the distinct verified boot tools formerly produced by the\n"
187"vboot_reference package.\n"
188"\n"
189"When symlinked under the name of one of those previous tools, it should\n"
190"fully implement the original behavior. It can also be invoked directly\n"
191"as " MYNAME ", followed by the original name as the first argument.\n"
192"\n";
193
Bill Richardson1eae8732015-02-05 12:36:15 -0800194static const char *const options =
195"Global options:\n"
196"\n"
197" --vb1 Use only vboot v1.0 binary formats\n"
198" --vb21 Use only vboot v2.1 binary formats\n"
199"\n";
Bill Richardson779796f2014-09-23 11:47:40 -0700200
201static const struct futil_cmd_t *find_command(const char *name)
202{
203 const struct futil_cmd_t *const *cmd;
204
205 for (cmd = futil_cmds; *cmd; cmd++)
206 if (0 == strcmp((*cmd)->name, name))
207 return *cmd;
208
209 return NULL;
210}
211
212static void list_commands(void)
213{
214 const struct futil_cmd_t *const *cmd;
215
216 for (cmd = futil_cmds; *cmd; cmd++)
Bill Richardson1eae8732015-02-05 12:36:15 -0800217 if (vboot_version & (*cmd)->version)
218 printf(" %-20s %s\n",
219 (*cmd)->name, (*cmd)->shorthelp);
Bill Richardson779796f2014-09-23 11:47:40 -0700220}
221
222static int do_help(int argc, char *argv[])
223{
224 const struct futil_cmd_t *cmd;
Bill Richardson1eae8732015-02-05 12:36:15 -0800225 const char *vstr;
Bill Richardson779796f2014-09-23 11:47:40 -0700226
227 if (argc >= 2) {
228 cmd = find_command(argv[1]);
229 if (cmd) {
230 printf("\n%s - %s\n", argv[1], cmd->shorthelp);
Bill Richardson004851f2014-12-11 12:20:07 -0800231 if (cmd->longhelp)
232 cmd->longhelp(argv[1]);
Bill Richardson779796f2014-09-23 11:47:40 -0700233 return 0;
234 }
235 }
236
237 fputs(usage, stdout);
238
Bill Richardson1eae8732015-02-05 12:36:15 -0800239 if (vboot_version == VBOOT_VERSION_ALL)
240 fputs(options, stdout);
241
242 switch (vboot_version) {
243 case VBOOT_VERSION_1_0:
244 vstr = "version 1.0 ";
245 break;
246 case VBOOT_VERSION_2_1:
247 vstr = "version 2.1 ";
248 break;
249 case VBOOT_VERSION_ALL:
250 vstr = "";
251 break;
252 }
253 printf("The following %scommands are built-in:\n\n", vstr);
Bill Richardson779796f2014-09-23 11:47:40 -0700254 list_commands();
255 printf("\nUse \"" MYNAME " help COMMAND\" for more information.\n\n");
256
257 return 0;
258}
259
Bill Richardson1eae8732015-02-05 12:36:15 -0800260DECLARE_FUTIL_COMMAND(help, do_help, VBOOT_VERSION_ALL,
Bill Richardson779796f2014-09-23 11:47:40 -0700261 "Show a bit of help (you're looking at it)",
Bill Richardson1eae8732015-02-05 12:36:15 -0800262 NULL);
Bill Richardson779796f2014-09-23 11:47:40 -0700263
Bill Richardsone1486c32014-10-30 17:41:51 -0700264static int do_version(int argc, char *argv[])
265{
266 printf("%s\n", futility_version);
267 return 0;
268}
269
Bill Richardson1eae8732015-02-05 12:36:15 -0800270DECLARE_FUTIL_COMMAND(version, do_version, VBOOT_VERSION_ALL,
Bill Richardsone1486c32014-10-30 17:41:51 -0700271 "Show the futility source revision and build date",
272 NULL);
273
Bill Richardson36386252014-10-14 20:58:41 -0700274int run_command(const struct futil_cmd_t *cmd, int argc, char *argv[])
275{
276 /* Handle the "CMD --help" case ourselves */
277 if (2 == argc && 0 == strcmp(argv[1], "--help")) {
278 char *fake_argv[] = {"help",
279 (char *)cmd->name,
280 NULL};
281 return do_help(2, fake_argv);
282 }
283
284 return cmd->handler(argc, argv);
285}
286
287static char *simple_basename(char *str)
288{
289 char *s = strrchr(str, '/');
290 if (s)
291 s++;
292 else
293 s = str;
294 return s;
295}
296
Bill Richardsonfeb25182013-03-07 12:54:29 -0800297/* Here we go */
Bill Richardsonfeb25182013-03-07 12:54:29 -0800298int main(int argc, char *argv[], char *envp[])
299{
Bill Richardson36386252014-10-14 20:58:41 -0700300 char *progname;
Bill Richardson779796f2014-09-23 11:47:40 -0700301 const struct futil_cmd_t *cmd;
Bill Richardson1eae8732015-02-05 12:36:15 -0800302 int i, errorcnt = 0;
303 int vb_ver = VBOOT_VERSION_ALL;
304 struct option long_opts[] = {
305 {"vb1" , 0, &vb_ver, VBOOT_VERSION_1_0},
306 {"vb21", 0, &vb_ver, VBOOT_VERSION_2_1},
307 { 0, 0, 0, 0},
308 };
Bill Richardsonfeb25182013-03-07 12:54:29 -0800309
Bill Richardson31d95c22014-08-24 22:07:17 -0700310 log_args(argc, argv);
Bill Richardsonfeb25182013-03-07 12:54:29 -0800311
Bill Richardson31d95c22014-08-24 22:07:17 -0700312 /* How were we invoked? */
Bill Richardson36386252014-10-14 20:58:41 -0700313 progname = simple_basename(argv[0]);
Bill Richardsonfeb25182013-03-07 12:54:29 -0800314
Bill Richardson36386252014-10-14 20:58:41 -0700315 /* See if the program name is a command we recognize */
Bill Richardson779796f2014-09-23 11:47:40 -0700316 cmd = find_command(progname);
Bill Richardsonf242ad02014-12-12 12:03:29 -0800317 if (cmd)
Bill Richardson1eae8732015-02-05 12:36:15 -0800318 /* Yep, just do that */
Bill Richardson36386252014-10-14 20:58:41 -0700319 return run_command(cmd, argc, argv);
Bill Richardsonfeb25182013-03-07 12:54:29 -0800320
Bill Richardson1eae8732015-02-05 12:36:15 -0800321 /* Parse the global options, stopping at the first non-option. */
322 opterr = 0; /* quiet, you. */
323 while ((i = getopt_long(argc, argv, "+:", long_opts, NULL)) != -1) {
324 switch (i) {
325 case '?':
326 if (optopt)
327 fprintf(stderr, "Unrecognized option: -%c\n",
328 optopt);
329 else
330 fprintf(stderr, "Unrecognized option: %s\n",
331 argv[optind - 1]);
332 errorcnt++;
333 break;
334 case ':':
335 fprintf(stderr, "Missing argument to -%c\n", optopt);
336 errorcnt++;
337 break;
338 case 0: /* handled option */
339 break;
340 default:
341 Debug("i=%d\n", i);
342 DIE;
343 }
344 }
345 vboot_version = vb_ver;
346
347 /* Reset the getopt state so commands can parse their own options. */
348 argc -= optind;
349 argv += optind;
350 optind = 0;
351
352 /* We require a command name. */
353 if (errorcnt || argc < 1) {
Bill Richardson31d95c22014-08-24 22:07:17 -0700354 do_help(0, 0);
Bill Richardson36386252014-10-14 20:58:41 -0700355 return 1;
Bill Richardson31d95c22014-08-24 22:07:17 -0700356 }
Bill Richardsonfeb25182013-03-07 12:54:29 -0800357
Bill Richardson36386252014-10-14 20:58:41 -0700358 /* For reasons I've forgotten, treat /blah/blah/CMD the same as CMD */
359 progname = simple_basename(argv[0]);
Bill Richardson36386252014-10-14 20:58:41 -0700360
361 /* Do we recognize the command? */
362 cmd = find_command(progname);
363 if (cmd)
364 return run_command(cmd, argc, argv);
365
366 /* Nope. We've no clue what we're being asked to do. */
367 do_help(0, 0);
Bill Richardson31d95c22014-08-24 22:07:17 -0700368 return 1;
Bill Richardsonfeb25182013-03-07 12:54:29 -0800369}