Blob


1 #include <fcntl.h>
2 #include <unistd.h>
3 #include "threadimpl.h"
5 void
6 procexec(Channel *pidc, 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->needexec = 1;
49 _sched();
51 close(p->exec.fd[1]);
52 if((n = read(p->exec.fd[0], p->exitstr, ERRMAX-1)) > 0){ /* exec failed */
53 p->exitstr[n] = '\0';
54 errstr(p->exitstr, ERRMAX);
55 close(p->exec.fd[0]);
56 goto Bad;
57 }
58 close(p->exec.fd[0]);
60 if(pidc)
61 sendul(pidc, t->ret);
63 _threaddebug(DBGEXEC, "procexec schedexecwait");
64 /* wait for exec'ed program, then exit */
65 _schedexecwait();
66 }
68 void
69 procexecl(Channel *pidc, char *f, ...)
70 {
71 procexec(pidc, f, &f+1);
72 }
74 void
75 _schedexecwait(void)
76 {
77 int pid;
78 Channel *c;
79 Proc *p;
80 Thread *t;
81 Waitmsg *w;
83 p = _threadgetproc();
84 t = p->thread;
85 pid = t->ret;
86 _threaddebug(DBGEXEC, "_schedexecwait %d", t->ret);
88 for(;;){
89 w = wait();
90 if(w == nil)
91 break;
92 if(w->pid == pid)
93 break;
94 free(w);
95 }
96 if(w != nil){
97 if((c = _threadwaitchan) != nil)
98 sendp(c, w);
99 else
100 free(w);
102 threadexits("procexec");
105 static void
106 efork(void *ve)
108 char buf[ERRMAX];
109 Execargs *e;
111 e = ve;
112 _threaddebug(DBGEXEC, "_schedexec %s -- calling execv", e->prog);
113 execv(e->prog, e->args);
114 _threaddebug(DBGEXEC, "_schedexec failed: %r");
115 rerrstr(buf, sizeof buf);
116 if(buf[0]=='\0')
117 strcpy(buf, "exec failed");
118 write(e->fd[1], buf, strlen(buf));
119 close(e->fd[1]);
120 _exits(buf);
123 int
124 _schedexec(Execargs *e)
126 int pid;
128 pid = fork();
129 if(pid == 0){
130 efork(e);
131 _exit(1);
133 return pid;