diff --git a/common/command.c b/common/command.c index ab02ed532..de2c3a9cd 100644 --- a/common/command.c +++ b/common/command.c @@ -91,8 +91,9 @@ int execute_command(int argc, char **argv) { struct command *cmdtp; int ret; + struct getopt_context gc; - getopt_reset(); + getopt_context_store(&gc); /* Look up command in command table */ if ((cmdtp = find_cmd(argv[0]))) { @@ -100,17 +101,20 @@ int execute_command(int argc, char **argv) ret = cmdtp->cmd(cmdtp, argc, argv); if (ret == COMMAND_ERROR_USAGE) { barebox_cmd_usage(cmdtp); - return COMMAND_ERROR; + ret = COMMAND_ERROR; } - return ret; } else { #ifdef CONFIG_CMD_HELP printf ("Unknown command '%s' - try 'help'\n", argv[0]); #else printf ("Unknown command '%s'\n", argv[0]); #endif - return -1; /* give up after bad command */ + ret = -1; /* give up after bad command */ } + + getopt_context_restore(&gc); + + return ret; } int register_command(struct command *cmd) diff --git a/common/hush.c b/common/hush.c index b59e59dd1..97dc13cd2 100644 --- a/common/hush.c +++ b/common/hush.c @@ -502,9 +502,10 @@ static void setup_string_in_str(struct in_str *i, const char *s) static int builtin_getopt(struct p_context *ctx, struct child_prog *child) { char *optstring, *var; - int opt; + int opt, ret = 0; char opta[2]; struct option *o; + struct getopt_context gc; if (child->argc != 3) return -2 - 1; @@ -512,7 +513,7 @@ static int builtin_getopt(struct p_context *ctx, struct child_prog *child) optstring = child->argv[1]; var = child->argv[2]; - getopt_reset(); + getopt_context_store(&gc); if (!ctx->options_parsed) { while((opt = getopt(ctx->global_argc, ctx->global_argv, optstring)) > 0) { @@ -525,8 +526,10 @@ static int builtin_getopt(struct p_context *ctx, struct child_prog *child) ctx->options_parsed = 1; - if (list_empty(&ctx->options)) - return -1; + if (list_empty(&ctx->options)) { + ret = -1; + goto out; + } o = list_first_entry(&ctx->options, struct option, list); @@ -538,8 +541,10 @@ static int builtin_getopt(struct p_context *ctx, struct child_prog *child) free(o->optarg); list_del(&o->list); free(o); +out: + getopt_context_restore(&gc); - return 0; + return ret; } BAREBOX_MAGICVAR(OPTARG, "optarg for hush builtin getopt"); diff --git a/include/getopt.h b/include/getopt.h index 4f43ac409..ed55e22fd 100644 --- a/include/getopt.h +++ b/include/getopt.h @@ -40,10 +40,20 @@ extern char *optarg; int getopt(int argc, char *argv[], char *optstring); +struct getopt_context { + int opterr; + int optind; + int optopt; + int nonopts; + int optindex; + char *optarg; +}; + /* * We do not start a new process for each getopt() run, so we - * need this function to reset the static variables. + * need this function to save and restore the context. */ -void getopt_reset(void); +void getopt_context_store(struct getopt_context *ctx); +void getopt_context_restore(struct getopt_context *ctx); #endif /* __GETOPT_H */ diff --git a/lib/getopt.c b/lib/getopt.c index 5c35ee17d..043ba054a 100644 --- a/lib/getopt.c +++ b/lib/getopt.c @@ -34,12 +34,30 @@ EXPORT_SYMBOL(optarg); static int optindex = 1; /* option index in the current argv[] element */ static int nonopts = 0; /* number of nonopts found */ -void getopt_reset(void) +void getopt_context_store(struct getopt_context *gc) { + gc->optind = optind; + gc->opterr = opterr; + gc->optopt = optopt; + gc->optarg = optarg; + gc->nonopts = nonopts; + gc->optindex = optindex; + optind = opterr = optindex = 1; nonopts = 0; } -EXPORT_SYMBOL(getopt_reset); +EXPORT_SYMBOL(getopt_context_store); + +void getopt_context_restore(struct getopt_context *gc) +{ + optind = gc->optind; + opterr = gc->opterr; + optopt = gc->optopt; + optarg = gc->optarg; + nonopts = gc->nonopts; + optindex = gc->optindex; +} +EXPORT_SYMBOL(getopt_context_restore); int getopt(int argc, char *argv[], char *optstring) {