xref: /plan9-contrib/sys/src/9k/port/devpipe.c (revision 406c76facc4b13aa2a55454bf4091aab9f03da22)
19ef1f84bSDavid du Colombier #include	"u.h"
29ef1f84bSDavid du Colombier #include	"../port/lib.h"
39ef1f84bSDavid du Colombier #include	"mem.h"
49ef1f84bSDavid du Colombier #include	"dat.h"
59ef1f84bSDavid du Colombier #include	"fns.h"
69ef1f84bSDavid du Colombier #include	"../port/error.h"
79ef1f84bSDavid du Colombier 
89ef1f84bSDavid du Colombier typedef struct Pipe	Pipe;
99ef1f84bSDavid du Colombier struct Pipe
109ef1f84bSDavid du Colombier {
119ef1f84bSDavid du Colombier 	QLock;
129ef1f84bSDavid du Colombier 	Pipe	*next;
139ef1f84bSDavid du Colombier 	int	ref;
149ef1f84bSDavid du Colombier 	ulong	path;
15*406c76faSDavid du Colombier 	long	perm;
169ef1f84bSDavid du Colombier 	Queue	*q[2];
179ef1f84bSDavid du Colombier 	int	qref[2];
189ef1f84bSDavid du Colombier };
199ef1f84bSDavid du Colombier 
209ef1f84bSDavid du Colombier struct
219ef1f84bSDavid du Colombier {
229ef1f84bSDavid du Colombier 	Lock;
239ef1f84bSDavid du Colombier 	ulong	path;
249ef1f84bSDavid du Colombier } pipealloc;
259ef1f84bSDavid du Colombier 
269ef1f84bSDavid du Colombier enum
279ef1f84bSDavid du Colombier {
289ef1f84bSDavid du Colombier 	Qdir,
299ef1f84bSDavid du Colombier 	Qdata0,
309ef1f84bSDavid du Colombier 	Qdata1,
319ef1f84bSDavid du Colombier 
329ef1f84bSDavid du Colombier 	PIPEQSIZE = 256*KiB,
339ef1f84bSDavid du Colombier };
349ef1f84bSDavid du Colombier 
359ef1f84bSDavid du Colombier Dirtab pipedir[] =
369ef1f84bSDavid du Colombier {
379ef1f84bSDavid du Colombier 	".",		{Qdir,0,QTDIR},	0,		DMDIR|0500,
389ef1f84bSDavid du Colombier 	"data",		{Qdata0},	0,		0600,
399ef1f84bSDavid du Colombier 	"data1",	{Qdata1},	0,		0600,
409ef1f84bSDavid du Colombier };
419ef1f84bSDavid du Colombier #define NPIPEDIR 3
429ef1f84bSDavid du Colombier 
439ef1f84bSDavid du Colombier #define PIPETYPE(x)	(((unsigned)x)&0x1f)
449ef1f84bSDavid du Colombier #define PIPEID(x)	((((unsigned)x))>>5)
459ef1f84bSDavid du Colombier #define PIPEQID(i, t)	((((unsigned)i)<<5)|(t))
469ef1f84bSDavid du Colombier 
479ef1f84bSDavid du Colombier /*
489ef1f84bSDavid du Colombier  *  create a pipe, no streams are created until an open
499ef1f84bSDavid du Colombier  */
509ef1f84bSDavid du Colombier static Chan*
pipeattach(char * spec)519ef1f84bSDavid du Colombier pipeattach(char *spec)
529ef1f84bSDavid du Colombier {
539ef1f84bSDavid du Colombier 	Pipe *p;
549ef1f84bSDavid du Colombier 	Chan *c;
559ef1f84bSDavid du Colombier 
569ef1f84bSDavid du Colombier 	c = devattach('|', spec);
579ef1f84bSDavid du Colombier 	p = malloc(sizeof(Pipe));
589ef1f84bSDavid du Colombier 	if(p == 0)
599ef1f84bSDavid du Colombier 		exhausted("memory");
609ef1f84bSDavid du Colombier 	p->ref = 1;
619ef1f84bSDavid du Colombier 
629ef1f84bSDavid du Colombier 	p->q[0] = qopen(PIPEQSIZE, 0, 0, 0);
639ef1f84bSDavid du Colombier 	if(p->q[0] == 0){
649ef1f84bSDavid du Colombier 		free(p);
659ef1f84bSDavid du Colombier 		exhausted("memory");
669ef1f84bSDavid du Colombier 	}
679ef1f84bSDavid du Colombier 	p->q[1] = qopen(PIPEQSIZE, 0, 0, 0);
689ef1f84bSDavid du Colombier 	if(p->q[1] == 0){
699ef1f84bSDavid du Colombier 		free(p->q[0]);
709ef1f84bSDavid du Colombier 		free(p);
719ef1f84bSDavid du Colombier 		exhausted("memory");
729ef1f84bSDavid du Colombier 	}
739ef1f84bSDavid du Colombier 
749ef1f84bSDavid du Colombier 	lock(&pipealloc);
759ef1f84bSDavid du Colombier 	p->path = ++pipealloc.path;
769ef1f84bSDavid du Colombier 	unlock(&pipealloc);
77*406c76faSDavid du Colombier 	p->perm = pipedir[Qdata0].perm;
789ef1f84bSDavid du Colombier 
799ef1f84bSDavid du Colombier 	mkqid(&c->qid, PIPEQID(2*p->path, Qdir), 0, QTDIR);
809ef1f84bSDavid du Colombier 	c->aux = p;
819ef1f84bSDavid du Colombier 	c->devno = 0;
829ef1f84bSDavid du Colombier 	return c;
839ef1f84bSDavid du Colombier }
849ef1f84bSDavid du Colombier 
859ef1f84bSDavid du Colombier static int
pipegen(Chan * c,char *,Dirtab * tab,int ntab,int i,Dir * dp)869ef1f84bSDavid du Colombier pipegen(Chan *c, char*, Dirtab *tab, int ntab, int i, Dir *dp)
879ef1f84bSDavid du Colombier {
889ef1f84bSDavid du Colombier 	Qid q;
899ef1f84bSDavid du Colombier 	int len;
909ef1f84bSDavid du Colombier 	Pipe *p;
919ef1f84bSDavid du Colombier 
929ef1f84bSDavid du Colombier 	if(i == DEVDOTDOT){
939ef1f84bSDavid du Colombier 		devdir(c, c->qid, "#|", 0, eve, DMDIR|0555, dp);
949ef1f84bSDavid du Colombier 		return 1;
959ef1f84bSDavid du Colombier 	}
969ef1f84bSDavid du Colombier 	i++;	/* skip . */
979ef1f84bSDavid du Colombier 	if(tab==0 || i>=ntab)
989ef1f84bSDavid du Colombier 		return -1;
999ef1f84bSDavid du Colombier 
1009ef1f84bSDavid du Colombier 	tab += i;
1019ef1f84bSDavid du Colombier 	p = c->aux;
1029ef1f84bSDavid du Colombier 	switch((ulong)tab->qid.path){
1039ef1f84bSDavid du Colombier 	case Qdata0:
1049ef1f84bSDavid du Colombier 		len = qlen(p->q[0]);
1059ef1f84bSDavid du Colombier 		break;
1069ef1f84bSDavid du Colombier 	case Qdata1:
1079ef1f84bSDavid du Colombier 		len = qlen(p->q[1]);
1089ef1f84bSDavid du Colombier 		break;
1099ef1f84bSDavid du Colombier 	default:
1109ef1f84bSDavid du Colombier 		len = tab->length;
1119ef1f84bSDavid du Colombier 		break;
1129ef1f84bSDavid du Colombier 	}
1139ef1f84bSDavid du Colombier 	mkqid(&q, PIPEQID(PIPEID(c->qid.path), tab->qid.path), 0, QTFILE);
114*406c76faSDavid du Colombier 	devdir(c, q, tab->name, len, eve, p->perm, dp);
1159ef1f84bSDavid du Colombier 	return 1;
1169ef1f84bSDavid du Colombier }
1179ef1f84bSDavid du Colombier 
1189ef1f84bSDavid du Colombier 
1199ef1f84bSDavid du Colombier static Walkqid*
pipewalk(Chan * c,Chan * nc,char ** name,int nname)1209ef1f84bSDavid du Colombier pipewalk(Chan *c, Chan *nc, char **name, int nname)
1219ef1f84bSDavid du Colombier {
1229ef1f84bSDavid du Colombier 	Walkqid *wq;
1239ef1f84bSDavid du Colombier 	Pipe *p;
1249ef1f84bSDavid du Colombier 
1259ef1f84bSDavid du Colombier 	wq = devwalk(c, nc, name, nname, pipedir, NPIPEDIR, pipegen);
1269ef1f84bSDavid du Colombier 	if(wq != nil && wq->clone != nil && wq->clone != c){
1279ef1f84bSDavid du Colombier 		p = c->aux;
1289ef1f84bSDavid du Colombier 		qlock(p);
1299ef1f84bSDavid du Colombier 		p->ref++;
1309ef1f84bSDavid du Colombier 		if(c->flag & COPEN){
1319ef1f84bSDavid du Colombier 			print("channel open in pipewalk\n");
1329ef1f84bSDavid du Colombier 			switch(PIPETYPE(c->qid.path)){
1339ef1f84bSDavid du Colombier 			case Qdata0:
1349ef1f84bSDavid du Colombier 				p->qref[0]++;
1359ef1f84bSDavid du Colombier 				break;
1369ef1f84bSDavid du Colombier 			case Qdata1:
1379ef1f84bSDavid du Colombier 				p->qref[1]++;
1389ef1f84bSDavid du Colombier 				break;
1399ef1f84bSDavid du Colombier 			}
1409ef1f84bSDavid du Colombier 		}
1419ef1f84bSDavid du Colombier 		qunlock(p);
1429ef1f84bSDavid du Colombier 	}
1439ef1f84bSDavid du Colombier 	return wq;
1449ef1f84bSDavid du Colombier }
1459ef1f84bSDavid du Colombier 
1469ef1f84bSDavid du Colombier static long
pipestat(Chan * c,uchar * db,long n)1479ef1f84bSDavid du Colombier pipestat(Chan *c, uchar *db, long n)
1489ef1f84bSDavid du Colombier {
1499ef1f84bSDavid du Colombier 	Pipe *p;
1509ef1f84bSDavid du Colombier 	Dir dir;
1519ef1f84bSDavid du Colombier 
1529ef1f84bSDavid du Colombier 	p = c->aux;
1539ef1f84bSDavid du Colombier 
1549ef1f84bSDavid du Colombier 	switch(PIPETYPE(c->qid.path)){
1559ef1f84bSDavid du Colombier 	case Qdir:
1569ef1f84bSDavid du Colombier 		devdir(c, c->qid, ".", 0, eve, DMDIR|0555, &dir);
1579ef1f84bSDavid du Colombier 		break;
1589ef1f84bSDavid du Colombier 	case Qdata0:
159*406c76faSDavid du Colombier 		devdir(c, c->qid, "data", qlen(p->q[0]), eve, p->perm, &dir);
1609ef1f84bSDavid du Colombier 		break;
1619ef1f84bSDavid du Colombier 	case Qdata1:
162*406c76faSDavid du Colombier 		devdir(c, c->qid, "data1", qlen(p->q[1]), eve, p->perm, &dir);
1639ef1f84bSDavid du Colombier 		break;
1649ef1f84bSDavid du Colombier 	default:
1659ef1f84bSDavid du Colombier 		panic("pipestat");
1669ef1f84bSDavid du Colombier 	}
1679ef1f84bSDavid du Colombier 	n = convD2M(&dir, db, n);
1689ef1f84bSDavid du Colombier 	if(n < BIT16SZ)
1699ef1f84bSDavid du Colombier 		error(Eshortstat);
1709ef1f84bSDavid du Colombier 	return n;
1719ef1f84bSDavid du Colombier }
1729ef1f84bSDavid du Colombier 
173*406c76faSDavid du Colombier static long
pipewstat(Chan * c,uchar * db,long n)174*406c76faSDavid du Colombier pipewstat(Chan* c, uchar* db, long n)
175*406c76faSDavid du Colombier {
176*406c76faSDavid du Colombier 	int m;
177*406c76faSDavid du Colombier 	Dir *dir;
178*406c76faSDavid du Colombier 	Pipe *p;
179*406c76faSDavid du Colombier 
180*406c76faSDavid du Colombier 	p = c->aux;
181*406c76faSDavid du Colombier 	if(strcmp(up->user, eve) != 0)
182*406c76faSDavid du Colombier 		error(Eperm);
183*406c76faSDavid du Colombier 	if(PIPETYPE(c->qid.path) == Qdir)
184*406c76faSDavid du Colombier 		error(Eisdir);
185*406c76faSDavid du Colombier 
186*406c76faSDavid du Colombier 	dir = smalloc(sizeof(Dir)+n);
187*406c76faSDavid du Colombier 	if(waserror()){
188*406c76faSDavid du Colombier 		free(dir);
189*406c76faSDavid du Colombier 		nexterror();
190*406c76faSDavid du Colombier 	}
191*406c76faSDavid du Colombier 	m = convM2D(db, n, &dir[0], (char*)&dir[1]);
192*406c76faSDavid du Colombier 	if(m == 0)
193*406c76faSDavid du Colombier 		error(Eshortstat);
194*406c76faSDavid du Colombier 	if(!emptystr(dir[0].uid))
195*406c76faSDavid du Colombier 		error("can't change owner");
196*406c76faSDavid du Colombier 	if(dir[0].mode != ~0UL)
197*406c76faSDavid du Colombier 		p->perm = dir[0].mode;
198*406c76faSDavid du Colombier 	poperror();
199*406c76faSDavid du Colombier 	free(dir);
200*406c76faSDavid du Colombier 	return m;
201*406c76faSDavid du Colombier }
202*406c76faSDavid du Colombier 
2039ef1f84bSDavid du Colombier /*
2049ef1f84bSDavid du Colombier  *  if the stream doesn't exist, create it
2059ef1f84bSDavid du Colombier  */
2069ef1f84bSDavid du Colombier static Chan*
pipeopen(Chan * c,int omode)2079ef1f84bSDavid du Colombier pipeopen(Chan *c, int omode)
2089ef1f84bSDavid du Colombier {
2099ef1f84bSDavid du Colombier 	Pipe *p;
2109ef1f84bSDavid du Colombier 
2119ef1f84bSDavid du Colombier 	if(c->qid.type & QTDIR){
2129ef1f84bSDavid du Colombier 		if(omode != OREAD)
2139ef1f84bSDavid du Colombier 			error(Ebadarg);
2149ef1f84bSDavid du Colombier 		c->mode = omode;
2159ef1f84bSDavid du Colombier 		c->flag |= COPEN;
2169ef1f84bSDavid du Colombier 		c->offset = 0;
2179ef1f84bSDavid du Colombier 		return c;
2189ef1f84bSDavid du Colombier 	}
2199ef1f84bSDavid du Colombier 
2209ef1f84bSDavid du Colombier 	p = c->aux;
2219ef1f84bSDavid du Colombier 	qlock(p);
2229ef1f84bSDavid du Colombier 	switch(PIPETYPE(c->qid.path)){
2239ef1f84bSDavid du Colombier 	case Qdata0:
2249ef1f84bSDavid du Colombier 		p->qref[0]++;
2259ef1f84bSDavid du Colombier 		break;
2269ef1f84bSDavid du Colombier 	case Qdata1:
2279ef1f84bSDavid du Colombier 		p->qref[1]++;
2289ef1f84bSDavid du Colombier 		break;
2299ef1f84bSDavid du Colombier 	}
2309ef1f84bSDavid du Colombier 	qunlock(p);
2319ef1f84bSDavid du Colombier 
2329ef1f84bSDavid du Colombier 	c->mode = openmode(omode);
2339ef1f84bSDavid du Colombier 	c->flag |= COPEN;
2349ef1f84bSDavid du Colombier 	c->offset = 0;
2359ef1f84bSDavid du Colombier 	c->iounit = qiomaxatomic;
2369ef1f84bSDavid du Colombier 	return c;
2379ef1f84bSDavid du Colombier }
2389ef1f84bSDavid du Colombier 
2399ef1f84bSDavid du Colombier static void
pipeclose(Chan * c)2409ef1f84bSDavid du Colombier pipeclose(Chan *c)
2419ef1f84bSDavid du Colombier {
2429ef1f84bSDavid du Colombier 	Pipe *p;
2439ef1f84bSDavid du Colombier 
2449ef1f84bSDavid du Colombier 	p = c->aux;
2459ef1f84bSDavid du Colombier 	qlock(p);
2469ef1f84bSDavid du Colombier 
2479ef1f84bSDavid du Colombier 	if(c->flag & COPEN){
2489ef1f84bSDavid du Colombier 		/*
2499ef1f84bSDavid du Colombier 		 *  closing either side hangs up the stream
2509ef1f84bSDavid du Colombier 		 */
2519ef1f84bSDavid du Colombier 		switch(PIPETYPE(c->qid.path)){
2529ef1f84bSDavid du Colombier 		case Qdata0:
2539ef1f84bSDavid du Colombier 			p->qref[0]--;
2549ef1f84bSDavid du Colombier 			if(p->qref[0] == 0){
2559ef1f84bSDavid du Colombier 				qhangup(p->q[1], 0);
2569ef1f84bSDavid du Colombier 				qclose(p->q[0]);
2579ef1f84bSDavid du Colombier 			}
2589ef1f84bSDavid du Colombier 			break;
2599ef1f84bSDavid du Colombier 		case Qdata1:
2609ef1f84bSDavid du Colombier 			p->qref[1]--;
2619ef1f84bSDavid du Colombier 			if(p->qref[1] == 0){
2629ef1f84bSDavid du Colombier 				qhangup(p->q[0], 0);
2639ef1f84bSDavid du Colombier 				qclose(p->q[1]);
2649ef1f84bSDavid du Colombier 			}
2659ef1f84bSDavid du Colombier 			break;
2669ef1f84bSDavid du Colombier 		}
2679ef1f84bSDavid du Colombier 	}
2689ef1f84bSDavid du Colombier 
2699ef1f84bSDavid du Colombier 
2709ef1f84bSDavid du Colombier 	/*
2719ef1f84bSDavid du Colombier 	 *  if both sides are closed, they are reusable
2729ef1f84bSDavid du Colombier 	 */
2739ef1f84bSDavid du Colombier 	if(p->qref[0] == 0 && p->qref[1] == 0){
2749ef1f84bSDavid du Colombier 		qreopen(p->q[0]);
2759ef1f84bSDavid du Colombier 		qreopen(p->q[1]);
2769ef1f84bSDavid du Colombier 	}
2779ef1f84bSDavid du Colombier 
2789ef1f84bSDavid du Colombier 	/*
2799ef1f84bSDavid du Colombier 	 *  free the structure on last close
2809ef1f84bSDavid du Colombier 	 */
2819ef1f84bSDavid du Colombier 	p->ref--;
2829ef1f84bSDavid du Colombier 	if(p->ref == 0){
2839ef1f84bSDavid du Colombier 		qunlock(p);
2849ef1f84bSDavid du Colombier 		free(p->q[0]);
2859ef1f84bSDavid du Colombier 		free(p->q[1]);
2869ef1f84bSDavid du Colombier 		free(p);
2879ef1f84bSDavid du Colombier 	} else
2889ef1f84bSDavid du Colombier 		qunlock(p);
2899ef1f84bSDavid du Colombier }
2909ef1f84bSDavid du Colombier 
2919ef1f84bSDavid du Colombier static long
piperead(Chan * c,void * va,long n,vlong)2929ef1f84bSDavid du Colombier piperead(Chan *c, void *va, long n, vlong)
2939ef1f84bSDavid du Colombier {
2949ef1f84bSDavid du Colombier 	Pipe *p;
2959ef1f84bSDavid du Colombier 
2969ef1f84bSDavid du Colombier 	p = c->aux;
2979ef1f84bSDavid du Colombier 
2989ef1f84bSDavid du Colombier 	switch(PIPETYPE(c->qid.path)){
2999ef1f84bSDavid du Colombier 	case Qdir:
3009ef1f84bSDavid du Colombier 		return devdirread(c, va, n, pipedir, NPIPEDIR, pipegen);
3019ef1f84bSDavid du Colombier 	case Qdata0:
3029ef1f84bSDavid du Colombier 		return qread(p->q[0], va, n);
3039ef1f84bSDavid du Colombier 	case Qdata1:
3049ef1f84bSDavid du Colombier 		return qread(p->q[1], va, n);
3059ef1f84bSDavid du Colombier 	default:
3069ef1f84bSDavid du Colombier 		panic("piperead");
3079ef1f84bSDavid du Colombier 	}
3089ef1f84bSDavid du Colombier 	return -1;	/* not reached */
3099ef1f84bSDavid du Colombier }
3109ef1f84bSDavid du Colombier 
3119ef1f84bSDavid du Colombier static Block*
pipebread(Chan * c,long n,vlong offset)3129ef1f84bSDavid du Colombier pipebread(Chan *c, long n, vlong offset)
3139ef1f84bSDavid du Colombier {
3149ef1f84bSDavid du Colombier 	Pipe *p;
3159ef1f84bSDavid du Colombier 
3169ef1f84bSDavid du Colombier 	p = c->aux;
3179ef1f84bSDavid du Colombier 
3189ef1f84bSDavid du Colombier 	switch(PIPETYPE(c->qid.path)){
3199ef1f84bSDavid du Colombier 	case Qdata0:
3209ef1f84bSDavid du Colombier 		return qbread(p->q[0], n);
3219ef1f84bSDavid du Colombier 	case Qdata1:
3229ef1f84bSDavid du Colombier 		return qbread(p->q[1], n);
3239ef1f84bSDavid du Colombier 	}
3249ef1f84bSDavid du Colombier 
3259ef1f84bSDavid du Colombier 	return devbread(c, n, offset);
3269ef1f84bSDavid du Colombier }
3279ef1f84bSDavid du Colombier 
3289ef1f84bSDavid du Colombier /*
3299ef1f84bSDavid du Colombier  *  a write to a closed pipe causes a note to be sent to
3309ef1f84bSDavid du Colombier  *  the process.
3319ef1f84bSDavid du Colombier  */
3329ef1f84bSDavid du Colombier static long
pipewrite(Chan * c,void * va,long n,vlong)3339ef1f84bSDavid du Colombier pipewrite(Chan *c, void *va, long n, vlong)
3349ef1f84bSDavid du Colombier {
3359ef1f84bSDavid du Colombier 	Pipe *p;
3369ef1f84bSDavid du Colombier 
3379ef1f84bSDavid du Colombier 	if(!islo())
3389ef1f84bSDavid du Colombier 		print("pipewrite hi %#p\n", getcallerpc(&c));
3399ef1f84bSDavid du Colombier 	if(waserror()) {
3409ef1f84bSDavid du Colombier 		/* avoid notes when pipe is a mounted queue */
3419ef1f84bSDavid du Colombier 		if((c->flag & CMSG) == 0)
3429ef1f84bSDavid du Colombier 			postnote(up, 1, "sys: write on closed pipe", NUser);
3439ef1f84bSDavid du Colombier 		nexterror();
3449ef1f84bSDavid du Colombier 	}
3459ef1f84bSDavid du Colombier 
3469ef1f84bSDavid du Colombier 	p = c->aux;
3479ef1f84bSDavid du Colombier 
3489ef1f84bSDavid du Colombier 	switch(PIPETYPE(c->qid.path)){
3499ef1f84bSDavid du Colombier 	case Qdata0:
3509ef1f84bSDavid du Colombier 		n = qwrite(p->q[1], va, n);
3519ef1f84bSDavid du Colombier 		break;
3529ef1f84bSDavid du Colombier 
3539ef1f84bSDavid du Colombier 	case Qdata1:
3549ef1f84bSDavid du Colombier 		n = qwrite(p->q[0], va, n);
3559ef1f84bSDavid du Colombier 		break;
3569ef1f84bSDavid du Colombier 
3579ef1f84bSDavid du Colombier 	default:
3589ef1f84bSDavid du Colombier 		panic("pipewrite");
3599ef1f84bSDavid du Colombier 	}
3609ef1f84bSDavid du Colombier 
3619ef1f84bSDavid du Colombier 	poperror();
3629ef1f84bSDavid du Colombier 	return n;
3639ef1f84bSDavid du Colombier }
3649ef1f84bSDavid du Colombier 
3659ef1f84bSDavid du Colombier static long
pipebwrite(Chan * c,Block * bp,vlong)3669ef1f84bSDavid du Colombier pipebwrite(Chan *c, Block *bp, vlong)
3679ef1f84bSDavid du Colombier {
3689ef1f84bSDavid du Colombier 	long n;
3699ef1f84bSDavid du Colombier 	Pipe *p;
3709ef1f84bSDavid du Colombier 
3719ef1f84bSDavid du Colombier 	if(waserror()) {
3729ef1f84bSDavid du Colombier 		/* avoid notes when pipe is a mounted queue */
3739ef1f84bSDavid du Colombier 		if((c->flag & CMSG) == 0)
3749ef1f84bSDavid du Colombier 			postnote(up, 1, "sys: write on closed pipe", NUser);
3759ef1f84bSDavid du Colombier 		nexterror();
3769ef1f84bSDavid du Colombier 	}
3779ef1f84bSDavid du Colombier 
3789ef1f84bSDavid du Colombier 	p = c->aux;
3799ef1f84bSDavid du Colombier 	switch(PIPETYPE(c->qid.path)){
3809ef1f84bSDavid du Colombier 	case Qdata0:
3819ef1f84bSDavid du Colombier 		n = qbwrite(p->q[1], bp);
3829ef1f84bSDavid du Colombier 		break;
3839ef1f84bSDavid du Colombier 
3849ef1f84bSDavid du Colombier 	case Qdata1:
3859ef1f84bSDavid du Colombier 		n = qbwrite(p->q[0], bp);
3869ef1f84bSDavid du Colombier 		break;
3879ef1f84bSDavid du Colombier 
3889ef1f84bSDavid du Colombier 	default:
3899ef1f84bSDavid du Colombier 		n = 0;
3909ef1f84bSDavid du Colombier 		panic("pipebwrite");
3919ef1f84bSDavid du Colombier 	}
3929ef1f84bSDavid du Colombier 
3939ef1f84bSDavid du Colombier 	poperror();
3949ef1f84bSDavid du Colombier 	return n;
3959ef1f84bSDavid du Colombier }
3969ef1f84bSDavid du Colombier 
3979ef1f84bSDavid du Colombier Dev pipedevtab = {
3989ef1f84bSDavid du Colombier 	'|',
3999ef1f84bSDavid du Colombier 	"pipe",
4009ef1f84bSDavid du Colombier 
4019ef1f84bSDavid du Colombier 	devreset,
4029ef1f84bSDavid du Colombier 	devinit,
4039ef1f84bSDavid du Colombier 	devshutdown,
4049ef1f84bSDavid du Colombier 	pipeattach,
4059ef1f84bSDavid du Colombier 	pipewalk,
4069ef1f84bSDavid du Colombier 	pipestat,
4079ef1f84bSDavid du Colombier 	pipeopen,
4089ef1f84bSDavid du Colombier 	devcreate,
4099ef1f84bSDavid du Colombier 	pipeclose,
4109ef1f84bSDavid du Colombier 	piperead,
4119ef1f84bSDavid du Colombier 	pipebread,
4129ef1f84bSDavid du Colombier 	pipewrite,
4139ef1f84bSDavid du Colombier 	pipebwrite,
4149ef1f84bSDavid du Colombier 	devremove,
415*406c76faSDavid du Colombier 	pipewstat,
4169ef1f84bSDavid du Colombier };
417