xref: /plan9-contrib/sys/src/libthread/exec.c (revision e7469f7cc458260881920c645908657cf1c4e7b7)
19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <thread.h>
49a747e4fSDavid du Colombier #include "threadimpl.h"
59a747e4fSDavid du Colombier 
69a747e4fSDavid du Colombier #define PIPEMNT	"/mnt/temp"
79a747e4fSDavid du Colombier 
89a747e4fSDavid du Colombier void
procexec(Channel * pidc,char * prog,char * args[])99a747e4fSDavid du Colombier procexec(Channel *pidc, char *prog, char *args[])
109a747e4fSDavid du Colombier {
119a747e4fSDavid du Colombier 	int n;
129a747e4fSDavid du Colombier 	Proc *p;
139a747e4fSDavid du Colombier 	Thread *t;
149a747e4fSDavid du Colombier 
159a747e4fSDavid du Colombier 	_threaddebug(DBGEXEC, "procexec %s", prog);
169a747e4fSDavid du Colombier 	/* must be only thread in proc */
179a747e4fSDavid du Colombier 	p = _threadgetproc();
189a747e4fSDavid du Colombier 	t = p->thread;
199a747e4fSDavid du Colombier 	if(p->threads.head != t || p->threads.head->nextt != nil){
209a747e4fSDavid du Colombier 		werrstr("not only thread in proc");
219a747e4fSDavid du Colombier 	Bad:
229a747e4fSDavid du Colombier 		if(pidc)
239a747e4fSDavid du Colombier 			sendul(pidc, ~0);
249a747e4fSDavid du Colombier 		return;
259a747e4fSDavid du Colombier 	}
269a747e4fSDavid du Colombier 
279a747e4fSDavid du Colombier 	/*
289a747e4fSDavid du Colombier 	 * We want procexec to behave like exec; if exec succeeds,
299a747e4fSDavid du Colombier 	 * never return, and if it fails, return with errstr set.
309a747e4fSDavid du Colombier 	 * Unfortunately, the exec happens in another proc since
319a747e4fSDavid du Colombier 	 * we have to wait for the exec'ed process to finish.
329a747e4fSDavid du Colombier 	 * To provide the semantics, we open a pipe with the
339a747e4fSDavid du Colombier 	 * write end close-on-exec and hand it to the proc that
349a747e4fSDavid du Colombier 	 * is doing the exec.  If the exec succeeds, the pipe will
359a747e4fSDavid du Colombier 	 * close so that our read below fails.  If the exec fails,
369a747e4fSDavid du Colombier 	 * then the proc doing the exec sends the errstr down the
379a747e4fSDavid du Colombier 	 * pipe to us.
389a747e4fSDavid du Colombier 	 */
399a747e4fSDavid du Colombier 	if(bind("#|", PIPEMNT, MREPL) < 0)
409a747e4fSDavid du Colombier 		goto Bad;
419a747e4fSDavid du Colombier 	if((p->exec.fd[0] = open(PIPEMNT "/data", OREAD)) < 0){
429a747e4fSDavid du Colombier 		unmount(nil, PIPEMNT);
439a747e4fSDavid du Colombier 		goto Bad;
449a747e4fSDavid du Colombier 	}
459a747e4fSDavid du Colombier 	if((p->exec.fd[1] = open(PIPEMNT "/data1", OWRITE|OCEXEC)) < 0){
469a747e4fSDavid du Colombier 		close(p->exec.fd[0]);
479a747e4fSDavid du Colombier 		unmount(nil, PIPEMNT);
489a747e4fSDavid du Colombier 		goto Bad;
499a747e4fSDavid du Colombier 	}
509a747e4fSDavid du Colombier 	unmount(nil, PIPEMNT);
519a747e4fSDavid du Colombier 
529a747e4fSDavid du Colombier 	/* exec in parallel via the scheduler */
539a747e4fSDavid du Colombier 	assert(p->needexec==0);
549a747e4fSDavid du Colombier 	p->exec.prog = prog;
559a747e4fSDavid du Colombier 	p->exec.args = args;
569a747e4fSDavid du Colombier 	p->needexec = 1;
579a747e4fSDavid du Colombier 	_sched();
589a747e4fSDavid du Colombier 
599a747e4fSDavid du Colombier 	close(p->exec.fd[1]);
609a747e4fSDavid du Colombier 	if((n = read(p->exec.fd[0], p->exitstr, ERRMAX-1)) > 0){	/* exec failed */
619a747e4fSDavid du Colombier 		p->exitstr[n] = '\0';
629a747e4fSDavid du Colombier 		errstr(p->exitstr, ERRMAX);
639a747e4fSDavid du Colombier 		close(p->exec.fd[0]);
649a747e4fSDavid du Colombier 		goto Bad;
659a747e4fSDavid du Colombier 	}
669a747e4fSDavid du Colombier 	close(p->exec.fd[0]);
679a747e4fSDavid du Colombier 
689a747e4fSDavid du Colombier 	if(pidc)
699a747e4fSDavid du Colombier 		sendul(pidc, t->ret);
709a747e4fSDavid du Colombier 
719a747e4fSDavid du Colombier 	/* wait for exec'ed program, then exit */
729a747e4fSDavid du Colombier 	_schedexecwait();
739a747e4fSDavid du Colombier }
749a747e4fSDavid du Colombier 
759a747e4fSDavid du Colombier void
procexecl(Channel * pidc,char * f,...)769a747e4fSDavid du Colombier procexecl(Channel *pidc, char *f, ...)
779a747e4fSDavid du Colombier {
789a747e4fSDavid du Colombier 	procexec(pidc, f, &f+1);
799a747e4fSDavid du Colombier }
809a747e4fSDavid du Colombier 
81*e7469f7cSDavid du Colombier static void
execproc(void * v)82*e7469f7cSDavid du Colombier execproc(void *v)
83*e7469f7cSDavid du Colombier {
84*e7469f7cSDavid du Colombier 	Execjob *e;
85*e7469f7cSDavid du Colombier 
86*e7469f7cSDavid du Colombier 	e = v;
87*e7469f7cSDavid du Colombier 	rfork(RFFDG);
88*e7469f7cSDavid du Colombier 	dup(e->fd[0], 0);
89*e7469f7cSDavid du Colombier 	dup(e->fd[1], 1);
90*e7469f7cSDavid du Colombier 	dup(e->fd[2], 2);
91*e7469f7cSDavid du Colombier 	procexec(e->c, e->cmd, e->argv);
92*e7469f7cSDavid du Colombier 	threadexits(nil);
93*e7469f7cSDavid du Colombier }
94*e7469f7cSDavid du Colombier 
95*e7469f7cSDavid du Colombier int
threadspawn(int fd[3],char * cmd,char * argv[])96*e7469f7cSDavid du Colombier threadspawn(int fd[3], char *cmd, char *argv[])
97*e7469f7cSDavid du Colombier {
98*e7469f7cSDavid du Colombier 	int pid;
99*e7469f7cSDavid du Colombier 	Execjob e;
100*e7469f7cSDavid du Colombier 
101*e7469f7cSDavid du Colombier 	e.fd = fd;
102*e7469f7cSDavid du Colombier 	e.cmd = cmd;
103*e7469f7cSDavid du Colombier 	e.argv = argv;
104*e7469f7cSDavid du Colombier 	e.c = chancreate(sizeof(void*), 0);
105*e7469f7cSDavid du Colombier 	proccreate(execproc, &e, 65536);
106*e7469f7cSDavid du Colombier 	close(fd[0]);
107*e7469f7cSDavid du Colombier 	close(fd[1]);
108*e7469f7cSDavid du Colombier 	close(fd[2]);
109*e7469f7cSDavid du Colombier 	pid = recvul(e.c);
110*e7469f7cSDavid du Colombier 	chanfree(e.c);
111*e7469f7cSDavid du Colombier 	return pid;
112*e7469f7cSDavid du Colombier }
113*e7469f7cSDavid du Colombier 
114*e7469f7cSDavid du Colombier int
threadspawnl(int fd[3],char * cmd,...)115*e7469f7cSDavid du Colombier threadspawnl(int fd[3], char *cmd, ...)
116*e7469f7cSDavid du Colombier {
117*e7469f7cSDavid du Colombier 	char **argv, *s;
118*e7469f7cSDavid du Colombier 	int n, pid;
119*e7469f7cSDavid du Colombier 	va_list arg;
120*e7469f7cSDavid du Colombier 
121*e7469f7cSDavid du Colombier 	va_start(arg, cmd);
122*e7469f7cSDavid du Colombier 	for(n=0; va_arg(arg, char*) != nil; n++)
123*e7469f7cSDavid du Colombier 		;
124*e7469f7cSDavid du Colombier 	n++;
125*e7469f7cSDavid du Colombier 	va_end(arg);
126*e7469f7cSDavid du Colombier 
127*e7469f7cSDavid du Colombier 	argv = malloc(n*sizeof(argv[0]));
128*e7469f7cSDavid du Colombier 	if(argv == nil)
129*e7469f7cSDavid du Colombier 		return -1;
130*e7469f7cSDavid du Colombier 
131*e7469f7cSDavid du Colombier 	va_start(arg, cmd);
132*e7469f7cSDavid du Colombier 	for(n=0; (s=va_arg(arg, char*)) != nil; n++)
133*e7469f7cSDavid du Colombier 		argv[n] = s;
134*e7469f7cSDavid du Colombier 	argv[n] = 0;
135*e7469f7cSDavid du Colombier 	va_end(arg);
136*e7469f7cSDavid du Colombier 
137*e7469f7cSDavid du Colombier 	pid = threadspawn(fd, cmd, argv);
138*e7469f7cSDavid du Colombier 	free(argv);
139*e7469f7cSDavid du Colombier 	return pid;
140*e7469f7cSDavid du Colombier }
141