exec.c (3487B)
1 #include "threadimpl.h" 2 3 static Lock thewaitlock; 4 static Channel *thewaitchan; 5 6 static void 7 execproc(void *v) 8 { 9 int pid; 10 Channel *c; 11 Execjob *e; 12 Waitmsg *w; 13 14 e = v; 15 pid = _threadspawn(e->fd, e->cmd, e->argv, e->dir); 16 sendul(e->c, pid); 17 if(pid > 0){ 18 w = waitfor(pid); 19 if((c = thewaitchan) != nil) 20 sendp(c, w); 21 else 22 free(w); 23 } 24 threadexits(nil); 25 } 26 27 int 28 _runthreadspawn(int *fd, char *cmd, char **argv, char *dir) 29 { 30 int pid; 31 Execjob e; 32 33 e.fd = fd; 34 e.cmd = cmd; 35 e.argv = argv; 36 e.dir = dir; 37 e.c = chancreate(sizeof(void*), 0); 38 proccreate(execproc, &e, 65536); 39 pid = recvul(e.c); 40 chanfree(e.c); 41 return pid; 42 } 43 44 Channel* 45 threadwaitchan(void) 46 { 47 if(thewaitchan) 48 return thewaitchan; 49 lock(&thewaitlock); 50 if(thewaitchan){ 51 unlock(&thewaitlock); 52 return thewaitchan; 53 } 54 thewaitchan = chancreate(sizeof(Waitmsg*), 4); 55 chansetname(thewaitchan, "threadwaitchan"); 56 unlock(&thewaitlock); 57 return thewaitchan; 58 } 59 60 int 61 _threadspawn(int fd[3], char *cmd, char *argv[], char *dir) 62 { 63 int i, n, p[2], pid; 64 char exitstr[100]; 65 66 notifyoff("sys: child"); /* do not let child note kill us */ 67 if(pipe(p) < 0) 68 return -1; 69 if(fcntl(p[0], F_SETFD, 1) < 0 || fcntl(p[1], F_SETFD, 1) < 0){ 70 close(p[0]); 71 close(p[1]); 72 return -1; 73 } 74 switch(pid = fork()){ 75 case -1: 76 close(p[0]); 77 close(p[1]); 78 return -1; 79 case 0: 80 /* can't RFNOTEG - will lose tty */ 81 if(dir != nil ) 82 chdir(dir); /* best effort */ 83 dup2(fd[0], 0); 84 dup2(fd[1], 1); 85 dup2(fd[2], 2); 86 if(!isatty(0) && !isatty(1) && !isatty(2)) 87 rfork(RFNOTEG); 88 for(i=3; i<100; i++) 89 if(i != p[1]) 90 close(i); 91 execvp(cmd, argv); 92 fprint(p[1], "%d", errno); 93 close(p[1]); 94 _exit(0); 95 } 96 97 close(p[1]); 98 n = read(p[0], exitstr, sizeof exitstr-1); 99 close(p[0]); 100 if(n > 0){ /* exec failed */ 101 free(waitfor(pid)); 102 exitstr[n] = 0; 103 errno = atoi(exitstr); 104 return -1; 105 } 106 107 close(fd[0]); 108 if(fd[1] != fd[0]) 109 close(fd[1]); 110 if(fd[2] != fd[1] && fd[2] != fd[0]) 111 close(fd[2]); 112 return pid; 113 } 114 115 int 116 threadspawn(int fd[3], char *cmd, char *argv[]) 117 { 118 return _runthreadspawn(fd, cmd, argv, nil); 119 } 120 121 int 122 threadspawnd(int fd[3], char *cmd, char *argv[], char *dir) 123 { 124 return _runthreadspawn(fd, cmd, argv, dir); 125 } 126 127 int 128 threadspawnl(int fd[3], char *cmd, ...) 129 { 130 char **argv, *s; 131 int n, pid; 132 va_list arg; 133 134 va_start(arg, cmd); 135 for(n=0; va_arg(arg, char*) != nil; n++) 136 ; 137 n++; 138 va_end(arg); 139 140 argv = malloc(n*sizeof(argv[0])); 141 if(argv == nil) 142 return -1; 143 144 va_start(arg, cmd); 145 for(n=0; (s=va_arg(arg, char*)) != nil; n++) 146 argv[n] = s; 147 argv[n] = 0; 148 va_end(arg); 149 150 pid = threadspawn(fd, cmd, argv); 151 free(argv); 152 return pid; 153 } 154 155 int 156 _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[]) 157 { 158 int pid; 159 160 pid = threadspawn(fd, cmd, argv); 161 if(cpid){ 162 if(pid < 0) 163 chansendul(cpid, ~0); 164 else 165 chansendul(cpid, pid); 166 } 167 return pid; 168 } 169 170 void 171 threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[]) 172 { 173 if(_threadexec(cpid, fd, cmd, argv) >= 0) 174 threadexits("threadexec"); 175 } 176 177 void 178 threadexecl(Channel *cpid, int fd[3], char *cmd, ...) 179 { 180 char **argv, *s; 181 int n, pid; 182 va_list arg; 183 184 va_start(arg, cmd); 185 for(n=0; va_arg(arg, char*) != nil; n++) 186 ; 187 n++; 188 va_end(arg); 189 190 argv = malloc(n*sizeof(argv[0])); 191 if(argv == nil){ 192 if(cpid) 193 chansendul(cpid, ~0); 194 return; 195 } 196 197 va_start(arg, cmd); 198 for(n=0; (s=va_arg(arg, char*)) != nil; n++) 199 argv[n] = s; 200 argv[n] = 0; 201 va_end(arg); 202 203 pid = _threadexec(cpid, fd, cmd, argv); 204 free(argv); 205 206 if(pid >= 0) 207 threadexits("threadexecl"); 208 }