コード例 #1
0
ファイル: client.c プロジェクト: rminnich/harvey
static void
execthread(void *a)
{
	Client *c;
	int p;
	char tmp[32];

	c = a;
	snprint(tmp, sizeof tmp, "exec%d", c->num);
	threadsetname(tmp);
	c->execpid = chancreate(sizeof(ulong), 0);
	proccreate(execproc, c, STACK);
	p = recvul(c->execpid);
	chanfree(c->execpid);
	c->execpid = nil;
	close(c->fd[1]);
	c->fd[1] = c->fd[0];
	if(p != -1){
		c->pid = p;
		c->activethread = 2;
		threadcreate(readthread, c, STACK);
		threadcreate(writethread, c, STACK);
		if(c->execreq)
			respond(c->execreq, nil);
	}else{
		if(c->execreq)
			respond(c->execreq, c->err);
	}
}
コード例 #2
0
ファイル: server.c プロジェクト: 00001/plan9port
static void
sunrpcproc(void *v)
{
	threadcreate(sunrpcreplythread, v, SunStackSize);
	threadcreate(sunrpcrequestthread, v, SunStackSize);
	threadcreate(sunrpcforkthread, v, SunStackSize);

}
コード例 #3
0
ファイル: server.c プロジェクト: 99years/plan9
static void
sunRpcProc(void *v)
{
	threadcreate(sunRpcReplyThread, v, SunStackSize);
	threadcreate(sunRpcRequestThread, v, SunStackSize);
	threadcreate(sunRpcForkThread, v, SunStackSize);

}
コード例 #4
0
ファイル: 9pserve.c プロジェクト: 00001/plan9port
int
xopenfd(Msg *m)
{
	char errs[ERRMAX];
	int n, p[2];
	Conn *nc;

	if(pipe(p) < 0){
		rerrstr(errs, sizeof errs);
		err(m, errs);
		/* XXX return here? */
	}
	if(verbose) fprint(2, "%T xopen pipe %d %d...", p[0], p[1]);

	/* now we're committed. */

	/* a new connection for this fid */
	nc = emalloc(sizeof(Conn));
	nc->internal = chancreate(sizeof(void*), 0);

	/* a ref for us */
	nc->fdfid = m->fid;
	m->fid->ref++;
	nc->fdfid->openfd++;
	nc->fdmode = m->tx.mode;
	nc->fd = p[0];

	/* a thread to tend the pipe */
	threadcreate(openfdthread, nc, STACK);

	/* if mode is ORDWR, that openfdthread will write; start a reader */
	if((m->tx.mode&3) == ORDWR){
		nc = emalloc(sizeof(Conn));
		nc->internal = chancreate(sizeof(void*), 0);
		nc->fdfid = m->fid;
		m->fid->ref++;
		nc->fdfid->openfd++;
		nc->fdmode = OREAD;
		nc->fd = dup(p[0], -1);
		threadcreate(openfdthread, nc, STACK);
	}

	/* steal fid from other connection */
	if(delhash(m->c->fid, m->fid->cfid, m->fid) == 0)
		fidput(m->fid);

	/* rewrite as Ropenfd */
	m->rx.type = Ropenfd;
	n = GBIT32(m->rpkt);
	m->rpkt = erealloc(m->rpkt, n+4);
	PBIT32(m->rpkt+n, p[1]);
	n += 4;
	PBIT32(m->rpkt, n);
	m->rpkt[4] = Ropenfd;
	m->rx.unixfd = p[1];
	return 0;
}
コード例 #5
0
ファイル: statusbar.c プロジェクト: 00001/plan9port
void
threadmain(int argc, char **argv)
{
	char *p;
	int lfd;

	p = "300x40@100,100";
	
	ARGBEGIN{
	case 'W':
		p = ARGF();
		break;
	case 't':
		textmode = 1;
		break;
	case 'k':
		nokill = 1;
		break;
	default:
		usage();
	}ARGEND;

	if(argc != 1)
		usage();

	winsize = p;

	title = argv[0];

	lfd = dup(0, -1);
	Binit(&b, lfd, OREAD);

	rbar = Rect(0, 0, 60, 1);
	if (!textmode){
		if(initdraw(0, nil, "bar") < 0)
			sysfatal("initdraw: %r");
		initcolor();
		if((mc = initmouse(nil, screen)) == nil)
			sysfatal("initmouse: %r");
		if((kc = initkeyboard(nil)) == nil)
			sysfatal("initkeyboard: %r");
		display->locking = 1;
		threadcreate(resizethread, nil, STACK);
		threadcreate(keyboardthread, nil, STACK);
		threadcreate(mousethread, nil, STACK);
		resize();
		unlockdisplay(display);
	}
	proccreate(updateproc, nil, STACK);
}
コード例 #6
0
ファイル: pipe.c プロジェクト: CoryXie/nix-os
void
startpipe(void)
{
	newpipechan = chancreate(sizeof(Window*), 0);
	threadcreate(newpipethread, nil, STACK);
	snarffd = open("/dev/snarf", OREAD|OCEXEC);
}
コード例 #7
0
ファイル: wait.c プロジェクト: 00001/plan9port
void
twaitinit(void)
{
	threadwaitchan();	/* allocate it before returning */
	twaitchan = chancreate(sizeof(Waitreq), 10);
	threadcreate(waitthread, nil, 128*1024);
}
コード例 #8
0
ファイル: look.c プロジェクト: 9fans/plan9port
void
startplumbing(void)
{
	cplumb = chancreate(sizeof(Plumbmsg*), 0);
	chansetname(cplumb, "cplumb");
	threadcreate(plumbthread, nil, STACK);
}
コード例 #9
0
ファイル: plumb.c プロジェクト: 99years/plan9
void
plumbstart(void)
{
	plumbchan = chancreate(sizeof(Plumbmsg*), 0);
	proccreate(plumbwebproc, nil, STACK);
	threadcreate(plumbwebthread, nil, STACK);
}
コード例 #10
0
ファイル: 9pserve.c プロジェクト: 00001/plan9port
void
listenthread(void *arg)
{
	Conn *c;
	Ioproc *io;

	io = ioproc();
	USED(arg);
	threadsetname("listen %s", adir);
	for(;;){
		c = emalloc(sizeof(Conn));
		c->fd = iolisten(io, adir, c->dir);
		if(c->fd < 0){
			if(verbose) fprint(2, "%T listen: %r\n");
			close(afd);
			free(c);
			return;
		}
		c->inc = chancreate(sizeof(void*), 0);
		c->internal = chancreate(sizeof(void*), 0);
		c->inq = qalloc();
		c->outq = qalloc();
		c->outqdead = chancreate(sizeof(void*), 0);
		if(verbose) fprint(2, "%T incoming call on %s\n", c->dir);
		threadcreate(connthread, c, STACK);
	}	
}
コード例 #11
0
ファイル: LeapRecorder.cpp プロジェクト: qingkaishi/canary
    void OnInit(int svsNum) {
        printf("OnInit-Record\n");
        initializeSigRoutine();

        //start = true;
        num_shared_vars = svsNum + 2; // one for fork, and the other is for synchronizations

        for (int i = 0; i < MAX_THREAD_NUM; i++) {
            thread_idx_map[i] = 0;
        }

        initialize(num_shared_vars); // initialize locks

        GLOG = new unsigned*[num_shared_vars];
        GIDX = new unsigned[num_shared_vars];
        for (int i = 0; i < num_shared_vars; i++) {
            GLOG[i] = new unsigned[MAX_LOG_LEN];
            GIDX[i] = 0;
        }

        // main thread.
        pthread_t tid = pthread_self();
        if (threadid(tid) == -1) {
            threadcreate(tid);
        }

        //gettimeofday(&tpstart, NULL);
    }
コード例 #12
0
ファイル: wiki.c プロジェクト: AustenConrad/plan-9
int
wikidiff(Wiki *w)
{
	Diffarg *d;
	char *p, *q, *r;
	Wiki *nw;

	p = emalloc(strlen(w->arg)+10);
	strcpy(p, w->arg);
	if(q = strchr(p, '/'))
		*q = '\0';
	r = estrdup(p);
	strcat(p, "/+Diff");

	nw = emalloc(sizeof *w);
	nw->arg = p;
	nw->win = newwindow();
	nw->special = 1;

	d = emalloc(sizeof(*d));
	d->w = nw;
	d->dir = r;
	wikiname(nw->win, p);
	proccreate(wineventproc, nw->win, STACK);
	proccreate(execdiff, d, STACK);
	threadcreate(wikithread, nw, STACK);
	return 1;
}
コード例 #13
0
ファイル: ftdi.c プロジェクト: 99years/plan9
static int
ftinit(Serialport *p)
{
	Serial *ser;
	uint timerval;
	int res;

	ser = p->s;
	if(p->isjtag){
		res = ftdiwrite(p, FTSETFLOWCTRL, 0, FTDISABLEFLOWCTRL);
		if(res < 0)
			return -1;
		res = ftdiread(p, FTSETLATENCYTIMER, 0, (uchar *)&timerval,
			FTLATENCYTIMERSZ);
		if(res < 0)
			return -1;
		dsprint(2, "serial: jtag latency timer is %d\n", timerval);
		timerval = 2;
		ftdiwrite(p, FTLATENCYDEFAULT, 0, FTSETLATENCYTIMER);
		res = ftdiread(p, FTSETLATENCYTIMER, 0, (uchar *)&timerval,
			FTLATENCYTIMERSZ);
		if(res < 0)
			return -1;

		dsprint(2, "serial: jtag latency timer set to %d\n", timerval);
		/* may be unnecessary */
		devctl(p->epin,  "timeout 5000");
		devctl(p->epout, "timeout 5000");
		/* 0xb is the mask for lines. plug dependant? */
		ftdiwrite(p, BMMPSSE|0x0b, 0, FTSETBITMODE);
	}
	incref(ser->dev);
	threadcreate(statusreader, p, 8*1024);
	return 0;
}
コード例 #14
0
ファイル: news.c プロジェクト: carriercomm/plan9-gpl
Article*
newpost(void)
{
	Article *m;
	char *p, tmp[40];
	static int nnew;

	m = emalloc(sizeof *m);
	sprint(tmp, "Post%d", ++nnew);
	p = estrstrdup(dir, tmp);

	m->w = newwindow();
	proccreate(wineventproc, m->w, STACK);
	winname(m->w, p);
	wintagwrite(m->w, "Post ", 5);
	m->sayspost = 1;
	m->ispost = 1;
	threadcreate(mesgthread, m, STACK);

	if(mlist){
		m->next = mlist;
		mlist->prev = m;
	}
	mlist = m;
	return m;
}
コード例 #15
0
ファイル: 9pserve.c プロジェクト: 00001/plan9port
void
mainproc(void *v)
{
	int n, nn;
	Fcall f;
	USED(v);

	atnotify(ignorepipe, 1);
	fmtinstall('D', dirfmt);
	fmtinstall('M', dirmodefmt);
	fmtinstall('F', fcallfmt);
	fmtinstall('H', encodefmt);

	outq = qalloc();
	inq = qalloc();

	if(!versioned){
		f.type = Tversion;
		f.version = "9P2000";
		f.msize = msize;
		f.tag = NOTAG;
		n = convS2M(&f, vbuf, sizeof vbuf);
		if(n <= BIT16SZ)
			sysfatal("convS2M conversion error");
		if(verbose > 1) fprint(2, "%T * <- %F\n", &f);
		nn = write(1, vbuf, n);
		if(n != nn)
			sysfatal("error writing Tversion: %r\n");
		n = read9pmsg(0, vbuf, sizeof vbuf);
		if(n < 0)
			sysfatal("read9pmsg failure");
		if(convM2S(vbuf, n, &f) != n)
			sysfatal("convM2S failure");
		if(f.msize < msize)
			msize = f.msize;
		if(verbose > 1) fprint(2, "%T * -> %F\n", &f);
	}

	threadcreate(inputthread, nil, STACK);
	threadcreate(outputthread, nil, STACK);

/*	if(rootfid) */
/*		dorootstat(); */
	
	threadcreate(listenthread, nil, STACK);
	threadexits(0);
}
コード例 #16
0
ファイル: pipe.c プロジェクト: CoryXie/nix-os
void
newpipethread(void*)
{
	Window *w;

	while(w = recvp(newpipechan))
		threadcreate(pipectl, w, STACK);
}
コード例 #17
0
ファイル: server.c プロジェクト: 99years/plan9
static void
sunRpcForkThread(void *v)
{
	SunSrv *srv = v;
	Targ t;

	while(recv(srv->cthread, &t) == 1)
		threadcreate(t.fn, t.arg, SunStackSize);
}
コード例 #18
0
ファイル: fsys.c プロジェクト: npe9/harvey
Filsys*
filsysinit(Channel *cxfidalloc)
{
	int n, fd, pid, p0;
	Filsys *fs;
	Channel *c;
	char buf[128];

	fs = emalloc(sizeof(Filsys));
	if(cexecpipe(&fs->cfd, &fs->sfd) < 0)
		goto Rescue;
	fmtinstall('F', fcallfmt);
	clockfd = open("/dev/time", OREAD|OCEXEC);
	fd = open("/dev/user", OREAD);
	strcpy(buf, "Jean-Paul_Belmondo");
	if(fd >= 0){
		n = read(fd, buf, sizeof buf-1);
		if(n > 0)
			buf[n] = 0;
		close(fd);
	}
	fs->user = estrdup(buf);
	fs->cxfidalloc = cxfidalloc;
	pid = getpid();

	/*
	 * Create and post wctl pipe
	 */
	if(cexecpipe(&p0, &wctlfd) < 0)
		goto Rescue;
	sprint(srvwctl, "/srv/riowctl.%s.%d", fs->user, pid);
	post(srvwctl, "wctl", p0);
	close(p0);

	/*
	 * Start server processes
	 */
	c = chancreate(sizeof(char*), 0);
	if(c == nil)
		error("wctl channel");
	proccreate(wctlproc, c, 4096);
	threadcreate(wctlthread, c, 4096);
	proccreate(filsysproc, fs, 10000);

	/*
	 * Post srv pipe
	 */
	sprint(srvpipe, "/srv/rio.%s.%d", fs->user, pid);
	post(srvpipe, "wsys", fs->cfd);

	return fs;

Rescue:
	free(fs);
	return nil;
}
コード例 #19
0
sqInt ioSetInputSemaphore(sqInt semaIndex) {
	if (semaIndex == 0) {
		success(0);
	}
	else {
		//Initialize thread and mouse/keyboard
		eventThreadID = threadcreate(eventThread,(void*)semaIndex,2048);
	}
	return true;
}
コード例 #20
0
ファイル: nfs3srv.c プロジェクト: 00001/plan9port
void
mount3proc(void *v)
{
	Channel *c;
	SunMsg *m;

	threadsetname("mount1");
	c = v;
	while((m=recvp(c)) != nil)
		threadcreate(rmount3, m, SunStackSize);
}
コード例 #21
0
ファイル: nfs3srv.c プロジェクト: 00001/plan9port
void
nfs3proc(void *v)
{
	Channel *c;
	SunMsg *m;

	c = v;
	threadsetname("nfs3");
	while((m = recvp(c)) != nil)
		threadcreate(rnfs3, m, SunStackSize);
}
コード例 #22
0
ファイル: wiki.c プロジェクト: AustenConrad/plan-9
void
wikinew(char *arg)
{
	static int n;
	Wiki *w;

	w = emalloc(sizeof *w);
	if(arg)
		arg = estrdup(arg);
	w->arg = arg;
	w->win = newwindow();
	w->isnew = ++n;
	proccreate(wineventproc, w->win, STACK);
	threadcreate(wikithread, w, STACK);
}
コード例 #23
0
ファイル: news.c プロジェクト: carriercomm/plan9-gpl
int
mesgopen(char *s)
{
	char *p, tmp[40];
	int fd, n;
	Article *m;

	n = atoi(s);
	if(n==0)
		return 0;

	for(m=mlist; m; m=m->next){
		if(m->n == n){
			ctlprint(m->w->ctl, "show\n");
			return 1;
		}
	}

	sprint(tmp, "%d/article", n);
	p = estrstrdup(dir, tmp);
	if((fd = open(p, OREAD)) < 0){
		free(p);	
		return 0;
	}

	m = emalloc(sizeof(*m));
	m->w = newwindow();
	m->n = n;
	proccreate(wineventproc, m->w, STACK);
	p[strlen(p)-strlen("article")] = '\0';
	winname(m->w, p);
	if(canpost)
		wintagwrite(m->w, "Reply ", 6);
	wintagwrite(m->w, "Headers ", 8);

	free(p);
	if(mlist){
		m->next = mlist;
		mlist->prev = m;
	}
	mlist = m;
	threadcreate(mesgthread, m, STACK);

	fillmesgwindow(fd, m);
	close(fd);
	windormant(m->w);
	return 1;
}
コード例 #24
0
ファイル: plan9.c プロジェクト: 00001/plan9port
int
plumbstart(void)
{
	CFid *fid;

	plumbfd = plumbopen("send", OWRITE|OCEXEC);	/* not open is ok */
	fid = plumbopenfid("edit", OREAD|OCEXEC);
	if(fid == nil)
		return -1;
	plumbc = chancreate(sizeof(int), 0);
	chansetname(plumbc, "plumbc");
	if(plumbc == nil){
		fsclose(fid);
		return -1;
	}
	threadcreate(plumbproc, fid, STACK);
	return 1;
}
コード例 #25
0
ファイル: edit.c プロジェクト: npe9/harvey
void
editcmd(Text *ct, Rune *r, uint n)
{
	char *err;

	if(n == 0)
		return;
	if(2*n > RBUFSIZE){
		warning(nil, "string too long\n");
		return;
	}

	allwindows(alleditinit, nil);
	if(cmdstartp)
		free(cmdstartp);
	cmdstartp = runemalloc(n+2);
	runemove(cmdstartp, r, n);
	if(r[n] != '\n')
		cmdstartp[n++] = '\n';
	cmdstartp[n] = '\0';
	cmdendp = cmdstartp+n;
	cmdp = cmdstartp;
	if(ct->w == nil)
		curtext = nil;
	else
		curtext = &ct->w->body;
	resetxec();
	if(editerrc == nil){
		editerrc = chancreate(sizeof(char*), 0);
		lastpat = allocstring(0);
	}
	threadcreate(editthread, nil, STACK);
	err = recvp(editerrc);
	editing = Inactive;
	if(err != nil){
		if(err[0] != '\0')
			warning(nil, "Edit: %s\n", err);
		free(err);
	}

	/* update everyone whose edit log has data */
	allwindows(allupdate, nil);
}
コード例 #26
0
ファイル: LeapRecorder.cpp プロジェクト: qingkaishi/canary
    void OnFork(long forked_tid_ptr) {
        if (!start) {
            return;
        }

        pthread_t ftid = *((pthread_t*) forked_tid_ptr);
        if (threadid(ftid) == -1) {
            threadcreate(ftid);
        }
#ifdef DEBUG
        printf("OnFork\n");
#endif
        pthread_t tid = pthread_self();
        int _tid = -1;
        do {
            _tid = threadid(tid);
        } while (_tid < 0);
        store(num_shared_vars - 1, _tid);
        forkunlock(num_shared_vars - 1);
    }
コード例 #27
0
ファイル: acme.c プロジェクト: UNGLinux/9base
void
xfidallocthread(void *v)
{
	Xfid *xfree, *x;
	enum { Alloc, Free, N };
	static Alt alts[N+1];

	USED(v);
	threadsetname("xfidallocthread");
	alts[Alloc].c = cxfidalloc;
	alts[Alloc].v = nil;
	alts[Alloc].op = CHANRCV;
	alts[Free].c = cxfidfree;
	alts[Free].v = &x;
	alts[Free].op = CHANRCV;
	alts[N].op = CHANEND;

	xfree = nil;
	for(;;){
		switch(alt(alts)){
		case Alloc:
			x = xfree;
			if(x)
				xfree = x->next;
			else{
				x = emalloc(sizeof(Xfid));
				x->c = chancreate(sizeof(void(*)(Xfid*)), 0);
				chansetname(x->c, "xc%p", x->c);
				x->arg = x;
				threadcreate(xfidctl, x->arg, STACK);
			}
			sendp(cxfidalloc, x);
			break;
		case Free:
			x->next = xfree;
			xfree = x;
			break;
		}
	}
}
コード例 #28
0
ファイル: vbackup.c プロジェクト: 00001/plan9port
void
ventiproc(void *dummy)
{
	int i;
	Block *db;
	u32int bno;
	u64int bsize;

	USED(dummy);

	proccreate(vtsendproc, z, STACK);
	proccreate(vtrecvproc, z, STACK);

	writechan = chancreate(sizeof(WriteReq), 0);
	for(i=0; i<nwritethread; i++)
		threadcreate(writethread, nil, STACK);
	vtcachesetwrite(zcache, myvtwrite);

	bsize = fsys->blocksize;
	vtfilelock(vfile, -1);
	while((db = qread(qventi, &bno)) != nil){
		if(nop){
			blockput(db);
			continue;
		}
		if(vtfilewrite(vfile, db->data, bsize, bno*bsize) != bsize)
			sysfatal("ventiproc vtfilewrite: %r");
		if(vtfileflushbefore(vfile, (bno+1)*bsize) < 0)
			sysfatal("ventiproc vtfileflushbefore: %r");
		blockput(db);
	}
	vtfileunlock(vfile);
	vtcachesetwrite(zcache, nil);
	for(i=0; i<nwritethread; i++)
		send(writechan, nil);
	chanfree(writechan);
	if(statustime)
		print("# %T venti proc exiting - nsend %d nrecv %d\n", nsend, nrecv);
	runlock(&endlk);
}
コード例 #29
0
ファイル: wiki.c プロジェクト: AustenConrad/plan-9
int
wikiopen(char *arg, char *addr)
{
	Dir *d;
	char *p;
	Wiki *w;

/*
	if(arg==nil){
		if(write(mapfd, title, strlen(title)) < 0
		|| seek(mapfd, 0, 0) < 0 || (n=read(mapfd, tmp, sizeof(tmp)-2)) < 0){
			fprint(2, "Wiki: no page '%s' found: %r\n", title);
			return -1;
		}
		if(tmp[n-1] == '\n')
			tmp[--n] = '\0';
		tmp[n++] = '/';
		tmp[n] = '\0';
		arg = tmp;
	}
*/

	/* replace embedded '\n' in links by ' ' */
	for(p=arg; *p; p++)
		if(*p=='\n')
			*p = ' ';

	if(strncmp(arg, dir, strlen(dir))==0 && arg[strlen(dir)]=='/' && arg[strlen(dir)+1])
		arg += strlen(dir)+1;
	else if(arg[0] == '/')
		return -1;

	if((d = dirstat(arg)) == nil)
		return -1;

	if((d->mode&DMDIR) && arg[strlen(arg)-1] != '/'){
		p = emalloc(strlen(arg)+2);
		strcpy(p, arg);
		strcat(p, "/");
		arg = p;
	}else if(!(d->mode&DMDIR) && arg[strlen(arg)-1]=='/'){
		arg = estrdup(arg);
		arg[strlen(arg)-1] = '\0';
	}else
		arg = estrdup(arg);
	free(d);

	/* rewrite /current into / */
	if(strlen(arg) > 8 && strcmp(arg+strlen(arg)-8, "/current")==0)
		arg[strlen(arg)-8+1] = '\0';

	/* look for window already open */
	for(w=wlist; w; w=w->next){
		if(strcmp(w->arg, arg)==0){
			ctlprint(w->win->ctl, "show\n");
			return 0;
		}
	}

	w = emalloc(sizeof *w);
	w->arg = arg;
	w->addr = addr;
	w->win = newwindow();
	link(w);

	proccreate(wineventproc, w->win, STACK);
	threadcreate(wikithread, w, STACK);
	return 0;
}
コード例 #30
0
ファイル: client.c プロジェクト: rminnich/harvey
void
ctlwrite(Req *r, Client *c)
{
	char *f[3], *s, *p;
	int nf;

	s = emalloc(r->ifcall.count+1);
	memmove(s, r->ifcall.data, r->ifcall.count);
	s[r->ifcall.count] = '\0';

	f[0] = s;
	p = strchr(s, ' ');
	if(p == nil)
		nf = 1;
	else{
		*p++ = '\0';
		f[1] = p;
		nf = 2;
	}

	if(f[0][0] == '\0'){
		free(s);
		respond(r, nil);
		return;
	}

	r->ofcall.count = r->ifcall.count;
	if(strcmp(f[0], "hangup") == 0){
		if(c->pid == 0){
			respond(r, "connection already hung up");
			goto Out;
		}
		postnote(PNPROC, c->pid, "kill");
		respond(r, nil);
		goto Out;
	}

	if(strcmp(f[0], "connect") == 0){
		if(c->cmd != nocmd){
			respond(r, "already have connection");
			goto Out;
		}
		if(nf == 1){
			respond(r, "need argument to connect");
			goto Out;
		}
		c->status = Exec;
		if(p = strrchr(f[1], '!'))
			*p = '\0';
		c->cmd = emalloc(4+1+strlen(f[1])+1);
		strcpy(c->cmd, "exec ");
		strcat(c->cmd, f[1]);
		c->execreq = r;
		threadcreate(execthread, c, STACK);
		goto Out;
	}

	respond(r, "bad or inappropriate control message");
Out:
	free(s);
}