4 #include "threadimpl.h"
6 static void efork(int[3], int[2], char*, char**);
8 _threadexec(Channel *pidc, int fd[3], char *prog, char *args[], int freeargs)
13 static int firstexec = 1;
16 _threaddebug(DBGEXEC, "threadexec %s", prog);
28 * We want threadexec to behave like exec; if exec succeeds,
29 * never return, and if it fails, return with errstr set.
30 * Unfortunately, the exec happens in another proc since
31 * we have to wait for the exec'ed process to finish.
32 * To provide the semantics, we open a pipe with the
33 * write end close-on-exec and hand it to the proc that
34 * is doing the exec. If the exec succeeds, the pipe will
35 * close so that our read below fails. If the exec fails,
36 * then the proc doing the exec sends the errstr down the
41 if(fcntl(pfd[0], F_SETFD, 1) < 0)
43 if(fcntl(pfd[1], F_SETFD, 1) < 0)
52 efork(fd, pfd, prog, args);
62 if((n = read(pfd[0], exitstr, ERRMAX-1)) > 0){ /* exec failed */
64 errstr(exitstr, ERRMAX);
72 if(fd[2] != fd[1] && fd[2] != fd[0])
77 _threaddebug(DBGEXEC, "threadexec schedexecwait");
81 _threaddebug(DBGEXEC, "threadexec bad %r");
88 threadexec(Channel *pidc, int fd[3], char *prog, char *args[])
90 if(_threadexec(pidc, fd, prog, args, 0) >= 0)
95 threadspawn(int fd[3], char *prog, char *args[])
97 return _threadexec(nil, fd, prog, args, 0);
101 * The &f+1 trick doesn't work on SunOS, so we might
102 * as well bite the bullet and do this correctly.
105 threadexecl(Channel *pidc, int fd[3], char *f, ...)
112 for(n=0; va_arg(arg, char*) != 0; n++)
117 args = malloc(n*sizeof(args[0]));
125 for(n=0; (s=va_arg(arg, char*)) != 0; n++)
130 if(_threadexec(pidc, fd, f, args, 1) >= 0)
135 efork(int stdfd[3], int fd[2], char *prog, char **args)
140 _threaddebug(DBGEXEC, "_schedexec %s -- calling execv", prog);
149 _threaddebug(DBGEXEC, "_schedexec failed: %r");
150 rerrstr(buf, sizeof buf);
152 strcpy(buf, "exec failed");
153 write(fd[1], buf, strlen(buf));