1 #include <u.h> 2 #include <libc.h> 3 #include <thread.h> 4 #include "threadimpl.h" 5 6 #define PIPEMNT "/mnt/temp" 7 8 void 9 procexec(Channel *pidc, char *prog, char *args[]) 10 { 11 int n; 12 Proc *p; 13 Thread *t; 14 15 _threaddebug(DBGEXEC, "procexec %s", prog); 16 /* must be only thread in proc */ 17 p = _threadgetproc(); 18 t = p->thread; 19 if(p->threads.head != t || p->threads.head->nextt != nil){ 20 werrstr("not only thread in proc"); 21 Bad: 22 if(pidc) 23 sendul(pidc, ~0); 24 return; 25 } 26 27 /* 28 * We want procexec 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 37 * pipe to us. 38 */ 39 if(bind("#|", PIPEMNT, MREPL) < 0) 40 goto Bad; 41 if((p->exec.fd[0] = open(PIPEMNT "/data", OREAD)) < 0){ 42 unmount(nil, PIPEMNT); 43 goto Bad; 44 } 45 if((p->exec.fd[1] = open(PIPEMNT "/data1", OWRITE|OCEXEC)) < 0){ 46 close(p->exec.fd[0]); 47 unmount(nil, PIPEMNT); 48 goto Bad; 49 } 50 unmount(nil, PIPEMNT); 51 52 /* exec in parallel via the scheduler */ 53 assert(p->needexec==0); 54 p->exec.prog = prog; 55 p->exec.args = args; 56 p->needexec = 1; 57 _sched(); 58 59 close(p->exec.fd[1]); 60 if((n = read(p->exec.fd[0], p->exitstr, ERRMAX-1)) > 0){ /* exec failed */ 61 p->exitstr[n] = '\0'; 62 errstr(p->exitstr, ERRMAX); 63 close(p->exec.fd[0]); 64 goto Bad; 65 } 66 close(p->exec.fd[0]); 67 68 if(pidc) 69 sendul(pidc, t->ret); 70 71 /* wait for exec'ed program, then exit */ 72 _schedexecwait(); 73 } 74 75 void 76 procexecl(Channel *pidc, char *f, ...) 77 { 78 procexec(pidc, f, &f+1); 79 } 80 81