xref: /inferno-os/emu/port/devcmd.c (revision 6e425a9de8c003b5a733621a6b6730ec3cc902b8)
137da2899SCharles.Forsyth #include	"dat.h"
237da2899SCharles.Forsyth #include	"fns.h"
337da2899SCharles.Forsyth #include	"error.h"
437da2899SCharles.Forsyth 
537da2899SCharles.Forsyth enum
637da2899SCharles.Forsyth {
737da2899SCharles.Forsyth 	Qtopdir,	/* top level directory */
837da2899SCharles.Forsyth 	Qcmd,
937da2899SCharles.Forsyth 	Qclonus,
1037da2899SCharles.Forsyth 	Qconvdir,
1137da2899SCharles.Forsyth 	Qconvbase,
1237da2899SCharles.Forsyth 	Qdata = Qconvbase,
13*6e425a9dSCharles.Forsyth 	Qstderr,
1437da2899SCharles.Forsyth 	Qctl,
1537da2899SCharles.Forsyth 	Qstatus,
1637da2899SCharles.Forsyth 	Qwait,
1737da2899SCharles.Forsyth 
1837da2899SCharles.Forsyth 	Debug=0	/* to help debug os.c */
1937da2899SCharles.Forsyth };
2037da2899SCharles.Forsyth #define TYPE(x) 	((ulong)(x).path & 0xf)
2137da2899SCharles.Forsyth #define CONV(x) 	(((ulong)(x).path >> 4)&0xfff)
2237da2899SCharles.Forsyth #define QID(c, y) 	(((c)<<4) | (y))
2337da2899SCharles.Forsyth 
2437da2899SCharles.Forsyth typedef struct Conv	Conv;
2537da2899SCharles.Forsyth struct Conv
2637da2899SCharles.Forsyth {
2737da2899SCharles.Forsyth 	int	x;
2837da2899SCharles.Forsyth 	int	inuse;
29*6e425a9dSCharles.Forsyth 	int	fd[3];	/* stdin, stdout, and stderr */
30*6e425a9dSCharles.Forsyth 	int	count[3];	/* number of readers on stdin/stdout/stderr */
3137da2899SCharles.Forsyth 	int	perm;
3237da2899SCharles.Forsyth 	char*	owner;
3337da2899SCharles.Forsyth 	char*	state;
3437da2899SCharles.Forsyth 	Cmdbuf*	cmd;
3537da2899SCharles.Forsyth 	char*	dir;
3637da2899SCharles.Forsyth 	QLock	l;	/* protects state changes */
3737da2899SCharles.Forsyth 	Queue*	waitq;
3837da2899SCharles.Forsyth 	void*	child;
3937da2899SCharles.Forsyth 	char*	error;	/* on start up */
4037da2899SCharles.Forsyth 	int	nice;
4137da2899SCharles.Forsyth 	short	killonclose;
4237da2899SCharles.Forsyth 	short	killed;
4337da2899SCharles.Forsyth 	Rendez	startr;
4437da2899SCharles.Forsyth };
4537da2899SCharles.Forsyth 
4637da2899SCharles.Forsyth static struct
4737da2899SCharles.Forsyth {
4837da2899SCharles.Forsyth 	QLock	l;
4937da2899SCharles.Forsyth 	int	nc;
5037da2899SCharles.Forsyth 	int	maxconv;
5137da2899SCharles.Forsyth 	Conv**	conv;
5237da2899SCharles.Forsyth } cmd;
5337da2899SCharles.Forsyth 
5437da2899SCharles.Forsyth static	Conv*	cmdclone(char*);
5537da2899SCharles.Forsyth static	void	cmdproc(void*);
5637da2899SCharles.Forsyth 
5737da2899SCharles.Forsyth static int
cmd3gen(Chan * c,int i,Dir * dp)5837da2899SCharles.Forsyth cmd3gen(Chan *c, int i, Dir *dp)
5937da2899SCharles.Forsyth {
6037da2899SCharles.Forsyth 	Qid q;
6137da2899SCharles.Forsyth 	Conv *cv;
6237da2899SCharles.Forsyth 
6337da2899SCharles.Forsyth 	cv = cmd.conv[CONV(c->qid)];
6437da2899SCharles.Forsyth 	switch(i){
6537da2899SCharles.Forsyth 	default:
6637da2899SCharles.Forsyth 		return -1;
6737da2899SCharles.Forsyth 	case Qdata:
6837da2899SCharles.Forsyth 		mkqid(&q, QID(CONV(c->qid), Qdata), 0, QTFILE);
6937da2899SCharles.Forsyth 		devdir(c, q, "data", 0, cv->owner, cv->perm, dp);
7037da2899SCharles.Forsyth 		return 1;
71*6e425a9dSCharles.Forsyth 	case Qstderr:
72*6e425a9dSCharles.Forsyth 		mkqid(&q, QID(CONV(c->qid), Qstderr), 0, QTFILE);
73*6e425a9dSCharles.Forsyth 		devdir(c, q, "stderr", 0, cv->owner, 0444, dp);
74*6e425a9dSCharles.Forsyth 		return 1;
7537da2899SCharles.Forsyth 	case Qctl:
7637da2899SCharles.Forsyth 		mkqid(&q, QID(CONV(c->qid), Qctl), 0, QTFILE);
7737da2899SCharles.Forsyth 		devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);
7837da2899SCharles.Forsyth 		return 1;
7937da2899SCharles.Forsyth 	case Qstatus:
8037da2899SCharles.Forsyth 		mkqid(&q, QID(CONV(c->qid), Qstatus), 0, QTFILE);
8137da2899SCharles.Forsyth 		devdir(c, q, "status", 0, cv->owner, 0444, dp);
8237da2899SCharles.Forsyth 		return 1;
8337da2899SCharles.Forsyth 	case Qwait:
8437da2899SCharles.Forsyth 		mkqid(&q, QID(CONV(c->qid), Qwait), 0, QTFILE);
8537da2899SCharles.Forsyth 		devdir(c, q, "wait", 0, cv->owner, 0444, dp);
8637da2899SCharles.Forsyth 		return 1;
8737da2899SCharles.Forsyth 	}
8837da2899SCharles.Forsyth }
8937da2899SCharles.Forsyth 
9037da2899SCharles.Forsyth static int
cmdgen(Chan * c,char * name,Dirtab * d,int nd,int s,Dir * dp)9137da2899SCharles.Forsyth cmdgen(Chan *c, char *name, Dirtab *d, int nd, int s, Dir *dp)
9237da2899SCharles.Forsyth {
9337da2899SCharles.Forsyth 	Qid q;
9437da2899SCharles.Forsyth 	Conv *cv;
9537da2899SCharles.Forsyth 
9637da2899SCharles.Forsyth 	USED(name);
9737da2899SCharles.Forsyth 	USED(nd);
9837da2899SCharles.Forsyth 	USED(d);
9937da2899SCharles.Forsyth 
10037da2899SCharles.Forsyth 	if(s == DEVDOTDOT){
10137da2899SCharles.Forsyth 		switch(TYPE(c->qid)){
10237da2899SCharles.Forsyth 		case Qtopdir:
10337da2899SCharles.Forsyth 		case Qcmd:
10437da2899SCharles.Forsyth 			mkqid(&q, QID(0, Qtopdir), 0, QTDIR);
10537da2899SCharles.Forsyth 			devdir(c, q, "#C", 0, eve, DMDIR|0555, dp);
10637da2899SCharles.Forsyth 			break;
10737da2899SCharles.Forsyth 		case Qconvdir:
10837da2899SCharles.Forsyth 			mkqid(&q, QID(0, Qcmd), 0, QTDIR);
10937da2899SCharles.Forsyth 			devdir(c, q, "cmd", 0, eve, DMDIR|0555, dp);
11037da2899SCharles.Forsyth 			break;
11137da2899SCharles.Forsyth 		default:
11237da2899SCharles.Forsyth 			panic("cmdgen %llux", c->qid.path);
11337da2899SCharles.Forsyth 		}
11437da2899SCharles.Forsyth 		return 1;
11537da2899SCharles.Forsyth 	}
11637da2899SCharles.Forsyth 
11737da2899SCharles.Forsyth 	switch(TYPE(c->qid)) {
11837da2899SCharles.Forsyth 	case Qtopdir:
11937da2899SCharles.Forsyth 		if(s >= 1)
12037da2899SCharles.Forsyth 			return -1;
12137da2899SCharles.Forsyth 		mkqid(&q, QID(0, Qcmd), 0, QTDIR);
12237da2899SCharles.Forsyth 		devdir(c, q, "cmd", 0, "cmd", DMDIR|0555, dp);
12337da2899SCharles.Forsyth 		return 1;
12437da2899SCharles.Forsyth 	case Qcmd:
12537da2899SCharles.Forsyth 		if(s < cmd.nc) {
12637da2899SCharles.Forsyth 			cv = cmd.conv[s];
12737da2899SCharles.Forsyth 			mkqid(&q, QID(s, Qconvdir), 0, QTDIR);
12837da2899SCharles.Forsyth 			sprint(up->genbuf, "%d", s);
12937da2899SCharles.Forsyth 			devdir(c, q, up->genbuf, 0, cv->owner, DMDIR|0555, dp);
13037da2899SCharles.Forsyth 			return 1;
13137da2899SCharles.Forsyth 		}
13237da2899SCharles.Forsyth 		s -= cmd.nc;
13337da2899SCharles.Forsyth 		if(s == 0){
13437da2899SCharles.Forsyth 			mkqid(&q, QID(0, Qclonus), 0, QTFILE);
13537da2899SCharles.Forsyth 			devdir(c, q, "clone", 0, "cmd", 0666, dp);
13637da2899SCharles.Forsyth 			return 1;
13737da2899SCharles.Forsyth 		}
13837da2899SCharles.Forsyth 		return -1;
13937da2899SCharles.Forsyth 	case Qclonus:
14037da2899SCharles.Forsyth 		if(s == 0){
14137da2899SCharles.Forsyth 			mkqid(&q, QID(0, Qclonus), 0, QTFILE);
14237da2899SCharles.Forsyth 			devdir(c, q, "clone", 0, "cmd", 0666, dp);
14337da2899SCharles.Forsyth 			return 1;
14437da2899SCharles.Forsyth 		}
14537da2899SCharles.Forsyth 		return -1;
14637da2899SCharles.Forsyth 	case Qconvdir:
14737da2899SCharles.Forsyth 		return cmd3gen(c, Qconvbase+s, dp);
14837da2899SCharles.Forsyth 	case Qdata:
149*6e425a9dSCharles.Forsyth 	case Qstderr:
15037da2899SCharles.Forsyth 	case Qctl:
15137da2899SCharles.Forsyth 	case Qstatus:
15237da2899SCharles.Forsyth 	case Qwait:
15337da2899SCharles.Forsyth 		return cmd3gen(c, TYPE(c->qid), dp);
15437da2899SCharles.Forsyth 	}
15537da2899SCharles.Forsyth 	return -1;
15637da2899SCharles.Forsyth }
15737da2899SCharles.Forsyth 
15837da2899SCharles.Forsyth static void
cmdinit(void)15937da2899SCharles.Forsyth cmdinit(void)
16037da2899SCharles.Forsyth {
161*6e425a9dSCharles.Forsyth 	cmd.maxconv = 1000;
16237da2899SCharles.Forsyth 	cmd.conv = mallocz(sizeof(Conv*)*(cmd.maxconv+1), 1);
16337da2899SCharles.Forsyth 	/* cmd.conv is checked by cmdattach, below */
16437da2899SCharles.Forsyth }
16537da2899SCharles.Forsyth 
16637da2899SCharles.Forsyth static Chan *
cmdattach(char * spec)16737da2899SCharles.Forsyth cmdattach(char *spec)
16837da2899SCharles.Forsyth {
16937da2899SCharles.Forsyth 	Chan *c;
17037da2899SCharles.Forsyth 
17137da2899SCharles.Forsyth 	if(cmd.conv == nil)
17237da2899SCharles.Forsyth 		error(Enomem);
17337da2899SCharles.Forsyth 	c = devattach('C', spec);
17437da2899SCharles.Forsyth 	mkqid(&c->qid, QID(0, Qtopdir), 0, QTDIR);
17537da2899SCharles.Forsyth 	return c;
17637da2899SCharles.Forsyth }
17737da2899SCharles.Forsyth 
17837da2899SCharles.Forsyth static Walkqid*
cmdwalk(Chan * c,Chan * nc,char ** name,int nname)17937da2899SCharles.Forsyth cmdwalk(Chan *c, Chan *nc, char **name, int nname)
18037da2899SCharles.Forsyth {
18137da2899SCharles.Forsyth 	return devwalk(c, nc, name, nname, 0, 0, cmdgen);
18237da2899SCharles.Forsyth }
18337da2899SCharles.Forsyth 
18437da2899SCharles.Forsyth static int
cmdstat(Chan * c,uchar * db,int n)18537da2899SCharles.Forsyth cmdstat(Chan *c, uchar *db, int n)
18637da2899SCharles.Forsyth {
18737da2899SCharles.Forsyth 	return devstat(c, db, n, 0, 0, cmdgen);
18837da2899SCharles.Forsyth }
18937da2899SCharles.Forsyth 
19037da2899SCharles.Forsyth static Chan *
cmdopen(Chan * c,int omode)19137da2899SCharles.Forsyth cmdopen(Chan *c, int omode)
19237da2899SCharles.Forsyth {
19337da2899SCharles.Forsyth 	int perm;
19437da2899SCharles.Forsyth 	Conv *cv;
19537da2899SCharles.Forsyth 	char *user;
19637da2899SCharles.Forsyth 
19737da2899SCharles.Forsyth 	perm = 0;
19837da2899SCharles.Forsyth 	omode = openmode(omode);
19937da2899SCharles.Forsyth 	switch(omode) {
20037da2899SCharles.Forsyth 	case OREAD:
20137da2899SCharles.Forsyth 		perm = 4;
20237da2899SCharles.Forsyth 		break;
20337da2899SCharles.Forsyth 	case OWRITE:
20437da2899SCharles.Forsyth 		perm = 2;
20537da2899SCharles.Forsyth 		break;
20637da2899SCharles.Forsyth 	case ORDWR:
20737da2899SCharles.Forsyth 		perm = 6;
20837da2899SCharles.Forsyth 		break;
20937da2899SCharles.Forsyth 	}
21037da2899SCharles.Forsyth 
21137da2899SCharles.Forsyth 	switch(TYPE(c->qid)) {
21237da2899SCharles.Forsyth 	default:
21337da2899SCharles.Forsyth 		break;
21437da2899SCharles.Forsyth 	case Qtopdir:
21537da2899SCharles.Forsyth 	case Qcmd:
21637da2899SCharles.Forsyth 	case Qconvdir:
21737da2899SCharles.Forsyth 	case Qstatus:
21837da2899SCharles.Forsyth 		if(omode != OREAD)
21937da2899SCharles.Forsyth 			error(Eperm);
22037da2899SCharles.Forsyth 		break;
22137da2899SCharles.Forsyth 	case Qclonus:
22237da2899SCharles.Forsyth 		qlock(&cmd.l);
22337da2899SCharles.Forsyth 		if(waserror()){
22437da2899SCharles.Forsyth 			qunlock(&cmd.l);
22537da2899SCharles.Forsyth 			nexterror();
22637da2899SCharles.Forsyth 		}
22737da2899SCharles.Forsyth 		cv = cmdclone(up->env->user);
22837da2899SCharles.Forsyth 		poperror();
22937da2899SCharles.Forsyth 		qunlock(&cmd.l);
23037da2899SCharles.Forsyth 		if(cv == 0)
23137da2899SCharles.Forsyth 			error(Enodev);
23237da2899SCharles.Forsyth 		mkqid(&c->qid, QID(cv->x, Qctl), 0, QTFILE);
23337da2899SCharles.Forsyth 		break;
23437da2899SCharles.Forsyth 	case Qdata:
235*6e425a9dSCharles.Forsyth 	case Qstderr:
23637da2899SCharles.Forsyth 	case Qctl:
23737da2899SCharles.Forsyth 	case Qwait:
23837da2899SCharles.Forsyth 		qlock(&cmd.l);
23937da2899SCharles.Forsyth 		cv = cmd.conv[CONV(c->qid)];
24037da2899SCharles.Forsyth 		qlock(&cv->l);
24137da2899SCharles.Forsyth 		if(waserror()){
24237da2899SCharles.Forsyth 			qunlock(&cv->l);
24337da2899SCharles.Forsyth 			qunlock(&cmd.l);
24437da2899SCharles.Forsyth 			nexterror();
24537da2899SCharles.Forsyth 		}
24637da2899SCharles.Forsyth 		user = up->env->user;
24737da2899SCharles.Forsyth 		if((perm & (cv->perm>>6)) != perm) {
24837da2899SCharles.Forsyth 			if(strcmp(user, cv->owner) != 0 ||
24937da2899SCharles.Forsyth 		 	  (perm & cv->perm) != perm)
25037da2899SCharles.Forsyth 				error(Eperm);
25137da2899SCharles.Forsyth 		}
25237da2899SCharles.Forsyth 		switch(TYPE(c->qid)){
25337da2899SCharles.Forsyth 		case Qdata:
25437da2899SCharles.Forsyth 			if(omode == OWRITE || omode == ORDWR)
255*6e425a9dSCharles.Forsyth 				cv->count[0]++;
25637da2899SCharles.Forsyth 			if(omode == OREAD || omode == ORDWR)
257*6e425a9dSCharles.Forsyth 				cv->count[1]++;
258*6e425a9dSCharles.Forsyth 			break;
259*6e425a9dSCharles.Forsyth 		case Qstderr:
260*6e425a9dSCharles.Forsyth 			if(omode != OREAD)
261*6e425a9dSCharles.Forsyth 				error(Eperm);
262*6e425a9dSCharles.Forsyth 			cv->count[2]++;
26337da2899SCharles.Forsyth 			break;
26437da2899SCharles.Forsyth 		case Qwait:
26537da2899SCharles.Forsyth 			if(cv->waitq == nil)
26637da2899SCharles.Forsyth 				cv->waitq = qopen(1024, Qmsg, nil, 0);
26737da2899SCharles.Forsyth 			break;
26837da2899SCharles.Forsyth 		}
26937da2899SCharles.Forsyth 		cv->inuse++;
27037da2899SCharles.Forsyth 		if(cv->inuse == 1) {
27137da2899SCharles.Forsyth 			cv->state = "Open";
27237da2899SCharles.Forsyth 			kstrdup(&cv->owner, user);
27337da2899SCharles.Forsyth 			cv->perm = 0660;
27437da2899SCharles.Forsyth 			cv->nice = 0;
27537da2899SCharles.Forsyth 		}
27637da2899SCharles.Forsyth 		poperror();
27737da2899SCharles.Forsyth 		qunlock(&cv->l);
27837da2899SCharles.Forsyth 		qunlock(&cmd.l);
27937da2899SCharles.Forsyth 		break;
28037da2899SCharles.Forsyth 	}
281*6e425a9dSCharles.Forsyth 	c->mode = omode;
28237da2899SCharles.Forsyth 	c->flag |= COPEN;
28337da2899SCharles.Forsyth 	c->offset = 0;
28437da2899SCharles.Forsyth 	return c;
28537da2899SCharles.Forsyth }
28637da2899SCharles.Forsyth 
28737da2899SCharles.Forsyth static void
closeconv(Conv * c)28837da2899SCharles.Forsyth closeconv(Conv *c)
28937da2899SCharles.Forsyth {
29037da2899SCharles.Forsyth 	kstrdup(&c->owner, "cmd");
29137da2899SCharles.Forsyth 	kstrdup(&c->dir, rootdir);
29237da2899SCharles.Forsyth 	c->perm = 0666;
29337da2899SCharles.Forsyth 	c->state = "Closed";
29437da2899SCharles.Forsyth 	c->killonclose = 0;
29537da2899SCharles.Forsyth 	c->killed = 0;
29637da2899SCharles.Forsyth 	c->nice = 0;
29737da2899SCharles.Forsyth 	free(c->cmd);
29837da2899SCharles.Forsyth 	c->cmd = nil;
29937da2899SCharles.Forsyth 	if(c->waitq != nil){
30037da2899SCharles.Forsyth 		qfree(c->waitq);
30137da2899SCharles.Forsyth 		c->waitq = nil;
30237da2899SCharles.Forsyth 	}
30337da2899SCharles.Forsyth 	free(c->error);
30437da2899SCharles.Forsyth 	c->error = nil;
30537da2899SCharles.Forsyth }
30637da2899SCharles.Forsyth 
30737da2899SCharles.Forsyth static void
cmdfdclose(Conv * c,int fd)308*6e425a9dSCharles.Forsyth cmdfdclose(Conv *c, int fd)
309*6e425a9dSCharles.Forsyth {
310*6e425a9dSCharles.Forsyth 	if(--c->count[fd] == 0 && c->fd[fd] != -1){
311*6e425a9dSCharles.Forsyth 		close(c->fd[fd]);
312*6e425a9dSCharles.Forsyth 		c->fd[fd] = -1;
313*6e425a9dSCharles.Forsyth 	}
314*6e425a9dSCharles.Forsyth }
315*6e425a9dSCharles.Forsyth 
316*6e425a9dSCharles.Forsyth static void
cmdclose(Chan * c)31737da2899SCharles.Forsyth cmdclose(Chan *c)
31837da2899SCharles.Forsyth {
31937da2899SCharles.Forsyth 	Conv *cc;
32037da2899SCharles.Forsyth 	int r;
32137da2899SCharles.Forsyth 
32237da2899SCharles.Forsyth 	if((c->flag & COPEN) == 0)
32337da2899SCharles.Forsyth 		return;
32437da2899SCharles.Forsyth 
32537da2899SCharles.Forsyth 	switch(TYPE(c->qid)) {
32637da2899SCharles.Forsyth 	case Qctl:
32737da2899SCharles.Forsyth 	case Qdata:
328*6e425a9dSCharles.Forsyth 	case Qstderr:
32937da2899SCharles.Forsyth 	case Qwait:
33037da2899SCharles.Forsyth 		cc = cmd.conv[CONV(c->qid)];
33137da2899SCharles.Forsyth 		qlock(&cc->l);
33237da2899SCharles.Forsyth 		if(TYPE(c->qid) == Qdata){
333*6e425a9dSCharles.Forsyth 			if(c->mode == OWRITE || c->mode == ORDWR)
334*6e425a9dSCharles.Forsyth 				cmdfdclose(cc, 0);
335*6e425a9dSCharles.Forsyth 			if(c->mode == OREAD || c->mode == ORDWR)
336*6e425a9dSCharles.Forsyth 				cmdfdclose(cc, 1);
337*6e425a9dSCharles.Forsyth 		}else if(TYPE(c->qid) == Qstderr)
338*6e425a9dSCharles.Forsyth 			cmdfdclose(cc, 2);
33937da2899SCharles.Forsyth 
34037da2899SCharles.Forsyth 		r = --cc->inuse;
34137da2899SCharles.Forsyth 		if(cc->child != nil){
34237da2899SCharles.Forsyth 			if(!cc->killed)
34337da2899SCharles.Forsyth 			if(r == 0 || (cc->killonclose && TYPE(c->qid) == Qctl)){
34437da2899SCharles.Forsyth 				oscmdkill(cc->child);
34537da2899SCharles.Forsyth 				cc->killed = 1;
34637da2899SCharles.Forsyth 			}
34737da2899SCharles.Forsyth 		}else if(r == 0)
34837da2899SCharles.Forsyth 			closeconv(cc);
34937da2899SCharles.Forsyth 
35037da2899SCharles.Forsyth 		qunlock(&cc->l);
35137da2899SCharles.Forsyth 		break;
35237da2899SCharles.Forsyth 	}
35337da2899SCharles.Forsyth }
35437da2899SCharles.Forsyth 
35537da2899SCharles.Forsyth static long
cmdread(Chan * ch,void * a,long n,vlong offset)35637da2899SCharles.Forsyth cmdread(Chan *ch, void *a, long n, vlong offset)
35737da2899SCharles.Forsyth {
35837da2899SCharles.Forsyth 	Conv *c;
35937da2899SCharles.Forsyth 	char *p, *cmds;
360*6e425a9dSCharles.Forsyth 	int fd;
36137da2899SCharles.Forsyth 
36237da2899SCharles.Forsyth 	USED(offset);
36337da2899SCharles.Forsyth 
36437da2899SCharles.Forsyth 	p = a;
36537da2899SCharles.Forsyth 	switch(TYPE(ch->qid)) {
36637da2899SCharles.Forsyth 	default:
36737da2899SCharles.Forsyth 		error(Eperm);
36837da2899SCharles.Forsyth 	case Qcmd:
36937da2899SCharles.Forsyth 	case Qtopdir:
37037da2899SCharles.Forsyth 	case Qconvdir:
37137da2899SCharles.Forsyth 		return devdirread(ch, a, n, 0, 0, cmdgen);
37237da2899SCharles.Forsyth 	case Qctl:
37337da2899SCharles.Forsyth 		sprint(up->genbuf, "%ld", CONV(ch->qid));
37437da2899SCharles.Forsyth 		return readstr(offset, p, n, up->genbuf);
37537da2899SCharles.Forsyth 	case Qstatus:
37637da2899SCharles.Forsyth 		c = cmd.conv[CONV(ch->qid)];
37737da2899SCharles.Forsyth 		cmds = "";
37837da2899SCharles.Forsyth 		if(c->cmd != nil)
37937da2899SCharles.Forsyth 			cmds = c->cmd->f[1];
38037da2899SCharles.Forsyth 		snprint(up->genbuf, sizeof(up->genbuf), "cmd/%d %d %s %q %q\n",
38137da2899SCharles.Forsyth 			c->x, c->inuse, c->state, c->dir, cmds);
38237da2899SCharles.Forsyth 		return readstr(offset, p, n, up->genbuf);
38337da2899SCharles.Forsyth 	case Qdata:
384*6e425a9dSCharles.Forsyth 	case Qstderr:
385*6e425a9dSCharles.Forsyth 		fd = 1;
386*6e425a9dSCharles.Forsyth 		if(TYPE(ch->qid) == Qstderr)
387*6e425a9dSCharles.Forsyth 			fd = 2;
38837da2899SCharles.Forsyth 		c = cmd.conv[CONV(ch->qid)];
38937da2899SCharles.Forsyth 		qlock(&c->l);
390*6e425a9dSCharles.Forsyth 		if(c->fd[fd] == -1){
39137da2899SCharles.Forsyth 			qunlock(&c->l);
39237da2899SCharles.Forsyth 			return 0;
39337da2899SCharles.Forsyth 		}
39437da2899SCharles.Forsyth 		qunlock(&c->l);
39537da2899SCharles.Forsyth 		osenter();
396*6e425a9dSCharles.Forsyth 		n = read(c->fd[fd], a, n);
39737da2899SCharles.Forsyth 		osleave();
39837da2899SCharles.Forsyth 		if(n < 0)
39937da2899SCharles.Forsyth 			oserror();
40037da2899SCharles.Forsyth 		return n;
40137da2899SCharles.Forsyth 	case Qwait:
40237da2899SCharles.Forsyth 		c = cmd.conv[CONV(ch->qid)];
40337da2899SCharles.Forsyth 		return qread(c->waitq, a, n);
40437da2899SCharles.Forsyth 	}
40537da2899SCharles.Forsyth }
40637da2899SCharles.Forsyth 
40737da2899SCharles.Forsyth static int
cmdstarted(void * a)40837da2899SCharles.Forsyth cmdstarted(void *a)
40937da2899SCharles.Forsyth {
41037da2899SCharles.Forsyth 	Conv *c;
41137da2899SCharles.Forsyth 
41237da2899SCharles.Forsyth 	c = a;
413*6e425a9dSCharles.Forsyth 	return c->child != nil || c->error != nil || strcmp(c->state, "Execute") != 0;
41437da2899SCharles.Forsyth }
41537da2899SCharles.Forsyth 
41637da2899SCharles.Forsyth enum
41737da2899SCharles.Forsyth {
41837da2899SCharles.Forsyth 	CMdir,
41937da2899SCharles.Forsyth 	CMexec,
42037da2899SCharles.Forsyth 	CMkill,
42137da2899SCharles.Forsyth 	CMnice,
42237da2899SCharles.Forsyth 	CMkillonclose
42337da2899SCharles.Forsyth };
42437da2899SCharles.Forsyth 
42537da2899SCharles.Forsyth static
42637da2899SCharles.Forsyth Cmdtab cmdtab[] = {
42737da2899SCharles.Forsyth 	CMdir,	"dir",	2,
42837da2899SCharles.Forsyth 	CMexec,	"exec",	0,
42937da2899SCharles.Forsyth 	CMkill,	"kill",	1,
43037da2899SCharles.Forsyth 	CMnice,	"nice",	0,
43137da2899SCharles.Forsyth 	CMkillonclose, "killonclose", 0,
43237da2899SCharles.Forsyth };
43337da2899SCharles.Forsyth 
43437da2899SCharles.Forsyth static long
cmdwrite(Chan * ch,void * a,long n,vlong offset)43537da2899SCharles.Forsyth cmdwrite(Chan *ch, void *a, long n, vlong offset)
43637da2899SCharles.Forsyth {
437*6e425a9dSCharles.Forsyth 	int i, r;
43837da2899SCharles.Forsyth 	Conv *c;
43937da2899SCharles.Forsyth 	Cmdbuf *cb;
44037da2899SCharles.Forsyth 	Cmdtab *ct;
44137da2899SCharles.Forsyth 
44237da2899SCharles.Forsyth 	USED(offset);
44337da2899SCharles.Forsyth 
44437da2899SCharles.Forsyth 	switch(TYPE(ch->qid)) {
44537da2899SCharles.Forsyth 	default:
44637da2899SCharles.Forsyth 		error(Eperm);
44737da2899SCharles.Forsyth 	case Qctl:
44837da2899SCharles.Forsyth 		c = cmd.conv[CONV(ch->qid)];
44937da2899SCharles.Forsyth 		cb = parsecmd(a, n);
45037da2899SCharles.Forsyth 		if(waserror()){
45137da2899SCharles.Forsyth 			free(cb);
45237da2899SCharles.Forsyth 			nexterror();
45337da2899SCharles.Forsyth 		}
45437da2899SCharles.Forsyth 		ct = lookupcmd(cb, cmdtab, nelem(cmdtab));
45537da2899SCharles.Forsyth 		switch(ct->index){
45637da2899SCharles.Forsyth 		case CMdir:
45737da2899SCharles.Forsyth 			kstrdup(&c->dir, cb->f[1]);
45837da2899SCharles.Forsyth 			break;
45937da2899SCharles.Forsyth 		case CMexec:
46037da2899SCharles.Forsyth 			poperror();	/* cb */
46137da2899SCharles.Forsyth 			qlock(&c->l);
46237da2899SCharles.Forsyth 			if(waserror()){
46337da2899SCharles.Forsyth 				qunlock(&c->l);
46437da2899SCharles.Forsyth 				free(cb);
46537da2899SCharles.Forsyth 				nexterror();
46637da2899SCharles.Forsyth 			}
467*6e425a9dSCharles.Forsyth 			if(c->child != nil || c->cmd != nil)
468*6e425a9dSCharles.Forsyth 				error(Einuse);
469*6e425a9dSCharles.Forsyth 			for(i = 0; i < nelem(c->fd); i++)
470*6e425a9dSCharles.Forsyth 				if(c->fd[i] != -1)
47137da2899SCharles.Forsyth 					error(Einuse);
47237da2899SCharles.Forsyth 			if(cb->nf < 1)
47337da2899SCharles.Forsyth 				error(Etoosmall);
47437da2899SCharles.Forsyth 			kproc("cmdproc", cmdproc, c, 0);	/* cmdproc held back until unlock below */
47537da2899SCharles.Forsyth 			free(c->cmd);
47637da2899SCharles.Forsyth 			c->cmd = cb;	/* don't free cb */
47737da2899SCharles.Forsyth 			c->state = "Execute";
47837da2899SCharles.Forsyth 			poperror();
47937da2899SCharles.Forsyth 			qunlock(&c->l);
48037da2899SCharles.Forsyth 			while(waserror())
48137da2899SCharles.Forsyth 				;
48237da2899SCharles.Forsyth 			Sleep(&c->startr, cmdstarted, c);
48337da2899SCharles.Forsyth 			poperror();
48437da2899SCharles.Forsyth 			if(c->error)
48537da2899SCharles.Forsyth 				error(c->error);
48637da2899SCharles.Forsyth 			return n;	/* avoid free(cb) below */
48737da2899SCharles.Forsyth 		case CMkill:
48837da2899SCharles.Forsyth 			qlock(&c->l);
48937da2899SCharles.Forsyth 			if(waserror()){
49037da2899SCharles.Forsyth 				qunlock(&c->l);
49137da2899SCharles.Forsyth 				nexterror();
49237da2899SCharles.Forsyth 			}
49337da2899SCharles.Forsyth 			if(c->child == nil)
49437da2899SCharles.Forsyth 				error("not started");
49537da2899SCharles.Forsyth 			if(oscmdkill(c->child) < 0)
49637da2899SCharles.Forsyth 				oserror();
49737da2899SCharles.Forsyth 			poperror();
49837da2899SCharles.Forsyth 			qunlock(&c->l);
49937da2899SCharles.Forsyth 			break;
50037da2899SCharles.Forsyth 		case CMnice:
50137da2899SCharles.Forsyth 			c->nice = cb->nf > 1? atoi(cb->f[1]): 1;
50237da2899SCharles.Forsyth 			break;
50337da2899SCharles.Forsyth 		case CMkillonclose:
50437da2899SCharles.Forsyth 			c->killonclose = 1;
50537da2899SCharles.Forsyth 			break;
50637da2899SCharles.Forsyth 		}
50737da2899SCharles.Forsyth 		poperror();
50837da2899SCharles.Forsyth 		free(cb);
50937da2899SCharles.Forsyth 		break;
51037da2899SCharles.Forsyth 	case Qdata:
51137da2899SCharles.Forsyth 		c = cmd.conv[CONV(ch->qid)];
51237da2899SCharles.Forsyth 		qlock(&c->l);
513*6e425a9dSCharles.Forsyth 		if(c->fd[0] == -1){
51437da2899SCharles.Forsyth 			qunlock(&c->l);
51537da2899SCharles.Forsyth 			error(Ehungup);
51637da2899SCharles.Forsyth 		}
51737da2899SCharles.Forsyth 		qunlock(&c->l);
51837da2899SCharles.Forsyth 		osenter();
519*6e425a9dSCharles.Forsyth 		r = write(c->fd[0], a, n);
52037da2899SCharles.Forsyth 		osleave();
52137da2899SCharles.Forsyth 		if(r == 0)
52237da2899SCharles.Forsyth 			error(Ehungup);
52337da2899SCharles.Forsyth 		if(r < 0) {
52437da2899SCharles.Forsyth 			/* XXX perhaps should kill writer "write on closed pipe" here, 2nd time around? */
52537da2899SCharles.Forsyth 			oserror();
52637da2899SCharles.Forsyth 		}
52737da2899SCharles.Forsyth 		return r;
52837da2899SCharles.Forsyth 	}
52937da2899SCharles.Forsyth 	return n;
53037da2899SCharles.Forsyth }
53137da2899SCharles.Forsyth 
53237da2899SCharles.Forsyth static int
cmdwstat(Chan * c,uchar * dp,int n)53337da2899SCharles.Forsyth cmdwstat(Chan *c, uchar *dp, int n)
53437da2899SCharles.Forsyth {
53537da2899SCharles.Forsyth 	Dir *d;
53637da2899SCharles.Forsyth 	Conv *cv;
53737da2899SCharles.Forsyth 
53837da2899SCharles.Forsyth 	switch(TYPE(c->qid)){
53937da2899SCharles.Forsyth 	default:
54037da2899SCharles.Forsyth 		error(Eperm);
54137da2899SCharles.Forsyth 	case Qctl:
54237da2899SCharles.Forsyth 	case Qdata:
543*6e425a9dSCharles.Forsyth 	case Qstderr:
54437da2899SCharles.Forsyth 		d = malloc(sizeof(*d)+n);
54537da2899SCharles.Forsyth 		if(d == nil)
54637da2899SCharles.Forsyth 			error(Enomem);
54737da2899SCharles.Forsyth 		if(waserror()){
54837da2899SCharles.Forsyth 			free(d);
54937da2899SCharles.Forsyth 			nexterror();
55037da2899SCharles.Forsyth 		}
55137da2899SCharles.Forsyth 		n = convM2D(dp, n, d, (char*)&d[1]);
55237da2899SCharles.Forsyth 		if(n == 0)
55337da2899SCharles.Forsyth 			error(Eshortstat);
55437da2899SCharles.Forsyth 		cv = cmd.conv[CONV(c->qid)];
55537da2899SCharles.Forsyth 		if(!iseve() && strcmp(up->env->user, cv->owner) != 0)
55637da2899SCharles.Forsyth 			error(Eperm);
55737da2899SCharles.Forsyth 		if(!emptystr(d->uid))
55837da2899SCharles.Forsyth 			kstrdup(&cv->owner, d->uid);
55937da2899SCharles.Forsyth 		if(d->mode != ~0UL)
56037da2899SCharles.Forsyth 			cv->perm = d->mode & 0777;
56137da2899SCharles.Forsyth 		poperror();
56237da2899SCharles.Forsyth 		free(d);
56337da2899SCharles.Forsyth 		break;
56437da2899SCharles.Forsyth 	}
56537da2899SCharles.Forsyth 	return n;
56637da2899SCharles.Forsyth }
56737da2899SCharles.Forsyth 
56837da2899SCharles.Forsyth static Conv*
cmdclone(char * user)56937da2899SCharles.Forsyth cmdclone(char *user)
57037da2899SCharles.Forsyth {
57137da2899SCharles.Forsyth 	Conv *c, **pp, **ep;
572*6e425a9dSCharles.Forsyth 	int i;
57337da2899SCharles.Forsyth 
57437da2899SCharles.Forsyth 	c = nil;
57537da2899SCharles.Forsyth 	ep = &cmd.conv[cmd.maxconv];
57637da2899SCharles.Forsyth 	for(pp = cmd.conv; pp < ep; pp++) {
57737da2899SCharles.Forsyth 		c = *pp;
57837da2899SCharles.Forsyth 		if(c == nil) {
57937da2899SCharles.Forsyth 			c = malloc(sizeof(Conv));
58037da2899SCharles.Forsyth 			if(c == nil)
58137da2899SCharles.Forsyth 				error(Enomem);
58237da2899SCharles.Forsyth 			qlock(&c->l);
58337da2899SCharles.Forsyth 			c->inuse = 1;
58437da2899SCharles.Forsyth 			c->x = pp - cmd.conv;
58537da2899SCharles.Forsyth 			cmd.nc++;
58637da2899SCharles.Forsyth 			*pp = c;
58737da2899SCharles.Forsyth 			break;
58837da2899SCharles.Forsyth 		}
58937da2899SCharles.Forsyth 		if(canqlock(&c->l)){
59037da2899SCharles.Forsyth 			if(c->inuse == 0 && c->child == nil)
59137da2899SCharles.Forsyth 				break;
59237da2899SCharles.Forsyth 			qunlock(&c->l);
59337da2899SCharles.Forsyth 		}
59437da2899SCharles.Forsyth 	}
59537da2899SCharles.Forsyth 	if(pp >= ep)
59637da2899SCharles.Forsyth 		return nil;
59737da2899SCharles.Forsyth 
59837da2899SCharles.Forsyth 	c->inuse = 1;
59937da2899SCharles.Forsyth 	kstrdup(&c->owner, user);
60037da2899SCharles.Forsyth 	kstrdup(&c->dir, rootdir);
60137da2899SCharles.Forsyth 	c->perm = 0660;
60237da2899SCharles.Forsyth 	c->state = "Closed";
603*6e425a9dSCharles.Forsyth 	for(i=0; i<nelem(c->fd); i++)
604*6e425a9dSCharles.Forsyth 		c->fd[i] = -1;
60537da2899SCharles.Forsyth 
60637da2899SCharles.Forsyth 	qunlock(&c->l);
60737da2899SCharles.Forsyth 	return c;
60837da2899SCharles.Forsyth }
60937da2899SCharles.Forsyth 
61037da2899SCharles.Forsyth static void
cmdproc(void * a)61137da2899SCharles.Forsyth cmdproc(void *a)
61237da2899SCharles.Forsyth {
61337da2899SCharles.Forsyth 	Conv *c;
61437da2899SCharles.Forsyth 	int n;
61537da2899SCharles.Forsyth 	char status[ERRMAX];
61637da2899SCharles.Forsyth 	void *t;
61737da2899SCharles.Forsyth 
61837da2899SCharles.Forsyth 	c = a;
61937da2899SCharles.Forsyth 	qlock(&c->l);
62037da2899SCharles.Forsyth 	if(Debug)
62137da2899SCharles.Forsyth 		print("f[0]=%q f[1]=%q\n", c->cmd->f[0], c->cmd->f[1]);
62237da2899SCharles.Forsyth 	if(waserror()){
62337da2899SCharles.Forsyth 		if(Debug)
62437da2899SCharles.Forsyth 			print("failed: %q\n", up->env->errstr);
62537da2899SCharles.Forsyth 		kstrdup(&c->error, up->env->errstr);
62637da2899SCharles.Forsyth 		c->state = "Done";
62737da2899SCharles.Forsyth 		qunlock(&c->l);
62837da2899SCharles.Forsyth 		Wakeup(&c->startr);
62937da2899SCharles.Forsyth 		pexit("cmdproc", 0);
63037da2899SCharles.Forsyth 	}
631*6e425a9dSCharles.Forsyth 	t = oscmd(c->cmd->f+1, c->nice, c->dir, c->fd);
63237da2899SCharles.Forsyth 	if(t == nil)
63337da2899SCharles.Forsyth 		oserror();
63437da2899SCharles.Forsyth 	c->child = t;	/* to allow oscmdkill */
63537da2899SCharles.Forsyth 	poperror();
63637da2899SCharles.Forsyth 	qunlock(&c->l);
63737da2899SCharles.Forsyth 	Wakeup(&c->startr);
63837da2899SCharles.Forsyth 	if(Debug)
63937da2899SCharles.Forsyth 		print("started\n");
64037da2899SCharles.Forsyth 	while(waserror())
64137da2899SCharles.Forsyth 		oscmdkill(t);
64237da2899SCharles.Forsyth 	osenter();
64337da2899SCharles.Forsyth 	n = oscmdwait(t, status, sizeof(status));
64437da2899SCharles.Forsyth 	osleave();
64537da2899SCharles.Forsyth 	if(n < 0){
64637da2899SCharles.Forsyth 		oserrstr(up->genbuf, sizeof(up->genbuf));
64737da2899SCharles.Forsyth 		n = snprint(status, sizeof(status), "0 0 0 0 %q", up->genbuf);
64837da2899SCharles.Forsyth 	}
64937da2899SCharles.Forsyth 	qlock(&c->l);
65037da2899SCharles.Forsyth 	c->child = nil;
65137da2899SCharles.Forsyth 	oscmdfree(t);
65237da2899SCharles.Forsyth 	if(Debug){
65337da2899SCharles.Forsyth 		status[n]=0;
654*6e425a9dSCharles.Forsyth 		print("done %d %d %d: %q\n", c->fd[0], c->fd[1], c->fd[2], status);
65537da2899SCharles.Forsyth 	}
65637da2899SCharles.Forsyth 	if(c->inuse > 0){
65737da2899SCharles.Forsyth 		c->state = "Done";
65837da2899SCharles.Forsyth 		if(c->waitq != nil)
65937da2899SCharles.Forsyth 			qproduce(c->waitq, status, n);
66037da2899SCharles.Forsyth 	}else
66137da2899SCharles.Forsyth 		closeconv(c);
66237da2899SCharles.Forsyth 	qunlock(&c->l);
66337da2899SCharles.Forsyth 	pexit("", 0);
66437da2899SCharles.Forsyth }
66537da2899SCharles.Forsyth 
66637da2899SCharles.Forsyth Dev cmddevtab = {
66737da2899SCharles.Forsyth 	'C',
66837da2899SCharles.Forsyth 	"cmd",
66937da2899SCharles.Forsyth 
67037da2899SCharles.Forsyth 	cmdinit,
67137da2899SCharles.Forsyth 	cmdattach,
67237da2899SCharles.Forsyth 	cmdwalk,
67337da2899SCharles.Forsyth 	cmdstat,
67437da2899SCharles.Forsyth 	cmdopen,
67537da2899SCharles.Forsyth 	devcreate,
67637da2899SCharles.Forsyth 	cmdclose,
67737da2899SCharles.Forsyth 	cmdread,
67837da2899SCharles.Forsyth 	devbread,
67937da2899SCharles.Forsyth 	cmdwrite,
68037da2899SCharles.Forsyth 	devbwrite,
68137da2899SCharles.Forsyth 	devremove,
68237da2899SCharles.Forsyth 	cmdwstat
68337da2899SCharles.Forsyth };
684