diff options
author | Bill Richardson <wfrichar@chromium.org> | 2015-03-11 11:21:47 -0700 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-03-18 23:07:36 +0000 |
commit | 01466d36afd10b3947de475bc9b4fb23848e81ce (patch) | |
tree | 331e22905fc988641f111cdb5bd49b7970207290 | |
parent | 49a422fab9afb3f013ee6115738c7e13d9ec8191 (diff) | |
download | vboot-01466d36afd10b3947de475bc9b4fb23848e81ce.tar.gz |
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>
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | futility/cmd_create.c | 11 | ||||
-rw-r--r-- | futility/cmd_dump_fmap.c | 19 | ||||
-rw-r--r-- | futility/cmd_dump_kernel_config.c | 15 | ||||
-rw-r--r-- | futility/cmd_gbb_utility.c | 12 | ||||
-rw-r--r-- | futility/cmd_load_fmap.c | 14 | ||||
-rw-r--r-- | futility/cmd_pcr.c | 19 | ||||
-rw-r--r-- | futility/cmd_show.c | 14 | ||||
-rw-r--r-- | futility/cmd_sign.c | 12 | ||||
-rw-r--r-- | futility/cmd_vbutil_firmware.c | 11 | ||||
-rw-r--r-- | futility/cmd_vbutil_kernel.c | 11 | ||||
-rw-r--r-- | futility/cmd_vbutil_key.c | 11 | ||||
-rw-r--r-- | futility/cmd_vbutil_keyblock.c | 11 | ||||
-rw-r--r-- | futility/futility.c | 94 | ||||
-rw-r--r-- | futility/futility.h | 10 |
15 files changed, 172 insertions, 94 deletions
@@ -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/ | \ diff --git a/futility/cmd_create.c b/futility/cmd_create.c index 6138f428..c919eab3 100644 --- a/futility/cmd_create.c +++ b/futility/cmd_create.c @@ -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"); diff --git a/futility/cmd_dump_fmap.c b/futility/cmd_dump_fmap.c index e57bbf7c..b512fdca 100644 --- a/futility/cmd_dump_fmap.c +++ b/futility/cmd_dump_fmap.c @@ -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"); diff --git a/futility/cmd_dump_kernel_config.c b/futility/cmd_dump_kernel_config.c index d1a91fdc..a46a19d1 100644 --- a/futility/cmd_dump_kernel_config.c +++ b/futility/cmd_dump_kernel_config.c @@ -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"); + diff --git a/futility/cmd_gbb_utility.c b/futility/cmd_gbb_utility.c index 1053eb2a..df0a51db 100644 --- a/futility/cmd_gbb_utility.c +++ b/futility/cmd_gbb_utility.c @@ -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)"); diff --git a/futility/cmd_load_fmap.c b/futility/cmd_load_fmap.c index 7522759d..897a0850 100644 --- a/futility/cmd_load_fmap.c +++ b/futility/cmd_load_fmap.c @@ -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"); + diff --git a/futility/cmd_pcr.c b/futility/cmd_pcr.c index 0de234dc..241bfb2f 100644 --- a/futility/cmd_pcr.c +++ b/futility/cmd_pcr.c @@ -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"); diff --git a/futility/cmd_show.c b/futility/cmd_show.c index 660bbcb2..e24e7cf7 100644 --- a/futility/cmd_show.c +++ b/futility/cmd_show.c @@ -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"); diff --git a/futility/cmd_sign.c b/futility/cmd_sign.c index 104fa2e1..bfd3a00d 100644 --- a/futility/cmd_sign.c +++ b/futility/cmd_sign.c @@ -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"); + diff --git a/futility/cmd_vbutil_firmware.c b/futility/cmd_vbutil_firmware.c index ce2f0a61..4e312b29 100644 --- a/futility/cmd_vbutil_firmware.c +++ b/futility/cmd_vbutil_firmware.c @@ -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"); diff --git a/futility/cmd_vbutil_kernel.c b/futility/cmd_vbutil_kernel.c index 635acdc4..8ddc5ef2 100644 --- a/futility/cmd_vbutil_kernel.c +++ b/futility/cmd_vbutil_kernel.c @@ -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"); diff --git a/futility/cmd_vbutil_key.c b/futility/cmd_vbutil_key.c index cfc21b7f..840a14df 100644 --- a/futility/cmd_vbutil_key.c +++ b/futility/cmd_vbutil_key.c @@ -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"); diff --git a/futility/cmd_vbutil_keyblock.c b/futility/cmd_vbutil_keyblock.c index 738ad4a2..4be6b2d0 100644 --- a/futility/cmd_vbutil_keyblock.c +++ b/futility/cmd_vbutil_keyblock.c @@ -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"); diff --git a/futility/futility.c b/futility/futility.c index 2a7b6bcf..91b7cdc6 100644 --- a/futility/futility.c +++ b/futility/futility.c @@ -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; } diff --git a/futility/futility.h b/futility/futility.h index c28f40e6..e0754d86 100644 --- a/futility/futility.h +++ b/futility/futility.h @@ -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. */ |