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