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