futility: Let each command provide its own help

Instead of a separate help function for each command, let's just
require each command to handle a --help option. This will make it
easier to layer the commands (for example, "sign" could have
several subcommand variants, each with its own help).

BUG=none
BRANCH=none
TEST=make runtests

I also compared the result of running "futility help CMD" before
and after this change. The help still shows up correctly.

Change-Id: I5c58176f32b41b0a2c2b8f0afb17dddd80fddc70
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/260495
Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
Bill Richardson 2015-03-11 11:21:47 -07:00 committed by ChromeOS Commit Bot
parent 49a422fab9
commit 01466d36af
15 changed files with 172 additions and 94 deletions

View File

@ -1422,7 +1422,7 @@ TEST_DEPS += ${TEST_OBJS:%.o=%.o.d}
SRCDIRPAT=$(subst /,\/,${SRCDIR}/)
# Note: vboot 2.0 is deprecated, so don't index those files
${BUILD}/cscope.files: test_setup
${BUILD}/cscope.files: all test_setup
${Q}rm -f $@
${Q}cat ${ALL_DEPS} | tr -d ':\\' | tr ' ' '\012' | \
grep -v /lib20/ | \

View File

@ -31,6 +31,7 @@ enum {
OPT_DESC,
OPT_ID,
OPT_HASH_ALG,
OPT_HELP,
};
#define DEFAULT_VERSION 1
@ -48,6 +49,7 @@ static const struct option long_opts[] = {
{"desc", 1, 0, OPT_DESC},
{"id", 1, 0, OPT_ID},
{"hash_alg", 1, 0, OPT_HASH_ALG},
{"help", 0, 0, OPT_HELP},
{NULL, 0, 0, 0}
};
@ -331,6 +333,9 @@ static int do_create(int argc, char *argv[])
errorcnt++;
}
break;
case OPT_HELP:
print_help(argc, argv);
return !!errorcnt;
case '?':
if (optopt)
@ -406,7 +411,5 @@ static int do_create(int argc, char *argv[])
return r;
}
DECLARE_FUTIL_COMMAND(create, do_create,
VBOOT_VERSION_ALL,
"Create a keypair from an RSA .pem file",
print_help);
DECLARE_FUTIL_COMMAND(create, do_create, VBOOT_VERSION_ALL,
"Create a keypair from an RSA .pem file");

View File

@ -5,6 +5,7 @@
*/
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
@ -411,6 +412,13 @@ static void print_help(int argc, char *argv[])
printf(usage, argv[0]);
}
enum {
OPT_HELP = 1000,
};
static const struct option long_opts[] = {
{"help", 0, 0, OPT_HELP},
{NULL, 0, 0, 0}
};
static int do_dump_fmap(int argc, char *argv[])
{
int c;
@ -421,7 +429,7 @@ static int do_dump_fmap(int argc, char *argv[])
int retval = 1;
opterr = 0; /* quiet, you */
while ((c = getopt(argc, argv, ":xpFhH")) != -1) {
while ((c = getopt_long(argc, argv, ":xpFhH", long_opts, 0)) != -1) {
switch (c) {
case 'x':
opt_extract = 1;
@ -439,6 +447,9 @@ static int do_dump_fmap(int argc, char *argv[])
opt_format = FMT_HUMAN;
opt_overlap++;
break;
case OPT_HELP:
print_help(argc, argv);
return 0;
case '?':
fprintf(stderr, "%s: unrecognized switch: -%c\n",
argv[0], optopt);
@ -510,7 +521,5 @@ static int do_dump_fmap(int argc, char *argv[])
return retval;
}
DECLARE_FUTIL_COMMAND(dump_fmap, do_dump_fmap,
VBOOT_VERSION_ALL,
"Display FMAP contents from a firmware image",
print_help);
DECLARE_FUTIL_COMMAND(dump_fmap, do_dump_fmap, VBOOT_VERSION_ALL,
"Display FMAP contents from a firmware image");

View File

@ -15,10 +15,12 @@
enum {
OPT_KLOADADDR = 1000,
OPT_HELP,
};
static const struct option long_opts[] = {
{"kloadaddr", 1, NULL, OPT_KLOADADDR},
{"help", 0, 0, OPT_HELP},
{NULL, 0, NULL, 0}
};
@ -29,7 +31,7 @@ static void print_help(int argc, char *argv[])
"KERNEL_PARTITION\n\n", argv[0]);
}
static int do_dump_kernel_config(int argc, char *argv[])
static int do_dump_kern_cfg(int argc, char *argv[])
{
char *infile = NULL;
char *config = NULL;
@ -58,6 +60,10 @@ static int do_dump_kernel_config(int argc, char *argv[])
parse_error = 1;
}
break;
case OPT_HELP:
print_help(argc, argv);
return 0;
}
}
@ -87,7 +93,6 @@ static int do_dump_kernel_config(int argc, char *argv[])
return 0;
}
DECLARE_FUTIL_COMMAND(dump_kernel_config, do_dump_kernel_config,
VBOOT_VERSION_ALL,
"Prints the kernel command line",
print_help);
DECLARE_FUTIL_COMMAND(dump_kernel_config, do_dump_kern_cfg, VBOOT_VERSION_ALL,
"Prints the kernel command line");

View File

@ -60,6 +60,7 @@ enum {
OPT_HWID = 1000,
OPT_FLAGS,
OPT_DIGEST,
OPT_HELP,
};
/* Command line options */
@ -75,6 +76,7 @@ static struct option long_opts[] = {
{"hwid", 0, NULL, OPT_HWID},
{"flags", 0, NULL, OPT_FLAGS},
{"digest", 0, NULL, OPT_DIGEST},
{"help", 0, NULL, OPT_HELP},
{NULL, 0, NULL, 0},
};
@ -410,6 +412,10 @@ static int do_gbb_utility(int argc, char *argv[])
case OPT_DIGEST:
sel_digest = 1;
break;
case OPT_HELP:
print_help(argc, argv);
return !!errorcnt;
case '?':
errorcnt++;
if (optopt)
@ -637,7 +643,5 @@ static int do_gbb_utility(int argc, char *argv[])
return !!errorcnt;
}
DECLARE_FUTIL_COMMAND(gbb_utility, do_gbb_utility,
VBOOT_VERSION_ALL,
"Manipulate the Google Binary Block (GBB)",
print_help);
DECLARE_FUTIL_COMMAND(gbb_utility, do_gbb_utility, VBOOT_VERSION_ALL,
"Manipulate the Google Binary Block (GBB)");

View File

@ -44,8 +44,12 @@ static void print_help(int argc, char *argv[])
printf(usage, argv[0], argv[0]);
}
enum {
OPT_HELP = 1000,
};
static const struct option long_opts[] = {
/* name hasarg *flag val */
{"help", 0, NULL, OPT_HELP},
{NULL, 0, NULL, 0},
};
static char *short_opts = ":o:";
@ -105,6 +109,9 @@ static int do_load_fmap(int argc, char *argv[])
case 'o':
outfile = optarg;
break;
case OPT_HELP:
print_help(argc, argv);
return !!errorcnt;
case '?':
if (optopt)
fprintf(stderr, "Unrecognized option: -%c\n",
@ -198,7 +205,6 @@ done_file:
return !!errorcnt;
}
DECLARE_FUTIL_COMMAND(load_fmap, do_load_fmap,
VBOOT_VERSION_ALL,
"Replace the contents of specified FMAP areas",
print_help);
DECLARE_FUTIL_COMMAND(load_fmap, do_load_fmap, VBOOT_VERSION_ALL,
"Replace the contents of specified FMAP areas");

View File

@ -96,7 +96,13 @@ static void print_digest(const uint8_t *buf, int len)
printf("%02x", buf[i]);
}
enum {
OPT_HELP = 1000,
};
static const struct option long_opts[] = {
{"help", 0, 0, OPT_HELP},
{NULL, 0, 0, 0}
};
static int do_pcr(int argc, char *argv[])
{
uint8_t accum[SHA256_DIGEST_SIZE * 2];
@ -109,7 +115,7 @@ static int do_pcr(int argc, char *argv[])
int i;
opterr = 0; /* quiet, you */
while ((i = getopt(argc, argv, ":i2")) != -1) {
while ((i = getopt_long(argc, argv, ":i2", long_opts, NULL)) != -1) {
switch (i) {
case 'i':
opt_init = 1;
@ -118,6 +124,9 @@ static int do_pcr(int argc, char *argv[])
digest_alg = SHA256_DIGEST_ALGORITHM;
digest_size = SHA256_DIGEST_SIZE;
break;
case OPT_HELP:
print_help(argc, argv);
return !!errorcnt;
case '?':
if (optopt)
fprintf(stderr, "Unrecognized option: -%c\n",
@ -181,7 +190,5 @@ static int do_pcr(int argc, char *argv[])
return 0;
}
DECLARE_FUTIL_COMMAND(pcr, do_pcr,
VBOOT_VERSION_ALL,
"Simulate a TPM PCR extension operation",
print_help);
DECLARE_FUTIL_COMMAND(pcr, do_pcr, VBOOT_VERSION_ALL,
"Simulate a TPM PCR extension operation");

View File

@ -557,6 +557,7 @@ int futil_cb_show_begin(struct futil_traverse_state_s *state)
enum no_short_opts {
OPT_PADDING = 1000,
OPT_HELP,
};
static const char usage[] = "\n"
@ -597,6 +598,7 @@ static const struct option long_opts[] = {
{"fv", 1, 0, 'f'},
{"pad", 1, NULL, OPT_PADDING},
{"verify", 0, &option.strict, 1},
{"help", 0, NULL, OPT_HELP},
{NULL, 0, NULL, 0},
};
static char *short_opts = ":f:k:t";
@ -667,6 +669,9 @@ static int do_show(int argc, char *argv[])
errorcnt++;
}
break;
case OPT_HELP:
print_help(argc, argv);
return !!errorcnt;
case '?':
if (optopt)
@ -746,10 +751,8 @@ done:
return !!errorcnt;
}
DECLARE_FUTIL_COMMAND(show, do_show,
VBOOT_VERSION_ALL,
"Display the content of various binary components",
print_help);
DECLARE_FUTIL_COMMAND(show, do_show, VBOOT_VERSION_ALL,
"Display the content of various binary components");
static int do_verify(int argc, char *argv[])
{
@ -759,5 +762,4 @@ static int do_verify(int argc, char *argv[])
DECLARE_FUTIL_COMMAND(verify, do_verify,
VBOOT_VERSION_ALL,
"Verify the signatures of various binary components",
print_help);
"Verify the signatures of various binary components");

View File

@ -666,6 +666,7 @@ enum no_short_opts {
OPT_PEM_SIGNPRIV,
OPT_PEM_ALGO,
OPT_PEM_EXTERNAL,
OPT_HELP,
};
static const struct option long_opts[] = {
@ -693,6 +694,7 @@ static const struct option long_opts[] = {
{"pem_algo", 1, NULL, OPT_PEM_ALGO},
{"pem_external", 1, NULL, OPT_PEM_EXTERNAL},
{"vblockonly", 0, &option.vblockonly, 1},
{"help", 0, NULL, OPT_HELP},
{NULL, 0, NULL, 0},
};
static char *short_opts = ":s:b:k:S:B:v:f:d:l:";
@ -856,6 +858,9 @@ static int do_sign(int argc, char *argv[])
case OPT_PEM_EXTERNAL:
option.pem_external = optarg;
break;
case OPT_HELP:
print_help(argc, argv);
return !!errorcnt;
case '?':
if (optopt)
@ -1077,7 +1082,6 @@ done:
return !!errorcnt;
}
DECLARE_FUTIL_COMMAND(sign, do_sign,
VBOOT_VERSION_ALL,
"Sign / resign various binary components",
print_help);
DECLARE_FUTIL_COMMAND(sign, do_sign, VBOOT_VERSION_ALL,
"Sign / resign various binary components");

View File

@ -30,6 +30,7 @@ enum {
OPT_FV,
OPT_KERNELKEY,
OPT_FLAGS,
OPT_HELP,
};
static const struct option long_opts[] = {
@ -42,6 +43,7 @@ static const struct option long_opts[] = {
{"fv", 1, 0, OPT_FV},
{"kernelkey", 1, 0, OPT_KERNELKEY},
{"flags", 1, 0, OPT_FLAGS},
{"help", 0, 0, OPT_HELP},
{NULL, 0, 0, 0}
};
@ -322,6 +324,9 @@ static int do_vbutil_firmware(int argc, char *argv[])
printf("Unknown option\n");
parse_error = 1;
break;
case OPT_HELP:
print_help(argc, argv);
return !!parse_error;
case OPT_MODE_VBLOCK:
case OPT_MODE_VERIFY:
@ -385,7 +390,5 @@ static int do_vbutil_firmware(int argc, char *argv[])
}
}
DECLARE_FUTIL_COMMAND(vbutil_firmware, do_vbutil_firmware,
VBOOT_VERSION_1_0,
"Verified boot firmware utility",
print_help);
DECLARE_FUTIL_COMMAND(vbutil_firmware, do_vbutil_firmware, VBOOT_VERSION_1_0,
"Verified boot firmware utility");

View File

@ -64,6 +64,7 @@ enum {
OPT_MINVERSION,
OPT_VMLINUZ_OUT,
OPT_FLAGS,
OPT_HELP,
};
static const struct option long_opts[] = {
@ -87,6 +88,7 @@ static const struct option long_opts[] = {
{"verbose", 0, &opt_verbose, 1},
{"vmlinuz-out", 1, 0, OPT_VMLINUZ_OUT},
{"flags", 1, 0, OPT_FLAGS},
{"help", 0, 0, OPT_HELP},
{NULL, 0, 0, 0}
};
@ -270,6 +272,9 @@ static int do_vbutil_kernel(int argc, char *argv[])
case 0:
/* silently handled option */
break;
case OPT_HELP:
print_help(argc, argv);
return !!parse_error;
case OPT_MODE_PACK:
case OPT_MODE_REPACK:
@ -646,7 +651,5 @@ static int do_vbutil_kernel(int argc, char *argv[])
return 1;
}
DECLARE_FUTIL_COMMAND(vbutil_kernel, do_vbutil_kernel,
VBOOT_VERSION_1_0,
"Creates, signs, and verifies the kernel partition",
print_help);
DECLARE_FUTIL_COMMAND(vbutil_kernel, do_vbutil_kernel, VBOOT_VERSION_1_0,
"Creates, signs, and verifies the kernel partition");

View File

@ -26,6 +26,7 @@ enum {
OPT_MODE_PACK,
OPT_MODE_UNPACK,
OPT_COPYTO,
OPT_HELP,
};
static const struct option long_opts[] = {
@ -35,6 +36,7 @@ static const struct option long_opts[] = {
{"pack", 1, 0, OPT_MODE_PACK},
{"unpack", 1, 0, OPT_MODE_UNPACK},
{"copyto", 1, 0, OPT_COPYTO},
{"help", 0, 0, OPT_HELP},
{NULL, 0, 0, 0}
};
@ -180,6 +182,9 @@ static int do_vbutil_key(int argc, char *argv[])
VbExError("Unknown option\n");
parse_error = 1;
break;
case OPT_HELP:
print_help(argc, argv);
return !!parse_error;
case OPT_INKEY:
infile = optarg;
@ -234,7 +239,5 @@ static int do_vbutil_key(int argc, char *argv[])
}
}
DECLARE_FUTIL_COMMAND(vbutil_key, do_vbutil_key,
VBOOT_VERSION_1_0,
"Wraps RSA keys with vboot headers",
print_help);
DECLARE_FUTIL_COMMAND(vbutil_key, do_vbutil_key, VBOOT_VERSION_1_0,
"Wraps RSA keys with vboot headers");

View File

@ -28,6 +28,7 @@ enum {
OPT_PEM_ALGORITHM,
OPT_EXTERNAL_SIGNER,
OPT_FLAGS,
OPT_HELP,
};
static const struct option long_opts[] = {
@ -40,6 +41,7 @@ static const struct option long_opts[] = {
{"pem_algorithm", 1, 0, OPT_PEM_ALGORITHM},
{"externalsigner", 1, 0, OPT_EXTERNAL_SIGNER},
{"flags", 1, 0, OPT_FLAGS},
{"help", 0, 0, OPT_HELP},
{NULL, 0, 0, 0}
};
@ -244,6 +246,9 @@ static int do_vbutil_keyblock(int argc, char *argv[])
printf("Unknown option\n");
parse_error = 1;
break;
case OPT_HELP:
print_help(argc, argv);
return !!parse_error;
case OPT_MODE_PACK:
case OPT_MODE_UNPACK:
@ -331,7 +336,5 @@ static int do_vbutil_keyblock(int argc, char *argv[])
}
}
DECLARE_FUTIL_COMMAND(vbutil_keyblock, do_vbutil_keyblock,
VBOOT_VERSION_1_0,
"Creates, signs, and verifies a keyblock",
print_help);
DECLARE_FUTIL_COMMAND(vbutil_keyblock, do_vbutil_keyblock, VBOOT_VERSION_1_0,
"Creates, signs, and verifies a keyblock");

View File

@ -17,7 +17,6 @@
#include "futility.h"
/******************************************************************************/
/* Logging stuff */
@ -201,7 +200,8 @@ static const struct futil_cmd_t *find_command(const char *name)
const struct futil_cmd_t *const *cmd;
for (cmd = futil_cmds; *cmd; cmd++)
if (0 == strcmp((*cmd)->name, name))
if (((*cmd)->version & vboot_version) &&
!strcmp((*cmd)->name, name))
return *cmd;
return NULL;
@ -217,18 +217,29 @@ static void list_commands(void)
(*cmd)->name, (*cmd)->shorthelp);
}
static int run_command(const struct futil_cmd_t *cmd, int argc, char *argv[])
{
int i;
Debug("%s(\"%s\") ...\n", __func__, cmd->name);
for (i = 0; i < argc; i++)
Debug(" argv[%d] = \"%s\"\n", i, argv[i]);
return cmd->handler(argc, argv);
}
static int do_help(int argc, char *argv[])
{
const struct futil_cmd_t *cmd;
const char *vstr;
if (argc >= 2) {
/* Help about a known command? */
if (argc > 1) {
cmd = find_command(argv[1]);
if (cmd) {
printf("\n%s - %s\n", argv[1], cmd->shorthelp);
if (cmd->longhelp)
cmd->longhelp(argc - 1, argv + 1);
return 0;
/* Let the command provide its own help */
argv[0] = argv[1];
argv[1] = "--help";
return run_command(cmd, argc, argv);
}
}
@ -256,31 +267,21 @@ static int do_help(int argc, char *argv[])
}
DECLARE_FUTIL_COMMAND(help, do_help, VBOOT_VERSION_ALL,
"Show a bit of help (you're looking at it)",
NULL);
"Show a bit of help (you're looking at it)");
static const char ver_help[] =
"Show the futility source revision and build date";
static int do_version(int argc, char *argv[])
{
printf("%s\n", futility_version);
if (argc > 1)
printf("%s - %s\n", argv[0], ver_help);
else
printf("%s\n", futility_version);
return 0;
}
DECLARE_FUTIL_COMMAND(version, do_version, VBOOT_VERSION_ALL,
"Show the futility source revision and build date",
NULL);
static int run_command(const struct futil_cmd_t *cmd, int argc, char *argv[])
{
/* Handle the "CMD --help" case ourselves */
if (2 == argc && 0 == strcmp(argv[1], "--help")) {
char *fake_argv[] = {"help",
(char *)cmd->name,
NULL};
return do_help(2, fake_argv);
}
return cmd->handler(argc, argv);
}
ver_help);
static char *simple_basename(char *str)
{
@ -293,16 +294,19 @@ static char *simple_basename(char *str)
}
/* Here we go */
#define OPT_HELP 1000
int main(int argc, char *argv[], char *envp[])
{
char *progname;
const struct futil_cmd_t *cmd;
int i, errorcnt = 0;
int vb_ver = VBOOT_VERSION_ALL;
int helpind = 0;
struct option long_opts[] = {
{"debug", 0, &debugging_enabled, 1},
{"vb1" , 0, &vb_ver, VBOOT_VERSION_1_0},
{"vb21", 0, &vb_ver, VBOOT_VERSION_2_1},
{"help", 0, 0, OPT_HELP},
{ 0, 0, 0, 0},
};
@ -313,14 +317,20 @@ int main(int argc, char *argv[], char *envp[])
/* See if the program name is a command we recognize */
cmd = find_command(progname);
if (cmd)
if (cmd) {
/* Yep, just do that */
return run_command(cmd, argc, argv);
}
/* Parse the global options, stopping at the first non-option. */
opterr = 0; /* quiet, you. */
while ((i = getopt_long(argc, argv, "+:", long_opts, NULL)) != -1) {
switch (i) {
case OPT_HELP:
/* Remember where we found this option */
/* Note: this might be GNU-specific */
helpind = optind - 1;
break;
case '?':
if (optopt)
fprintf(stderr, "Unrecognized option: -%c\n",
@ -343,26 +353,38 @@ int main(int argc, char *argv[], char *envp[])
}
vboot_version = vb_ver;
/* Reset the getopt state so commands can parse their own options. */
argc -= optind;
argv += optind;
optind = 0;
/*
* Translate "--help" in the args to "help" as the first parameter,
* by rearranging argv[].
*/
if (helpind) {
int i;
optind--;
for (i = helpind; i < optind; i++)
argv[i] = argv[i + 1];
argv[i] = "help";
}
/* We require a command name. */
if (errorcnt || argc < 1) {
do_help(0, 0);
if (errorcnt || argc == optind) {
do_help(1, argv);
return 1;
}
/* For reasons I've forgotten, treat /blah/blah/CMD the same as CMD */
progname = simple_basename(argv[0]);
argv[optind] = simple_basename(argv[optind]);
/* Do we recognize the command? */
cmd = find_command(progname);
if (cmd)
cmd = find_command(argv[optind]);
if (cmd) {
/* Reset so commands can parse their own options */
argc -= optind;
argv += optind;
optind = 0;
return run_command(cmd, argc, argv);
}
/* Nope. We've no clue what we're being asked to do. */
do_help(0, 0);
do_help(1, argv);
return 1;
}

View File

@ -44,21 +44,25 @@ enum vboot_version vboot_version;
/* Here's a structure to define the commands that futility implements. */
struct futil_cmd_t {
/* String used to invoke this command */
const char *const name;
/* Function to do the work. Returns 0 on success.
* Called with argv[0] == "name".
* It should handle its own "--help" option. */
int (*const handler) (int argc, char **argv);
/* Supported ABIs */
enum vboot_version version;
/* One-line summary of what it does */
const char *const shorthelp;
void (*longhelp) (int argc, char *argv[]); /* argv[0] is the command */
};
/* Macro to define a command */
#define DECLARE_FUTIL_COMMAND(NAME, HANDLER, VERSION, SHORTHELP, LONGHELP) \
#define DECLARE_FUTIL_COMMAND(NAME, HANDLER, VERSION, SHORTHELP) \
const struct futil_cmd_t __cmd_##NAME = { \
.name = #NAME, \
.handler = HANDLER, \
.version = VERSION, \
.shorthelp = SHORTHELP, \
.longhelp = LONGHELP, \
}
/* This is the list of pointers to all commands. */