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 }