Commit | Line | Data |
---|---|---|
2614d1e5 C |
1 | /* exec.c */ |
2 | #include <signal.h> | |
3 | #include <errno.h> | |
4 | #include <setjmp.h> | |
5 | #include "rc.h" | |
6 | #include "jbwrap.h" | |
7 | ||
8 | /* | |
9 | Takes an argument list and does the appropriate thing (calls a | |
10 | builtin, calls a function, etc.) | |
11 | */ | |
12 | ||
13 | extern void exec(List *s, bool parent) { | |
14 | char **av, **ev = NULL; | |
15 | int pid, stat; | |
16 | builtin_t *b; | |
17 | char *path = NULL; | |
18 | bool didfork, returning, saw_exec, saw_builtin; | |
19 | av = list2array(s, dashex); | |
20 | saw_builtin = saw_exec = FALSE; | |
21 | do { | |
22 | if (*av == NULL || isabsolute(*av)) | |
23 | b = NULL; | |
24 | else if (!saw_builtin && fnlookup(*av) != NULL) | |
25 | b = funcall; | |
26 | else | |
27 | b = isbuiltin(*av); | |
28 | ||
29 | /* | |
30 | a builtin applies only to the immmediately following | |
31 | command, e.g., builtin exec echo hi | |
32 | */ | |
33 | saw_builtin = FALSE; | |
34 | ||
35 | if (b == b_exec) { | |
36 | av++; | |
37 | saw_exec = TRUE; | |
38 | parent = FALSE; | |
39 | } else if (b == b_builtin) { | |
40 | av++; | |
41 | saw_builtin = TRUE; | |
42 | } | |
43 | } while (b == b_exec || b == b_builtin); | |
44 | if (*av == NULL && saw_exec) { /* do redirs and return on a null exec */ | |
45 | doredirs(); | |
46 | return; | |
47 | } | |
48 | /* force an exit on exec with any rc_error, but not for null commands as above */ | |
49 | if (saw_exec) | |
50 | rc_pid = -1; | |
51 | if (b == NULL) { | |
52 | path = which(*av, TRUE); | |
53 | if (path == NULL && *av != NULL) { /* perform null commands for redirections */ | |
54 | set(FALSE); | |
55 | redirq = NULL; | |
56 | if (parent) | |
57 | return; | |
58 | rc_exit(1); | |
59 | } | |
60 | ev = makeenv(); /* environment only needs to be built for execve() */ | |
61 | } | |
62 | /* | |
63 | If parent & the redirq is nonnull, builtin or not it has to fork. | |
64 | If the fifoq is nonnull, then it must be emptied at the end so we | |
65 | must fork no matter what. | |
66 | */ | |
67 | if ((parent && (b == NULL || redirq != NULL)) || outstanding_cmdarg()) { | |
68 | pid = rc_fork(); | |
69 | didfork = TRUE; | |
70 | } else { | |
71 | pid = 0; | |
72 | didfork = FALSE; | |
73 | } | |
74 | returning = (!didfork && parent); | |
75 | switch (pid) { | |
76 | case -1: | |
77 | uerror("fork"); | |
78 | rc_error(NULL); | |
79 | /* NOTREACHED */ | |
80 | case 0: | |
81 | if (!returning) | |
82 | setsigdefaults(FALSE); | |
83 | pop_cmdarg(FALSE); | |
84 | doredirs(); | |
85 | ||
86 | /* null commands performed for redirections */ | |
87 | if (*av == NULL || b != NULL) { | |
88 | if (b != NULL) | |
89 | (*b)(av); | |
90 | if (returning) | |
91 | return; | |
92 | rc_exit(getstatus()); | |
93 | } | |
94 | execve(path, (char * const *) av, (char * const *) ev); | |
95 | uerror(*av); | |
96 | rc_exit(1); | |
97 | /* NOTREACHED */ | |
98 | default: | |
99 | redirq = NULL; | |
100 | rc_wait4(pid, &stat, TRUE); | |
101 | setstatus(-1, stat); | |
102 | if ((stat & 0xff) == 0) | |
103 | nl_on_intr = FALSE; | |
104 | SIGCHK; | |
105 | nl_on_intr = TRUE; | |
106 | pop_cmdarg(TRUE); | |
107 | } | |
108 | } |