Blob


1 #include <fcntl.h>
2 #include <unistd.h>
3 #include "threadimpl.h"
5 void
6 procexec(Channel *pidc, int fd[3], char *prog, char *args[])
7 {
8 int n;
9 Proc *p;
10 Thread *t;
12 _threaddebug(DBGEXEC, "procexec %s", prog);
13 /* must be only thread in proc */
14 p = _threadgetproc();
15 t = p->thread;
16 if(p->threads.head != t || p->threads.head->nextt != nil){
17 werrstr("not only thread in proc");
18 Bad:
19 _threaddebug(DBGEXEC, "procexec bad %r");
20 if(pidc)
21 sendul(pidc, ~0);
22 return;
23 }
25 /*
26 * We want procexec to behave like exec; if exec succeeds,
27 * never return, and if it fails, return with errstr set.
28 * Unfortunately, the exec happens in another proc since
29 * we have to wait for the exec'ed process to finish.
30 * To provide the semantics, we open a pipe with the
31 * write end close-on-exec and hand it to the proc that
32 * is doing the exec. If the exec succeeds, the pipe will
33 * close so that our read below fails. If the exec fails,
34 * then the proc doing the exec sends the errstr down the
35 * pipe to us.
36 */
37 if(pipe(p->exec.fd) < 0)
38 goto Bad;
39 if(fcntl(p->exec.fd[0], F_SETFD, 1) < 0)
40 goto Bad;
41 if(fcntl(p->exec.fd[1], F_SETFD, 1) < 0)
42 goto Bad;
44 /* exec in parallel via the scheduler */
45 assert(p->needexec==0);
46 p->exec.prog = prog;
47 p->exec.args = args;
48 p->exec.stdfd = fd;
49 p->needexec = 1;
50 _sched();
52 close(p->exec.fd[1]);
53 if((n = read(p->exec.fd[0], p->exitstr, ERRMAX-1)) > 0){ /* exec failed */
54 p->exitstr[n] = '\0';
55 errstr(p->exitstr, ERRMAX);
56 close(p->exec.fd[0]);
57 goto Bad;
58 }
59 close(p->exec.fd[0]);
60 close(fd[0]);
61 if(fd[1] != fd[0])
62 close(fd[1]);
63 if(fd[2] != fd[1] && fd[2] != fd[0])
64 close(fd[2]);
65 if(pidc)
66 sendul(pidc, t->ret);
68 _threaddebug(DBGEXEC, "procexec schedexecwait");
69 /* wait for exec'ed program, then exit */
70 _schedexecwait();
71 }
73 void
74 procexecl(Channel *pidc, int fd[3], char *f, ...)
75 {
76 procexec(pidc, fd, f, &f+1);
77 }
79 void
80 _schedexecwait(void)
81 {
82 int pid;
83 Channel *c;
84 Proc *p;
85 Thread *t;
86 Waitmsg *w;
88 p = _threadgetproc();
89 t = p->thread;
90 pid = t->ret;
91 _threaddebug(DBGEXEC, "_schedexecwait %d", t->ret);
93 for(;;){
94 w = wait();
95 if(w == nil)
96 break;
97 if(w->pid == pid)
98 break;
99 free(w);
101 if(w != nil){
102 if((c = _threadwaitchan) != nil)
103 sendp(c, w);
104 else
105 free(w);
107 threadexits("procexec");
110 static void
111 efork(void *ve)
113 char buf[ERRMAX];
114 Execargs *e;
115 int i;
117 e = ve;
118 _threaddebug(DBGEXEC, "_schedexec %s -- calling execv", e->prog);
119 dup(e->stdfd[0], 0);
120 dup(e->stdfd[1], 1);
121 dup(e->stdfd[2], 2);
122 for(i=3; i<40; i++)
123 if(i != e->fd[1])
124 close(i);
125 rfork(RFNOTEG);
126 execvp(e->prog, e->args);
127 _threaddebug(DBGEXEC, "_schedexec failed: %r");
128 rerrstr(buf, sizeof buf);
129 if(buf[0]=='\0')
130 strcpy(buf, "exec failed");
131 write(e->fd[1], buf, strlen(buf));
132 close(e->fd[1]);
133 _exits(buf);
136 int
137 _schedexec(Execargs *e)
139 int pid;
141 pid = fork();
142 if(pid == 0){
143 efork(e);
144 _exit(1);
146 return pid;