Blame


1 be22ae2d 2004-03-26 devnull #include <u.h>
2 76193d7c 2003-09-30 devnull #include <fcntl.h>
3 76193d7c 2003-09-30 devnull #include <unistd.h>
4 76193d7c 2003-09-30 devnull #include "threadimpl.h"
5 76193d7c 2003-09-30 devnull
6 5a8e63b2 2004-02-29 devnull static void efork(int[3], int[2], char*, char**);
7 1aa4e9c8 2004-04-23 devnull static int
8 8ad51794 2004-03-25 devnull _threadexec(Channel *pidc, int fd[3], char *prog, char *args[], int freeargs)
9 76193d7c 2003-09-30 devnull {
10 5a8e63b2 2004-02-29 devnull int pfd[2];
11 5a8e63b2 2004-02-29 devnull int n, pid;
12 5a8e63b2 2004-02-29 devnull char exitstr[ERRMAX];
13 76193d7c 2003-09-30 devnull
14 5a8e63b2 2004-02-29 devnull _threaddebug(DBGEXEC, "threadexec %s", prog);
15 5a8e63b2 2004-02-29 devnull
16 76193d7c 2003-09-30 devnull /*
17 5a8e63b2 2004-02-29 devnull * We want threadexec to behave like exec; if exec succeeds,
18 76193d7c 2003-09-30 devnull * never return, and if it fails, return with errstr set.
19 76193d7c 2003-09-30 devnull * Unfortunately, the exec happens in another proc since
20 76193d7c 2003-09-30 devnull * we have to wait for the exec'ed process to finish.
21 76193d7c 2003-09-30 devnull * To provide the semantics, we open a pipe with the
22 76193d7c 2003-09-30 devnull * write end close-on-exec and hand it to the proc that
23 76193d7c 2003-09-30 devnull * is doing the exec. If the exec succeeds, the pipe will
24 76193d7c 2003-09-30 devnull * close so that our read below fails. If the exec fails,
25 76193d7c 2003-09-30 devnull * then the proc doing the exec sends the errstr down the
26 76193d7c 2003-09-30 devnull * pipe to us.
27 76193d7c 2003-09-30 devnull */
28 5a8e63b2 2004-02-29 devnull if(pipe(pfd) < 0)
29 76193d7c 2003-09-30 devnull goto Bad;
30 5a8e63b2 2004-02-29 devnull if(fcntl(pfd[0], F_SETFD, 1) < 0)
31 912fba95 2003-11-24 devnull goto Bad;
32 5a8e63b2 2004-02-29 devnull if(fcntl(pfd[1], F_SETFD, 1) < 0)
33 76193d7c 2003-09-30 devnull goto Bad;
34 76193d7c 2003-09-30 devnull
35 5a8e63b2 2004-02-29 devnull switch(pid = fork()){
36 5a8e63b2 2004-02-29 devnull case -1:
37 5a8e63b2 2004-02-29 devnull close(pfd[0]);
38 5a8e63b2 2004-02-29 devnull close(pfd[1]);
39 5a8e63b2 2004-02-29 devnull goto Bad;
40 5a8e63b2 2004-02-29 devnull case 0:
41 5a8e63b2 2004-02-29 devnull efork(fd, pfd, prog, args);
42 5a8e63b2 2004-02-29 devnull _exit(0);
43 5a8e63b2 2004-02-29 devnull default:
44 8ad51794 2004-03-25 devnull if(freeargs)
45 8ad51794 2004-03-25 devnull free(args);
46 5a8e63b2 2004-02-29 devnull break;
47 5a8e63b2 2004-02-29 devnull }
48 76193d7c 2003-09-30 devnull
49 5a8e63b2 2004-02-29 devnull close(pfd[1]);
50 5a8e63b2 2004-02-29 devnull if((n = read(pfd[0], exitstr, ERRMAX-1)) > 0){ /* exec failed */
51 5a8e63b2 2004-02-29 devnull exitstr[n] = '\0';
52 5a8e63b2 2004-02-29 devnull errstr(exitstr, ERRMAX);
53 5a8e63b2 2004-02-29 devnull close(pfd[0]);
54 76193d7c 2003-09-30 devnull goto Bad;
55 76193d7c 2003-09-30 devnull }
56 5a8e63b2 2004-02-29 devnull close(pfd[0]);
57 32f69c36 2003-12-11 devnull close(fd[0]);
58 32f69c36 2003-12-11 devnull if(fd[1] != fd[0])
59 32f69c36 2003-12-11 devnull close(fd[1]);
60 32f69c36 2003-12-11 devnull if(fd[2] != fd[1] && fd[2] != fd[0])
61 32f69c36 2003-12-11 devnull close(fd[2]);
62 76193d7c 2003-09-30 devnull if(pidc)
63 5a8e63b2 2004-02-29 devnull sendul(pidc, pid);
64 76193d7c 2003-09-30 devnull
65 5a8e63b2 2004-02-29 devnull _threaddebug(DBGEXEC, "threadexec schedexecwait");
66 1aa4e9c8 2004-04-23 devnull return pid;
67 76193d7c 2003-09-30 devnull
68 5a8e63b2 2004-02-29 devnull Bad:
69 5a8e63b2 2004-02-29 devnull _threaddebug(DBGEXEC, "threadexec bad %r");
70 5a8e63b2 2004-02-29 devnull if(pidc)
71 5a8e63b2 2004-02-29 devnull sendul(pidc, ~0);
72 1aa4e9c8 2004-04-23 devnull return -1;
73 76193d7c 2003-09-30 devnull }
74 76193d7c 2003-09-30 devnull
75 76193d7c 2003-09-30 devnull void
76 8ad51794 2004-03-25 devnull threadexec(Channel *pidc, int fd[3], char *prog, char *args[])
77 8ad51794 2004-03-25 devnull {
78 1aa4e9c8 2004-04-23 devnull if(_threadexec(pidc, fd, prog, args, 0) >= 0)
79 1aa4e9c8 2004-04-23 devnull threadexits(nil);
80 8ad51794 2004-03-25 devnull }
81 8ad51794 2004-03-25 devnull
82 1aa4e9c8 2004-04-23 devnull int
83 1aa4e9c8 2004-04-23 devnull threadspawn(int fd[3], char *prog, char *args[])
84 1aa4e9c8 2004-04-23 devnull {
85 1aa4e9c8 2004-04-23 devnull return _threadexec(nil, fd, prog, args, 0);
86 1aa4e9c8 2004-04-23 devnull }
87 1aa4e9c8 2004-04-23 devnull
88 8ad51794 2004-03-25 devnull /*
89 8ad51794 2004-03-25 devnull * The &f+1 trick doesn't work on SunOS, so we might
90 8ad51794 2004-03-25 devnull * as well bite the bullet and do this correctly.
91 8ad51794 2004-03-25 devnull */
92 8ad51794 2004-03-25 devnull void
93 5a8e63b2 2004-02-29 devnull threadexecl(Channel *pidc, int fd[3], char *f, ...)
94 76193d7c 2003-09-30 devnull {
95 8ad51794 2004-03-25 devnull char **args, *s;
96 8ad51794 2004-03-25 devnull int n;
97 8ad51794 2004-03-25 devnull va_list arg;
98 8ad51794 2004-03-25 devnull
99 8ad51794 2004-03-25 devnull va_start(arg, f);
100 8ad51794 2004-03-25 devnull for(n=0; va_arg(arg, char*) != 0; n++)
101 8ad51794 2004-03-25 devnull ;
102 8ad51794 2004-03-25 devnull n++;
103 8ad51794 2004-03-25 devnull va_end(arg);
104 8ad51794 2004-03-25 devnull
105 8ad51794 2004-03-25 devnull args = malloc(n*sizeof(args[0]));
106 8ad51794 2004-03-25 devnull if(args == nil){
107 8ad51794 2004-03-25 devnull if(pidc)
108 8ad51794 2004-03-25 devnull sendul(pidc, ~0);
109 8ad51794 2004-03-25 devnull return;
110 8ad51794 2004-03-25 devnull }
111 8ad51794 2004-03-25 devnull
112 8ad51794 2004-03-25 devnull va_start(arg, f);
113 8ad51794 2004-03-25 devnull for(n=0; (s=va_arg(arg, char*)) != 0; n++)
114 8ad51794 2004-03-25 devnull args[n] = s;
115 8ad51794 2004-03-25 devnull args[n] = 0;
116 8ad51794 2004-03-25 devnull va_end(arg);
117 8ad51794 2004-03-25 devnull
118 10495dd3 2004-04-25 devnull if(_threadexec(pidc, fd, f, args, 1) >= 0)
119 10495dd3 2004-04-25 devnull threadexits(nil);
120 76193d7c 2003-09-30 devnull }
121 76193d7c 2003-09-30 devnull
122 76193d7c 2003-09-30 devnull static void
123 5a8e63b2 2004-02-29 devnull efork(int stdfd[3], int fd[2], char *prog, char **args)
124 76193d7c 2003-09-30 devnull {
125 76193d7c 2003-09-30 devnull char buf[ERRMAX];
126 32f69c36 2003-12-11 devnull int i;
127 76193d7c 2003-09-30 devnull
128 5a8e63b2 2004-02-29 devnull _threaddebug(DBGEXEC, "_schedexec %s -- calling execv", prog);
129 5a8e63b2 2004-02-29 devnull dup(stdfd[0], 0);
130 5a8e63b2 2004-02-29 devnull dup(stdfd[1], 1);
131 5a8e63b2 2004-02-29 devnull dup(stdfd[2], 2);
132 32f69c36 2003-12-11 devnull for(i=3; i<40; i++)
133 5a8e63b2 2004-02-29 devnull if(i != fd[1])
134 32f69c36 2003-12-11 devnull close(i);
135 49588d5d 2003-12-17 devnull rfork(RFNOTEG);
136 5a8e63b2 2004-02-29 devnull execvp(prog, args);
137 76193d7c 2003-09-30 devnull _threaddebug(DBGEXEC, "_schedexec failed: %r");
138 76193d7c 2003-09-30 devnull rerrstr(buf, sizeof buf);
139 76193d7c 2003-09-30 devnull if(buf[0]=='\0')
140 76193d7c 2003-09-30 devnull strcpy(buf, "exec failed");
141 5a8e63b2 2004-02-29 devnull write(fd[1], buf, strlen(buf));
142 5a8e63b2 2004-02-29 devnull close(fd[1]);
143 76193d7c 2003-09-30 devnull _exits(buf);
144 76193d7c 2003-09-30 devnull }
145 76193d7c 2003-09-30 devnull