Blob


1 #include <fcntl.h>
2 #include <unistd.h>
3 #include "threadimpl.h"
5 static void efork(int[3], int[2], char*, char**);
6 void
7 threadexec(Channel *pidc, int fd[3], char *prog, char *args[])
8 {
9 int pfd[2];
10 int n, pid;
11 char exitstr[ERRMAX];
13 _threaddebug(DBGEXEC, "threadexec %s", prog);
15 /*
16 * We want threadexec to behave like exec; if exec succeeds,
17 * never return, and if it fails, return with errstr set.
18 * Unfortunately, the exec happens in another proc since
19 * we have to wait for the exec'ed process to finish.
20 * To provide the semantics, we open a pipe with the
21 * write end close-on-exec and hand it to the proc that
22 * is doing the exec. If the exec succeeds, the pipe will
23 * close so that our read below fails. If the exec fails,
24 * then the proc doing the exec sends the errstr down the
25 * pipe to us.
26 */
27 if(pipe(pfd) < 0)
28 goto Bad;
29 if(fcntl(pfd[0], F_SETFD, 1) < 0)
30 goto Bad;
31 if(fcntl(pfd[1], F_SETFD, 1) < 0)
32 goto Bad;
34 switch(pid = fork()){
35 case -1:
36 close(pfd[0]);
37 close(pfd[1]);
38 goto Bad;
39 case 0:
40 efork(fd, pfd, prog, args);
41 _exit(0);
42 default:
43 break;
44 }
46 close(pfd[1]);
47 if((n = read(pfd[0], exitstr, ERRMAX-1)) > 0){ /* exec failed */
48 exitstr[n] = '\0';
49 errstr(exitstr, ERRMAX);
50 close(pfd[0]);
51 goto Bad;
52 }
53 close(pfd[0]);
54 close(fd[0]);
55 if(fd[1] != fd[0])
56 close(fd[1]);
57 if(fd[2] != fd[1] && fd[2] != fd[0])
58 close(fd[2]);
59 if(pidc)
60 sendul(pidc, pid);
62 _threaddebug(DBGEXEC, "threadexec schedexecwait");
63 threadexits(0);
65 Bad:
66 _threaddebug(DBGEXEC, "threadexec bad %r");
67 if(pidc)
68 sendul(pidc, ~0);
69 }
71 void
72 threadexecl(Channel *pidc, int fd[3], char *f, ...)
73 {
74 threadexec(pidc, fd, f, &f+1);
75 }
77 static void
78 efork(int stdfd[3], int fd[2], char *prog, char **args)
79 {
80 char buf[ERRMAX];
81 int i;
83 _threaddebug(DBGEXEC, "_schedexec %s -- calling execv", prog);
84 dup(stdfd[0], 0);
85 dup(stdfd[1], 1);
86 dup(stdfd[2], 2);
87 for(i=3; i<40; i++)
88 if(i != fd[1])
89 close(i);
90 rfork(RFNOTEG);
91 execvp(prog, args);
92 _threaddebug(DBGEXEC, "_schedexec failed: %r");
93 rerrstr(buf, sizeof buf);
94 if(buf[0]=='\0')
95 strcpy(buf, "exec failed");
96 write(fd[1], buf, strlen(buf));
97 close(fd[1]);
98 _exits(buf);
99 }