commit 2ea901dfe7f367ddad61b3a64bbef4195a90ce35
parent f8f33b2674afaa2682c4a4ccec3e20439c53c144
Author: tim <tim>
Date: Tue, 20 May 1997 16:17:15 +0000
Initial revision
Diffstat:
A | exec.c | | | 130 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 130 insertions(+), 0 deletions(-)
diff --git a/exec.c b/exec.c
@@ -0,0 +1,130 @@
+/* exec.c */
+#include <signal.h>
+#include <errno.h>
+#include <setjmp.h>
+#include "rc.h"
+#include "jbwrap.h"
+
+/*
+ Takes an argument list and does the appropriate thing (calls a
+ builtin, calls a function, etc.)
+*/
+
+extern void exec(List *s, bool parent) {
+ char **av, **ev = NULL;
+ int pid, stat;
+ builtin_t *b;
+ char *path = NULL;
+ bool didfork, returning, saw_exec, saw_builtin;
+ av = list2array(s, dashex);
+ saw_builtin = saw_exec = FALSE;
+ do {
+ if (*av == NULL || isabsolute(*av))
+ b = NULL;
+ else if (!saw_builtin && fnlookup(*av) != NULL)
+ b = funcall;
+ else
+ b = isbuiltin(*av);
+
+ /*
+ a builtin applies only to the immmediately following
+ command, e.g., builtin exec echo hi
+ */
+ saw_builtin = FALSE;
+
+ if (b == b_exec) {
+ av++;
+ saw_exec = TRUE;
+ parent = FALSE;
+ } else if (b == b_builtin) {
+ av++;
+ saw_builtin = TRUE;
+ }
+ } while (b == b_exec || b == b_builtin);
+ if (*av == NULL && saw_exec) { /* do redirs and return on a null exec */
+ doredirs();
+ return;
+ }
+ /* force an exit on exec with any rc_error, but not for null commands as above */
+ if (saw_exec)
+ rc_pid = -1;
+ if (b == NULL) {
+ path = which(*av, TRUE);
+ if (path == NULL && *av != NULL) { /* perform null commands for redirections */
+ set(FALSE);
+ redirq = NULL;
+ if (parent)
+ return;
+ rc_exit(1);
+ }
+ ev = makeenv(); /* environment only needs to be built for execve() */
+ }
+ /*
+ If parent & the redirq is nonnull, builtin or not it has to fork.
+ If the fifoq is nonnull, then it must be emptied at the end so we
+ must fork no matter what.
+ */
+ if ((parent && (b == NULL || redirq != NULL)) || outstanding_cmdarg()) {
+ pid = rc_fork();
+ didfork = TRUE;
+ } else {
+ pid = 0;
+ didfork = FALSE;
+ }
+ returning = (!didfork && parent);
+ switch (pid) {
+ case -1:
+ uerror("fork");
+ rc_error(NULL);
+ /* NOTREACHED */
+ case 0:
+ if (!returning)
+ setsigdefaults(FALSE);
+ pop_cmdarg(FALSE);
+ doredirs();
+
+ /* null commands performed for redirections */
+ if (*av == NULL || b != NULL) {
+ if (b != NULL)
+ (*b)(av);
+ if (returning)
+ return;
+ rc_exit(getstatus());
+ }
+#ifdef NOEXECVE
+ my_execve(path, (const char **) av, (const char **) ev); /* bogus, huh? */
+#else
+ execve(path, (const char **) av, (const char **) ev);
+#endif
+#ifdef DEFAULTINTERP
+ if (errno == ENOEXEC) {
+ *av = path;
+ *--av = DEFAULTINTERP;
+ execve(*av, (const char **) av, (const char **) ev);
+ }
+#endif
+ uerror(*av);
+ rc_exit(1);
+ /* NOTREACHED */
+ default:
+ redirq = NULL;
+ rc_wait4(pid, &stat, TRUE);
+ setstatus(-1, stat);
+ /*
+ There is a very good reason for having this weird
+ nl_on_intr variable: when rc and its child both
+ process a SIGINT, (i.e., the child has a SIGINT
+ catcher installed) then you don't want rc to print
+ a newline when the child finally exits. Here's an
+ example: ed, <type ^C>, <type "q">. rc does not
+ and should not print a newline before the next
+ prompt, even though there's a SIGINT in its signal
+ vector.
+ */
+ if ((stat & 0xff) == 0)
+ nl_on_intr = FALSE;
+ sigchk();
+ nl_on_intr = TRUE;
+ pop_cmdarg(TRUE);
+ }
+}