aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2020-03-11 22:09:15 -0500
committerRob Landley <rob@landley.net>2020-03-11 22:09:15 -0500
commit114541b98e755bd28a9386008a352065bd942875 (patch)
tree6a90b20d308978d354e2cf0cea4c5e1446febfb0
parent42be28f77458618c128d32d9273f6eca7f73a971 (diff)
downloadtoybox-114541b98e755bd28a9386008a352065bd942875.tar.gz
Redo NOFORK plumbing so commands like eval/unset can access/edit shell state.
-rw-r--r--main.c2
-rw-r--r--toys.h11
-rw-r--r--toys/other/help.c2
-rw-r--r--toys/pending/sh.c55
4 files changed, 52 insertions, 18 deletions
diff --git a/main.c b/main.c
index 60cb2b07..b67b8cd7 100644
--- a/main.c
+++ b/main.c
@@ -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;
diff --git a/toys.h b/toys.h
index eb9208e4..955cc4ca 100644
--- a/toys.h
+++ b/toys.h
@@ -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;
+}