]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libthread/exec.c
libthread: use devdup instead of mounting pipe to /mnt/temp for close-on-exec in...
[plan9front.git] / sys / src / libthread / exec.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "threadimpl.h"
5
6 void
7 procexec(Channel *pidc, char *prog, char *args[])
8 {
9         int n;
10         Proc *p;
11         Thread *t;
12
13         _threaddebug(DBGEXEC, "procexec %s", prog);
14         /* must be only thread in proc */
15         p = _threadgetproc();
16         t = p->thread;
17         if(p->threads.head != t || p->threads.head->nextt != nil){
18                 werrstr("not only thread in proc");
19         Bad:
20                 if(pidc)
21                         sendul(pidc, ~0);
22                 return;
23         }
24
25         /*
26          * We want procexec to behave like exec; if exec succeeds,
27          * never return, and if it fails, return with errstr set.
28          * Unfortunately, the exec happens in another proc since
29          * we have to wait for the exec'ed process to finish.
30          * To provide the semantics, we open a pipe with the 
31          * write end close-on-exec and hand it to the proc that
32          * is doing the exec.  If the exec succeeds, the pipe will
33          * close so that our read below fails.  If the exec fails,
34          * then the proc doing the exec sends the errstr down the
35          * pipe to us.
36          */
37         if(pipe(p->exec.fd) < 0)
38                 goto Bad;
39         snprint(p->exitstr, ERRMAX, "/fd/%d", p->exec.fd[1]);
40         if((n = open(p->exitstr, OWRITE|OCEXEC)) < 0){
41                 close(p->exec.fd[0]);
42                 close(p->exec.fd[1]);
43                 goto Bad;
44         }
45         close(p->exec.fd[1]);
46         p->exec.fd[1] = n;
47
48         /* exec in parallel via the scheduler */
49         assert(p->needexec==0);
50         p->exec.prog = prog;
51         p->exec.args = args;
52         p->needexec = 1;
53         _sched();
54
55         close(p->exec.fd[1]);
56         if((n = read(p->exec.fd[0], p->exitstr, ERRMAX-1)) > 0){        /* exec failed */
57                 p->exitstr[n] = '\0';
58                 errstr(p->exitstr, ERRMAX);
59                 close(p->exec.fd[0]);
60                 goto Bad;
61         }
62         close(p->exec.fd[0]);
63
64         if(pidc)
65                 sendul(pidc, t->ret);
66
67         /* wait for exec'ed program, then exit */
68         _schedexecwait();
69 }
70
71 void
72 procexecl(Channel *pidc, char *f, ...)
73 {
74         procexec(pidc, f, &f+1);
75 }
76