/* execcmd - proc file system execution wrapper wrapper Copyright (C) 2010, IBM Corporation, Eric Van Hensbergen (bergevan@us.ibm.com) Description: This provides a small wrapper the file system can use to boot strap the application while maintaining expected clone semantics. TODO: * fork namespace after mounting mpipes * support for ns configuration prior to exec */ #include <u.h>#include <libc.h>#include <fcall.h>#include <thread.h>#include <9p.h>#include <debug.h> static char defaultpath[] = "/proc";static char *procpath, *mmount; char Estdios[] = "execcmd: couldn't open stdios";char Ebadctl[] = "execcmd: bad ctl command";char Ebadexec[] = "execcmd: bad exec command"; /* using parsecmd for later expansion */enum{ Cexec,}; Cmdtab ctltab[]={ Cexec, "exec", 0,}; /* FIXME: debugging... */enum{ STACK = (8 * 1024),};char *extpath = 0;static voidlsproc(void *arg){ Channel *pidc = arg; // FIXME: procpath currently not used char *path = procpath; if (extpath) path = extpath; // Channel *pidc = chancreate(sizeof(ulong), 0);// char *path = arg; threadsetname("exec2fs-lsproc"); DPRINT(DFID, "lsproc (%p) (%s) (%s) (%s) (%s) pid=(%d): %r\n", pidc, "/bin/ls", "ls", "-l", path, getpid()); procexecl(pidc, "/bin/ls", "ls", path, nil); sendul(pidc, 0); threadexits(nil); } static voidusage(void){ fprint(2, "execcmd [-D] [-v debuglevel] [-s srvctl] [-L logdir]\n"); exits("usage");} voidthreadmain(int argc, char **argv){ int stdinfd; int stdoutfd; int stderrfd; int ctlfd; int ret; char *ctlbuf = emalloc9p(255); char *fname = emalloc9p(255); Cmdbuf *cb; Cmdtab *cmd; char *srvctl = nil; char *logfile; char *logdir = nil; char *x; int pid = getpid(); procpath = defaultpath; mmount = defaultpath; ARGBEGIN{ case 'D': chatty9p++; break; case 'v': x = ARGF(); if(x) vflag = atol(x); break; case 's': srvctl = ARGF(); break; case 'm': /* mntpt override */ procpath = ARGF(); break; case 'M': /* mntpt override */ mmount = ARGF(); break; case 'L': logdir = ARGF(); break; default: /* break */ usage(); exits("argument"); }ARGEND if(argc != 0){ DPRINT(DERR, "*ERROR*: number of argument mismatch\n"); usage(); exits("number of arguments"); } /* move the log file generation outside the test directory */ if(vflag > 0) { if(logdir) logfile = smprint("%s/execcmd-%d.log", logdir, getpid()); else logfile = smprint("execcmd-%d.log", getpid()); debugfd = create(logfile, OWRITE, 0666); if(debugfd <= 2){ DPRINT(DERR, "*ERROR*: could not open log file (%s)\n", logfile); exits("logfile"); } //sleep(100); DPRINT(DEXC, "Main: logfile=%s\n", logfile); free(logfile); } DPRINT(DEXC, "Inside execution wrapper: logdir=%s vflag=%d debugfd=%d\n", logdir, vflag, debugfd); DPRINT(DEXC, "\tsrvctl=%s\n", srvctl); DPRINT(DEXC, "\tprocpath=%s\n", procpath); DPRINT(DEXC, "\tmmount=%s\n", mmount); /* open our files */ ctlfd = open(srvctl, ORDWR|OCEXEC); if(ctlfd < 0){ DPRINT(DERR, "*ERROR*: could not open server ctl (%s)\n", srvctl); exits("srvctl"); } remove(srvctl); DPRINT(DEXC, "After srv ctl open\n"); ret = read(ctlfd, ctlbuf, 255); if(ret <= 0){ DPRINT(DERR, "*ERROR*: ctl read failed\n"); exits("ctl read"); } ctlbuf[ret] = 0; DPRINT(DEXC, "got ret=(%d) ctlbuf=(%s) pid=(%d)\n", ret, ctlbuf, pid); /* need to open our bit */ snprint(fname, 255, "%s/%d/stdin", mmount, pid); stdinfd = open(fname, OREAD); DPRINT(DCUR, "stdin=(%s) stdinfd=(%d)\n", fname, stdinfd); snprint(fname, 255, "%s/%d/stdout", mmount, pid); stdoutfd = open(fname, OWRITE); DPRINT(DCUR, "stdout=(%s) stdoutfd=(%d)\n", fname, stdoutfd); snprint(fname, 255, "%s/%d/stderr", mmount, pid); stderrfd = open(fname, OWRITE); DPRINT(DCUR, "stderr=(%s) stderrfd=(%d)\n", fname, stderrfd); DPRINT(DEXC, "after opening stdio pipes\n"); if((stdinfd < 0)||(stdoutfd < 0)||(stderrfd < 0)) { DPRINT(DERR, "*ERROR*: some sort of issue opening stdio pipes\n"); write(ctlfd, Estdios, strlen(Estdios)); exits("stdios"); } DPRINT(DEXC, "reporting partial success\n"); ret = write(ctlfd, "1", 1); /* report partial sucess */ if(ret <= 0){ DPRINT(DERR, "*ERROR*: ctl write failed\n"); exits("ctl write"); } DPRINT(DEXC, "waiting for cmds\n"); while((ret = read(ctlfd, ctlbuf, 255)) > 0) { DPRINT(DEXC, "received cmd \"%s\"\n", ctlbuf); cb = parsecmd(ctlbuf, ret); cmd = lookupcmd(cb, ctltab, nelem(ctltab)); if(cmd == nil) { DPRINT(DERR, "ERROR: bad ctl\n"); write(ctlfd, Ebadctl, strlen(Ebadctl)); continue; } switch(cmd->index){ case Cexec: if(cb->nf < 2) { DPRINT(DERR, "ERROR: bad exec\n"); write(ctlfd, Ebadexec, strlen(Ebadexec)); continue; } DPRINT(DEXC, "exec, duping and going\n"); dup(stdinfd, 0); dup(stdoutfd, 1); dup(stderrfd, 2); close(debugfd); debugfd = 2; free(fname); free(ctlbuf); //exits(0); /* go baby go */ exec(cb->f[1], &cb->f[1]); // FIXME: test this fail over... /* something happened report it */ DPRINT(DERR, "ERROR: something happened with the exec\n"); ctlbuf = smprint("execcmd: exec: %r"); write(ctlfd, ctlbuf, ret); /* make sure that we will not try to free fname twice... */ fname = nil; goto error; break; /* room for more commands later */ } }error: free(fname); free(ctlbuf); close(ctlfd); close(stdinfd); close(stdoutfd); close(stderrfd); exits("ctl abort");}
/*
execcmd - proc file system execution wrapper wrapper
Copyright (C) 2010, IBM Corporation,
Eric Van Hensbergen (bergevan@us.ibm.com)
Description:
This provides a small wrapper the file system can use
to boot strap the application while maintaining expected
clone semantics.
TODO:
* fork namespace after mounting mpipes
* support for ns configuration prior to exec
*/
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
#include <debug.h>
static char defaultpath[] = "/proc";
static char *procpath, *mmount;
char Estdios[] = "execcmd: couldn't open stdios";
char Ebadctl[] = "execcmd: bad ctl command";
char Ebadexec[] = "execcmd: bad exec command";
/* using parsecmd for later expansion */
enum
{
Cexec,
};
Cmdtab ctltab[]={
Cexec, "exec", 0,
};
/* FIXME: debugging... */
enum
{
STACK = (8 * 1024),
};
char *extpath = 0;
static void
lsproc(void *arg)
{
Channel *pidc = arg;
// FIXME: procpath currently not used
char *path = procpath;
if (extpath)
path = extpath;
// Channel *pidc = chancreate(sizeof(ulong), 0);
// char *path = arg;
threadsetname("exec2fs-lsproc");
DPRINT(DFID, "lsproc (%p) (%s) (%s) (%s) (%s) pid=(%d): %r\n",
pidc, "/bin/ls", "ls", "-l", path, getpid());
procexecl(pidc, "/bin/ls", "ls", path, nil);
sendul(pidc, 0);
threadexits(nil);
}
static void
usage(void)
{
fprint(2, "execcmd [-D] [-v debuglevel] [-s srvctl] [-L logdir]\n");
exits("usage");
}
void
threadmain(int argc, char **argv)
{
int stdinfd;
int stdoutfd;
int stderrfd;
int ctlfd;
int ret;
char *ctlbuf = emalloc9p(255);
char *fname = emalloc9p(255);
Cmdbuf *cb;
Cmdtab *cmd;
char *srvctl = nil;
char *logfile;
char *logdir = nil;
char *x;
int pid = getpid();
procpath = defaultpath;
mmount = defaultpath;
ARGBEGIN{
case 'D':
chatty9p++;
break;
case 'v':
x = ARGF();
if(x)
vflag = atol(x);
break;
case 's':
srvctl = ARGF();
break;
case 'm': /* mntpt override */
procpath = ARGF();
break;
case 'M': /* mntpt override */
mmount = ARGF();
break;
case 'L':
logdir = ARGF();
break;
default:
/* break */
usage();
exits("argument");
}ARGEND
if(argc != 0){
DPRINT(DERR, "*ERROR*: number of argument mismatch\n");
usage();
exits("number of arguments");
}
/* move the log file generation outside the test directory */
if(vflag > 0) {
if(logdir)
logfile = smprint("%s/execcmd-%d.log", logdir, getpid());
else
logfile = smprint("execcmd-%d.log", getpid());
debugfd = create(logfile, OWRITE, 0666);
if(debugfd <= 2){
DPRINT(DERR, "*ERROR*: could not open log file (%s)\n", logfile);
exits("logfile");
}
//sleep(100);
DPRINT(DEXC, "Main: logfile=%s\n", logfile);
free(logfile);
}
DPRINT(DEXC, "Inside execution wrapper: logdir=%s vflag=%d debugfd=%d\n", logdir, vflag, debugfd);
DPRINT(DEXC, "\tsrvctl=%s\n", srvctl);
DPRINT(DEXC, "\tprocpath=%s\n", procpath);
DPRINT(DEXC, "\tmmount=%s\n", mmount);
/* open our files */
ctlfd = open(srvctl, ORDWR|OCEXEC);
if(ctlfd < 0){
DPRINT(DERR, "*ERROR*: could not open server ctl (%s)\n", srvctl);
exits("srvctl");
}
remove(srvctl);
DPRINT(DEXC, "After srv ctl open\n");
ret = read(ctlfd, ctlbuf, 255);
if(ret <= 0){
DPRINT(DERR, "*ERROR*: ctl read failed\n");
exits("ctl read");
}
ctlbuf[ret] = 0;
DPRINT(DEXC, "got ret=(%d) ctlbuf=(%s) pid=(%d)\n", ret, ctlbuf, pid);
/* need to open our bit */
snprint(fname, 255, "%s/%d/stdin", mmount, pid);
stdinfd = open(fname, OREAD);
DPRINT(DCUR, "stdin=(%s) stdinfd=(%d)\n", fname, stdinfd);
snprint(fname, 255, "%s/%d/stdout", mmount, pid);
stdoutfd = open(fname, OWRITE);
DPRINT(DCUR, "stdout=(%s) stdoutfd=(%d)\n", fname, stdoutfd);
snprint(fname, 255, "%s/%d/stderr", mmount, pid);
stderrfd = open(fname, OWRITE);
DPRINT(DCUR, "stderr=(%s) stderrfd=(%d)\n", fname, stderrfd);
DPRINT(DEXC, "after opening stdio pipes\n");
if((stdinfd < 0)||(stdoutfd < 0)||(stderrfd < 0)) {
DPRINT(DERR, "*ERROR*: some sort of issue opening stdio pipes\n");
write(ctlfd, Estdios, strlen(Estdios));
exits("stdios");
}
DPRINT(DEXC, "reporting partial success\n");
ret = write(ctlfd, "1", 1); /* report partial sucess */
if(ret <= 0){
DPRINT(DERR, "*ERROR*: ctl write failed\n");
exits("ctl write");
}
DPRINT(DEXC, "waiting for cmds\n");
while((ret = read(ctlfd, ctlbuf, 255)) > 0) {
DPRINT(DEXC, "received cmd \"%s\"\n", ctlbuf);
cb = parsecmd(ctlbuf, ret);
cmd = lookupcmd(cb, ctltab, nelem(ctltab));
if(cmd == nil) {
DPRINT(DERR, "ERROR: bad ctl\n");
write(ctlfd, Ebadctl, strlen(Ebadctl));
continue;
}
switch(cmd->index){
case Cexec:
if(cb->nf < 2) {
DPRINT(DERR, "ERROR: bad exec\n");
write(ctlfd, Ebadexec, strlen(Ebadexec));
continue;
}
DPRINT(DEXC, "exec, duping and going\n");
dup(stdinfd, 0);
dup(stdoutfd, 1);
dup(stderrfd, 2);
close(debugfd);
debugfd = 2;
free(fname);
free(ctlbuf);
//exits(0);
/* go baby go */
exec(cb->f[1], &cb->f[1]);
// FIXME: test this fail over...
/* something happened report it */
DPRINT(DERR, "ERROR: something happened with the exec\n");
ctlbuf = smprint("execcmd: exec: %r");
write(ctlfd, ctlbuf, ret);
/* make sure that we will not try to free fname twice... */
fname = nil;
goto error;
break;
/* room for more commands later */
}
}
error:
free(fname);
free(ctlbuf);
close(ctlfd);
close(stdinfd);
close(stdoutfd);
close(stderrfd);
exits("ctl abort");
}