aboutsummaryrefslogtreecommitdiff
path: root/src/libthread/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libthread/exec.c')
-rw-r--r--src/libthread/exec.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/src/libthread/exec.c b/src/libthread/exec.c
new file mode 100644
index 00000000..bcf20802
--- /dev/null
+++ b/src/libthread/exec.c
@@ -0,0 +1,77 @@
+#include "threadimpl.h"
+
+#define PIPEMNT "/mnt/temp"
+
+void
+procexec(Channel *pidc, char *prog, char *args[])
+{
+ int n;
+ Proc *p;
+ Thread *t;
+
+ _threaddebug(DBGEXEC, "procexec %s", prog);
+ /* must be only thread in proc */
+ p = _threadgetproc();
+ t = p->thread;
+ if(p->threads.head != t || p->threads.head->nextt != nil){
+ werrstr("not only thread in proc");
+ Bad:
+ if(pidc)
+ sendul(pidc, ~0);
+ return;
+ }
+
+ /*
+ * We want procexec to behave like exec; if exec succeeds,
+ * never return, and if it fails, return with errstr set.
+ * Unfortunately, the exec happens in another proc since
+ * we have to wait for the exec'ed process to finish.
+ * To provide the semantics, we open a pipe with the
+ * write end close-on-exec and hand it to the proc that
+ * is doing the exec. If the exec succeeds, the pipe will
+ * close so that our read below fails. If the exec fails,
+ * then the proc doing the exec sends the errstr down the
+ * pipe to us.
+ */
+ if(bind("#|", PIPEMNT, MREPL) < 0)
+ goto Bad;
+ if((p->exec.fd[0] = open(PIPEMNT "/data", OREAD)) < 0){
+ unmount(nil, PIPEMNT);
+ goto Bad;
+ }
+ if((p->exec.fd[1] = open(PIPEMNT "/data1", OWRITE|OCEXEC)) < 0){
+ close(p->exec.fd[0]);
+ unmount(nil, PIPEMNT);
+ goto Bad;
+ }
+ unmount(nil, PIPEMNT);
+
+ /* exec in parallel via the scheduler */
+ assert(p->needexec==0);
+ p->exec.prog = prog;
+ p->exec.args = args;
+ p->needexec = 1;
+ _sched();
+
+ close(p->exec.fd[1]);
+ if((n = read(p->exec.fd[0], p->exitstr, ERRMAX-1)) > 0){ /* exec failed */
+ p->exitstr[n] = '\0';
+ errstr(p->exitstr, ERRMAX);
+ close(p->exec.fd[0]);
+ goto Bad;
+ }
+ close(p->exec.fd[0]);
+
+ if(pidc)
+ sendul(pidc, t->ret);
+
+ /* wait for exec'ed program, then exit */
+ _schedexecwait();
+}
+
+void
+procexecl(Channel *pidc, char *f, ...)
+{
+ procexec(pidc, f, &f+1);
+}
+