xref: /plan9/sys/src/libthread/exec.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
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
procexec(Channel * pidc,char * prog,char * args[])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
procexecl(Channel * pidc,char * f,...)76 procexecl(Channel *pidc, char *f, ...)
77 {
78 	procexec(pidc, f, &f+1);
79 }
80 
81