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