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 if(pidc)
20 sendul(pidc, ~0);
21 return;
22 }
24 /*
25 * We want procexec to behave like exec; if exec succeeds,
26 * never return, and if it fails, return with errstr set.
27 * Unfortunately, the exec happens in another proc since
28 * we have to wait for the exec'ed process to finish.
29 * To provide the semantics, we open a pipe with the
30 * write end close-on-exec and hand it to the proc that
31 * is doing the exec. If the exec succeeds, the pipe will
32 * close so that our read below fails. If the exec fails,
33 * then the proc doing the exec sends the errstr down the
34 * pipe to us.
35 */
36 if(pipe(p->exec.fd) < 0)
37 goto Bad;
38 if(fcntl(p->exec.fd[1], F_SETFD, 1) < 0)
39 goto Bad;
41 /* exec in parallel via the scheduler */
42 assert(p->needexec==0);
43 p->exec.prog = prog;
44 p->exec.args = args;
45 p->needexec = 1;
46 _sched();
48 close(p->exec.fd[1]);
49 if((n = read(p->exec.fd[0], p->exitstr, ERRMAX-1)) > 0){ /* exec failed */
50 p->exitstr[n] = '\0';
51 errstr(p->exitstr, ERRMAX);
52 close(p->exec.fd[0]);
53 goto Bad;
54 }
55 close(p->exec.fd[0]);
57 if(pidc)
58 sendul(pidc, t->ret);
60 /* wait for exec'ed program, then exit */
61 _schedexecwait();
62 }
64 void
65 procexecl(Channel *pidc, char *f, ...)
66 {
67 procexec(pidc, f, &f+1);
68 }
70 void
71 _schedexecwait(void)
72 {
73 int pid;
74 Channel *c;
75 Proc *p;
76 Thread *t;
77 Waitmsg *w;
79 p = _threadgetproc();
80 t = p->thread;
81 pid = t->ret;
82 _threaddebug(DBGEXEC, "_schedexecwait %d", t->ret);
84 for(;;){
85 w = wait();
86 if(w == nil)
87 break;
88 if(w->pid == pid)
89 break;
90 free(w);
91 }
92 if(w != nil){
93 if((c = _threadwaitchan) != nil)
94 sendp(c, w);
95 else
96 free(w);
97 }
98 threadexits("procexec");
99 }
101 static void
102 efork(void *ve)
104 char buf[ERRMAX];
105 Execargs *e;
107 e = ve;
108 _threaddebug(DBGEXEC, "_schedexec %s", e->prog);
109 close(e->fd[0]);
110 execv(e->prog, e->args);
111 _threaddebug(DBGEXEC, "_schedexec failed: %r");
112 rerrstr(buf, sizeof buf);
113 if(buf[0]=='\0')
114 strcpy(buf, "exec failed");
115 write(e->fd[1], buf, strlen(buf));
116 close(e->fd[1]);
117 _exits(buf);
120 int
121 _schedexec(Execargs *e)
123 return ffork(RFFDG|RFPROC|RFMEM, efork, e);