rc

[fork] interactive rc shell
git clone https://hhvn.uk/rc
git clone git://hhvn.uk/rc
Log | Files | Refs | README | LICENSE

exec.c (3183B)


      1 /* exec.c */
      2 
      3 #include "rc.h"
      4 
      5 #include <errno.h>
      6 #include <signal.h>
      7 #include <termios.h>
      8 #include <unistd.h>
      9 
     10 #include "wait.h"
     11 
     12 /*
     13    Takes an argument list and does the appropriate thing (calls a
     14    builtin, calls a function, etc.)
     15 */
     16 
     17 extern void exec(List *s, bool parent) {
     18 	char **av, **ev = NULL;
     19 	int stat;
     20 	pid_t pid;
     21 	builtin_t *b;
     22 	char *path = NULL;
     23 	bool didfork, returning, saw_exec, saw_builtin;
     24 	struct termios t;
     25 	av = list2array(s, dashex);
     26 	saw_builtin = saw_exec = FALSE;
     27 	do {
     28 		if (*av == NULL	|| isabsolute(*av))
     29 			b = NULL;
     30 		else if (!saw_builtin && fnlookup(*av) != NULL)
     31 			b = funcall;
     32 		else
     33 			b = isbuiltin(*av);
     34 
     35 		/*
     36 		   a builtin applies only to the immediately following
     37 		   command, e.g., builtin exec echo hi
     38 		*/
     39 		saw_builtin = FALSE;
     40 
     41 		if (b == b_exec) {
     42 			av++;
     43 			saw_exec = TRUE;
     44 			parent = FALSE;
     45 		} else if (b == b_builtin) {
     46 			av++;
     47 			saw_builtin = TRUE;
     48 		}
     49 	} while (b == b_exec || b == b_builtin);
     50 	if (*av == NULL && saw_exec) { /* do redirs and return on a null exec */
     51 		doredirs();
     52 		return;
     53 	}
     54 	/* force an exit on exec with any rc_error, but not for null commands as above */
     55 	if (saw_exec)
     56 		rc_pid = -1;
     57 	if (b == NULL) {
     58 		path = which(*av, TRUE);
     59 		if (path == NULL && *av != NULL) { /* perform null commands for redirections */
     60 			set(FALSE);
     61 			redirq = NULL;
     62 			if (parent)
     63 				return;
     64 			rc_exit(1);
     65 		}
     66 		ev = makeenv(); /* environment only needs to be built for execve() */
     67 	}
     68 	/*
     69 	   If parent & the redirq is nonnull, builtin or not it has to fork.
     70 	   If the fifoq is nonnull, then it must be emptied at the end so we
     71 	   must fork no matter what.
     72 	 */
     73 	if ((parent && (b == NULL || redirq != NULL)) || outstanding_cmdarg()) {
     74 		if (interactive)
     75 			tcgetattr(0, &t);
     76 		pid = rc_fork();
     77 		didfork = TRUE;
     78 	} else {
     79 		pid = 0;
     80 		didfork = FALSE;
     81 	}
     82 	returning = (!didfork && parent);
     83 	switch (pid) {
     84 	case -1:
     85 		uerror("fork");
     86 		rc_error(NULL);
     87 		/* NOTREACHED */
     88 	case 0:
     89 		if (!returning)
     90 			setsigdefaults(FALSE);
     91 		pop_cmdarg(FALSE);
     92 		doredirs();
     93 
     94 		/* null commands performed for redirections */
     95 		if (*av == NULL || b != NULL) {
     96 			if (b != NULL)
     97 				(*b)(av);
     98 			if (returning)
     99 				return;
    100 			rc_exit(getstatus());
    101 		}
    102 		rc_execve(path, (char * const *) av, (char * const *) ev);
    103 
    104 #ifdef DEFAULTINTERP
    105 		if (errno == ENOEXEC) {
    106 			*av = path;
    107 			*--av = DEFAULTINTERP;
    108 			execve(*av, (char * const *) av, (char * const *) ev);
    109 		}
    110 #endif
    111 
    112 		uerror(*av);
    113 		rc_exit(1);
    114 		/* NOTREACHED */
    115 	default:
    116 		redirq = NULL;
    117 		rc_wait4(pid, &stat, TRUE);
    118 		if (interactive && WIFSIGNALED(stat))
    119 			tcsetattr(0, TCSANOW, &t);
    120 		setstatus(-1, stat);
    121 		/*
    122 		   There is a very good reason for having this weird
    123 		   nl_on_intr variable: when rc and its child both
    124 		   process a SIGINT, (i.e., the child has a SIGINT
    125 		   catcher installed) then you don't want rc to print
    126 		   a newline when the child finally exits. Here's an
    127 		   example: ed, <type ^C>, <type "q">. rc does not
    128 		   and should not print a newline before the next
    129 		   prompt, even though there's a SIGINT in its signal
    130 		   vector.
    131 		*/
    132 		if (WIFEXITED(stat))
    133 			nl_on_intr = FALSE;
    134 		sigchk();
    135 		nl_on_intr = TRUE;
    136 		pop_cmdarg(TRUE);
    137 	}
    138 }