From 580765e16aca68132babc09a02b4ea6c220c1988 Mon Sep 17 00:00:00 2001 From: Nguyễn Thái Ngọc Duy Date: Thu, 23 Apr 2009 00:26:07 +1000 Subject: shell/ash: replace shellexec() with shellspawn() --- shell/ash.c | 5 ++ shell/ash_mingw.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ shell/ash_mingw.h | 3 ++ 3 files changed, 156 insertions(+) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 284f49303..7c97e72e2 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -8453,6 +8453,10 @@ evalcommand(union node *cmd, int flags) /* Execute the command. */ switch (cmdentry.cmdtype) { default: +#ifdef __MINGW32__ + shellspawn((const char**)argv, path, cmdentry.u.index, varlist.list); + break; +#else /* Fork off a child process if necessary. */ if (!(flags & EV_EXIT) || trap[0]) { INT_OFF; @@ -8467,6 +8471,7 @@ evalcommand(union node *cmd, int flags) listsetvar(varlist.list, VEXPORT|VSTACK); shellexec(argv, path, cmdentry.u.index); /* NOTREACHED */ +#endif case CMDBUILTIN: cmdenviron = varlist.list; diff --git a/shell/ash_mingw.c b/shell/ash_mingw.c index a412b7210..c36973164 100644 --- a/shell/ash_mingw.c +++ b/shell/ash_mingw.c @@ -893,3 +893,151 @@ subshell_run() die("subshell ended unexpectedly"); } + +static int +tryspawn(const char *cmd, const char **argv, const char * const*envp) +{ + struct child_process cp; + + memset(&cp, 0, sizeof(cp)); + + cp.env = envp; +#if ENABLE_FEATURE_SH_STANDALONE + if (strchr(cmd, '/') == NULL) { + const struct bb_applet *a; + + a = find_applet_by_name(cmd); + if (a) { + const char **new_argv; + const char **argp; + int retval; + + for (argp = argv;*argp;argp++); + new_argv = xmalloc(sizeof(const char *)*(argp - argv + 2)); + new_argv[0] = CONFIG_BUSYBOX_EXEC_PATH; + memcpy(&new_argv[1], &argv[0], (argp - argv + 1)*sizeof(const char*)); + cp.argv = new_argv; + trace_argv_printf(new_argv, "git-box: applet:"); + retval = set_exitstatus(run_command(&cp), new_argv, NULL); + free(new_argv); + return retval; + } + } +#endif + + /* FIXME + * Need to copy vartab atab cmdtable localvars to the subshell + */ + cp.argv = argv; + trace_argv_printf(argv, "git-box: spawn:"); + return set_exitstatus(run_command(&cp), argv, NULL); +} + +static const char * const* +shellspawn_getenv(const struct strlist *newvars) +{ + struct var **vpp; + struct var *vp; + const struct strlist *vlp; + char **ep; + int mask; + int on = VEXPORT; + int off = VUNSET; + + STARTSTACKSTR(ep); + vpp = vartab; + mask = on | off; + do { + for (vp = *vpp; vp; vp = vp->next) { + if ((vp->flags & mask) == on) { + if (ep == stackstrend()) + ep = growstackstr(); + for (vlp = newvars;vlp;vlp = vlp->next) + if (varequal(vlp->text, vp->text)) + break; + if (!vlp) + *ep++ = (char *) vp->text; + } + } + } while (++vpp < vartab + VTABSIZE); + for (vlp = newvars;vlp;vlp = vlp->next) { + if (ep == stackstrend()) + ep = growstackstr(); + *ep++ = vlp->text; + } + if (ep == stackstrend()) + ep = growstackstr(); + *ep++ = NULL; + return grabstackstr(ep); +} + +static int +shellspawn(const char **argv, const char *path, int idx, struct strlist *varlist) +{ + char *cmdname; + int e; + const char* const* envp; + + /*clearredir(1);*/ + /*listsetvar(varlist.list, VEXPORT|VSTACK);*/ + /*envp = listvars(VEXPORT, VUNSET, 0);*/ + envp = shellspawn_getenv(varlist); + if (strchr(argv[0], '/') +#if ENABLE_FEATURE_SH_STANDALONE + || find_applet_by_name(argv[0]) +#endif + ) { + e = tryspawn(argv[0], argv, envp); + } else { + e = ENOENT; + while ((cmdname = padvance(&path, argv[0])) != NULL) { + if (--idx < 0 && pathopt == NULL) { + e = tryspawn(cmdname, argv, envp); + if (e != -1) break; + } + stunalloc(cmdname); + } + } + + if (e == -1) { + e = errno; + switch (e) { + case EACCES: + exitstatus = 126; + break; + case ENOENT: + exitstatus = 127; + break; + default: + exitstatus = 2; + break; + } + ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found")); + } + return e; +} + +static int set_exitstatus(int val, const char **argv,int *out) +{ + if (!out) + out = &exitstatus; + switch (val) { + case -ERR_RUN_COMMAND_WAITPID_WRONG_PID: + if (argv) + ash_msg_and_raise_error("%s: Waitpid on wrong PID",argv[0]); + else + ash_msg_and_raise_error("Waitpid on wrong PID"); + break; + + case -ERR_RUN_COMMAND_WAITPID_SIGNAL: + case -ERR_RUN_COMMAND_WAITPID_NOEXIT: + *out = -val + 128; + return 0; + + default: + *out = -val; + return 0; + } + return -1; +} + diff --git a/shell/ash_mingw.h b/shell/ash_mingw.h index 658c7dae2..b7c53e036 100644 --- a/shell/ash_mingw.h +++ b/shell/ash_mingw.h @@ -12,6 +12,9 @@ static void forkshell_transfer_done(struct forkshell *fs); static void forkshell_cleanup(struct forkshell *fs); static int forkshell(const char *fp, union node *n, int flags); static void subshell_run(); +struct strlist; +static int set_exitstatus(int retval, const char **argv, int *out); +static int shellspawn(const char **argv, const char *path, int idx, struct strlist *varlist); static int subash_fd = -1; static char subash_entry[16]; -- cgit v1.2.3-55-g6feb