diff options
author | Rob Landley <rob@landley.net> | 2020-03-11 22:09:15 -0500 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2020-03-11 22:09:15 -0500 |
commit | 114541b98e755bd28a9386008a352065bd942875 (patch) | |
tree | 6a90b20d308978d354e2cf0cea4c5e1446febfb0 | |
parent | 42be28f77458618c128d32d9273f6eca7f73a971 (diff) | |
download | toybox-114541b98e755bd28a9386008a352065bd942875.tar.gz |
Redo NOFORK plumbing so commands like eval/unset can access/edit shell state.
-rw-r--r-- | main.c | 2 | ||||
-rw-r--r-- | toys.h | 11 | ||||
-rw-r--r-- | toys/other/help.c | 2 | ||||
-rw-r--r-- | toys/pending/sh.c | 55 |
4 files changed, 52 insertions, 18 deletions
@@ -68,7 +68,7 @@ static void unknown(char *name) } // Setup toybox global state for this command. -static void toy_singleinit(struct toy_list *which, char *argv[]) +void toy_singleinit(struct toy_list *which, char *argv[]) { toys.which = which; toys.argv = argv; @@ -82,6 +82,7 @@ struct toy_list *toy_find(char *name); void toy_init(struct toy_list *which, char *argv[]); +void toy_singleinit(struct toy_list *which, char *argv[]); void toy_exec(char *argv[]); // Array of available commands @@ -101,18 +102,18 @@ extern struct toy_context { char **optargs; // Arguments left over from get_optflags() unsigned long long optflags; // Command line option flags from get_optflags() int optc; // Count of optargs - int envc; // Count of original environ entries - int old_umask; // Old umask preserved by TOYFLAG_UMASK short toycount; // Total number of commands in this build - short signal; // generic_signal() records what signal it saw here - int signalfd; // and writes signal to this fd, if set char exitval; // Value error_exit feeds to exit() char wasroot; // dropped setuid - // This is at the end so toy_init() doesn't zero it. + // toy_init() should not zero past here. sigjmp_buf *rebound; // siglongjmp here instead of exit when do_rebound struct arg_list *xexit; // atexit() functions for xexit(), set by sigatexit() void *stacktop; // nested toy_exec() call count, or 0 if vforked + int envc; // Count of original environ entries + int old_umask; // Old umask preserved by TOYFLAG_UMASK + short signal; // generic_signal() records what signal it saw here + int signalfd; // and writes signal to this fd, if set } toys; // Two big temporary buffers: one for use by commands, one for library functions diff --git a/toys/other/help.c b/toys/other/help.c index 686f862b..179dd4e7 100644 --- a/toys/other/help.c +++ b/toys/other/help.c @@ -42,7 +42,7 @@ void help_main(void) { int i; - // If called with no arguments as a builtin form the shell, show all builtins + // If called with no arguments as a builtin from the shell, show all builtins if (toys.rebound && !*toys.optargs && !toys.optflags) { for (i = 0; i < toys.toycount; i++) { if (!(toy_list[i].flags&(TOYFLAG_NOFORK|TOYFLAG_MAYFORK))) continue; diff --git a/toys/pending/sh.c b/toys/pending/sh.c index dda044d9..68004ce4 100644 --- a/toys/pending/sh.c +++ b/toys/pending/sh.c @@ -8,14 +8,14 @@ * * The first link describes the following shell builtins: * - * break : continue dot eval exec exit export readonly return set shift - * times trap unset + * break : continue exit + * . eval exec export readonly return set shift times trap unset * * The second link (the utilities directory) also contains specs for the * following shell builtins: * - * alias bg cd command fc fg getopts hash jobs kill read type ulimit - * umask unalias wait + * cd ulimit umask + * alias bg command fc fg getopts hash jobs kill read type unalias wait * * Things like the bash man page are good to read too. * @@ -50,6 +50,7 @@ USE_SH(NEWTOY(cd, ">1LP[-LP]", TOYFLAG_NOFORK)) USE_SH(NEWTOY(exit, 0, TOYFLAG_NOFORK)) USE_SH(NEWTOY(unset, "fvn", TOYFLAG_NOFORK)) +USE_SH(NEWTOY(eval, 0, TOYFLAG_NOFORK)) USE_SH(NEWTOY(sh, "(noediting)(noprofile)(norc)sc:i", TOYFLAG_BIN)) USE_SH(OLDTOY(toysh, sh, TOYFLAG_BIN)) @@ -104,14 +105,28 @@ config UNSET -f NAME is a function -v NAME is a variable -n dereference NAME and unset that + +config EVAL + bool + default n + depends on SH + help + usage: eval COMMAND... + + Execute (combined) arguments as a shell command. */ #define FOR_sh #include "toys.h" GLOBALS( - char *c; + union { + struct { + char *c; + } sh; + }; + // keep lineno here, we use it to work around a compiler bug long lineno; char **locals, *subshell_env, *ifs; struct double_list functions; @@ -1109,23 +1124,29 @@ if (BUGBUG) { int i; dprintf(255, "envlen=%d arg->c=%d run=", envlen, arg->c); f else if ((tl = toy_find(*pp->arg.v)) && (tl->flags & (TOYFLAG_NOFORK|TOYFLAG_MAYFORK))) { - struct toy_context temp; sigjmp_buf rebound; + char temp[j = offsetof(struct toy_context, rebound)]; // This fakes lots of what toybox_main() does. - memcpy(&temp, &toys, sizeof(struct toy_context)); - memset(&toys, 0, sizeof(struct toy_context)); + memcpy(&temp, &toys, j); + memset(&toys, 0, j); + + // If we give the union in TT a name, the compiler complains + // "declaration does not declare anything", but if we DON'T give it a name + // it accepts it. So we can't use the union's type name here, and have + // to offsetof() the first thing _after_ the union to get the size. + memset(&TT, 0, offsetof(struct sh_data, lineno)); if (!sigsetjmp(rebound, 1)) { toys.rebound = &rebound; - toy_init(tl, pp->arg.v); // arg.v must be null terminated + toy_singleinit(tl, pp->arg.v); // arg.v must be null terminated tl->toy_main(); xflush(0); } pp->exit = toys.exitval; if (toys.optargs != toys.argv+1) free(toys.optargs); if (toys.old_umask) umask(toys.old_umask); - memcpy(&toys, &temp, sizeof(struct toy_context)); + memcpy(&toys, &temp, j); } else { char **env = 0, **old = environ, *ss, *sss; int kk = 0, ll; @@ -2202,7 +2223,7 @@ if (BUGBUG) { int fd = open("/dev/tty", O_RDWR); dup2(fd, 255); close(fd); } memset(&scratch, 0, sizeof(scratch)); // TODO unify fmemopen() here with sh_run - if (TT.c) f = fmemopen(TT.c, strlen(TT.c), "r"); + if (TT.sh.c) f = fmemopen(TT.sh.c, strlen(TT.sh.c), "r"); else if (*toys.optargs) f = xfopen(*toys.optargs, "r"); else { f = stdin; @@ -2343,3 +2364,15 @@ void unset_main(void) } } } + +void eval_main(void) +{ + struct sh_arg *aa, arg; + + aa = TT.arg; + TT.arg = &arg; + arg.v = toys.argv; + arg.c = toys.optc+1; + sh_run("\"$@\""); + TT.arg = aa; +} |