xref: /plan9/sys/src/9/port/devpipe.c (revision aa72973a2891ccbd3fb042462446761159389e19)
13e12c5d1SDavid du Colombier #include	"u.h"
23e12c5d1SDavid du Colombier #include	"../port/lib.h"
33e12c5d1SDavid du Colombier #include	"mem.h"
43e12c5d1SDavid du Colombier #include	"dat.h"
53e12c5d1SDavid du Colombier #include	"fns.h"
63e12c5d1SDavid du Colombier #include	"../port/error.h"
73e12c5d1SDavid du Colombier 
87dd7cddfSDavid du Colombier #include	"netif.h"
93e12c5d1SDavid du Colombier 
103e12c5d1SDavid du Colombier typedef struct Pipe	Pipe;
113e12c5d1SDavid du Colombier struct Pipe
123e12c5d1SDavid du Colombier {
133e12c5d1SDavid du Colombier 	QLock;
143e12c5d1SDavid du Colombier 	Pipe	*next;
157dd7cddfSDavid du Colombier 	int	ref;
163e12c5d1SDavid du Colombier 	ulong	path;
17*aa72973aSDavid du Colombier 	long	perm;
187dd7cddfSDavid du Colombier 	Queue	*q[2];
197dd7cddfSDavid du Colombier 	int	qref[2];
203e12c5d1SDavid du Colombier };
213e12c5d1SDavid du Colombier 
223e12c5d1SDavid du Colombier struct
233e12c5d1SDavid du Colombier {
243e12c5d1SDavid du Colombier 	Lock;
253e12c5d1SDavid du Colombier 	ulong	path;
263e12c5d1SDavid du Colombier } pipealloc;
273e12c5d1SDavid du Colombier 
287dd7cddfSDavid du Colombier enum
293e12c5d1SDavid du Colombier {
307dd7cddfSDavid du Colombier 	Qdir,
317dd7cddfSDavid du Colombier 	Qdata0,
327dd7cddfSDavid du Colombier 	Qdata1,
333e12c5d1SDavid du Colombier };
343e12c5d1SDavid du Colombier 
353e12c5d1SDavid du Colombier Dirtab pipedir[] =
363e12c5d1SDavid du Colombier {
379a747e4fSDavid du Colombier 	".",		{Qdir,0,QTDIR},	0,		DMDIR|0500,
387dd7cddfSDavid du Colombier 	"data",		{Qdata0},	0,		0600,
397dd7cddfSDavid du Colombier 	"data1",	{Qdata1},	0,		0600,
403e12c5d1SDavid du Colombier };
419a747e4fSDavid du Colombier #define NPIPEDIR 3
423e12c5d1SDavid du Colombier 
437dd7cddfSDavid du Colombier static void
pipeinit(void)443e12c5d1SDavid du Colombier pipeinit(void)
453e12c5d1SDavid du Colombier {
467dd7cddfSDavid du Colombier 	if(conf.pipeqsize == 0){
477dd7cddfSDavid du Colombier 		if(conf.nmach > 1)
487dd7cddfSDavid du Colombier 			conf.pipeqsize = 256*1024;
497dd7cddfSDavid du Colombier 		else
507dd7cddfSDavid du Colombier 			conf.pipeqsize = 32*1024;
513e12c5d1SDavid du Colombier 	}
523e12c5d1SDavid du Colombier }
533e12c5d1SDavid du Colombier 
543e12c5d1SDavid du Colombier /*
553e12c5d1SDavid du Colombier  *  create a pipe, no streams are created until an open
563e12c5d1SDavid du Colombier  */
577dd7cddfSDavid du Colombier static Chan*
pipeattach(char * spec)583e12c5d1SDavid du Colombier pipeattach(char *spec)
593e12c5d1SDavid du Colombier {
603e12c5d1SDavid du Colombier 	Pipe *p;
613e12c5d1SDavid du Colombier 	Chan *c;
623e12c5d1SDavid du Colombier 
633e12c5d1SDavid du Colombier 	c = devattach('|', spec);
647dd7cddfSDavid du Colombier 	p = malloc(sizeof(Pipe));
657dd7cddfSDavid du Colombier 	if(p == 0)
667dd7cddfSDavid du Colombier 		exhausted("memory");
673e12c5d1SDavid du Colombier 	p->ref = 1;
683e12c5d1SDavid du Colombier 
697dd7cddfSDavid du Colombier 	p->q[0] = qopen(conf.pipeqsize, 0, 0, 0);
707dd7cddfSDavid du Colombier 	if(p->q[0] == 0){
717dd7cddfSDavid du Colombier 		free(p);
727dd7cddfSDavid du Colombier 		exhausted("memory");
737dd7cddfSDavid du Colombier 	}
747dd7cddfSDavid du Colombier 	p->q[1] = qopen(conf.pipeqsize, 0, 0, 0);
757dd7cddfSDavid du Colombier 	if(p->q[1] == 0){
767dd7cddfSDavid du Colombier 		free(p->q[0]);
777dd7cddfSDavid du Colombier 		free(p);
787dd7cddfSDavid du Colombier 		exhausted("memory");
797dd7cddfSDavid du Colombier 	}
807dd7cddfSDavid du Colombier 
813e12c5d1SDavid du Colombier 	lock(&pipealloc);
823e12c5d1SDavid du Colombier 	p->path = ++pipealloc.path;
833e12c5d1SDavid du Colombier 	unlock(&pipealloc);
84*aa72973aSDavid du Colombier 	p->perm = pipedir[Qdata0].perm;
853e12c5d1SDavid du Colombier 
869a747e4fSDavid du Colombier 	mkqid(&c->qid, NETQID(2*p->path, Qdir), 0, QTDIR);
877dd7cddfSDavid du Colombier 	c->aux = p;
883e12c5d1SDavid du Colombier 	c->dev = 0;
893e12c5d1SDavid du Colombier 	return c;
903e12c5d1SDavid du Colombier }
913e12c5d1SDavid du Colombier 
927dd7cddfSDavid du Colombier static int
pipegen(Chan * c,char *,Dirtab * tab,int ntab,int i,Dir * dp)939a747e4fSDavid du Colombier pipegen(Chan *c, char*, Dirtab *tab, int ntab, int i, Dir *dp)
943e12c5d1SDavid du Colombier {
959a747e4fSDavid du Colombier 	Qid q;
9636d3592fSDavid du Colombier 	int len;
9736d3592fSDavid du Colombier 	Pipe *p;
983e12c5d1SDavid du Colombier 
997dd7cddfSDavid du Colombier 	if(i == DEVDOTDOT){
1009a747e4fSDavid du Colombier 		devdir(c, c->qid, "#|", 0, eve, DMDIR|0555, dp);
1017dd7cddfSDavid du Colombier 		return 1;
1027dd7cddfSDavid du Colombier 	}
1039a747e4fSDavid du Colombier 	i++;	/* skip . */
1043e12c5d1SDavid du Colombier 	if(tab==0 || i>=ntab)
1053e12c5d1SDavid du Colombier 		return -1;
1069a747e4fSDavid du Colombier 
1073e12c5d1SDavid du Colombier 	tab += i;
10836d3592fSDavid du Colombier 	p = c->aux;
10936d3592fSDavid du Colombier 	switch((ulong)tab->qid.path){
11036d3592fSDavid du Colombier 	case Qdata0:
11136d3592fSDavid du Colombier 		len = qlen(p->q[0]);
11236d3592fSDavid du Colombier 		break;
11336d3592fSDavid du Colombier 	case Qdata1:
11436d3592fSDavid du Colombier 		len = qlen(p->q[1]);
11536d3592fSDavid du Colombier 		break;
11636d3592fSDavid du Colombier 	default:
11736d3592fSDavid du Colombier 		len = tab->length;
11836d3592fSDavid du Colombier 		break;
11936d3592fSDavid du Colombier 	}
1209a747e4fSDavid du Colombier 	mkqid(&q, NETQID(NETID(c->qid.path), tab->qid.path), 0, QTFILE);
121*aa72973aSDavid du Colombier 	devdir(c, q, tab->name, len, eve, p->perm, dp);
1223e12c5d1SDavid du Colombier 	return 1;
1233e12c5d1SDavid du Colombier }
1243e12c5d1SDavid du Colombier 
1253e12c5d1SDavid du Colombier 
1269a747e4fSDavid du Colombier static Walkqid*
pipewalk(Chan * c,Chan * nc,char ** name,int nname)1279a747e4fSDavid du Colombier pipewalk(Chan *c, Chan *nc, char **name, int nname)
1283e12c5d1SDavid du Colombier {
1299a747e4fSDavid du Colombier 	Walkqid *wq;
1309a747e4fSDavid du Colombier 	Pipe *p;
1319a747e4fSDavid du Colombier 
1329a747e4fSDavid du Colombier 	wq = devwalk(c, nc, name, nname, pipedir, NPIPEDIR, pipegen);
1339a747e4fSDavid du Colombier 	if(wq != nil && wq->clone != nil && wq->clone != c){
1349a747e4fSDavid du Colombier 		p = c->aux;
1359a747e4fSDavid du Colombier 		qlock(p);
1369a747e4fSDavid du Colombier 		p->ref++;
1379a747e4fSDavid du Colombier 		if(c->flag & COPEN){
1389a747e4fSDavid du Colombier 			print("channel open in pipewalk\n");
1399a747e4fSDavid du Colombier 			switch(NETTYPE(c->qid.path)){
1409a747e4fSDavid du Colombier 			case Qdata0:
1419a747e4fSDavid du Colombier 				p->qref[0]++;
1429a747e4fSDavid du Colombier 				break;
1439a747e4fSDavid du Colombier 			case Qdata1:
1449a747e4fSDavid du Colombier 				p->qref[1]++;
1459a747e4fSDavid du Colombier 				break;
1469a747e4fSDavid du Colombier 			}
1479a747e4fSDavid du Colombier 		}
1489a747e4fSDavid du Colombier 		qunlock(p);
1499a747e4fSDavid du Colombier 	}
1509a747e4fSDavid du Colombier 	return wq;
1513e12c5d1SDavid du Colombier }
1523e12c5d1SDavid du Colombier 
1539a747e4fSDavid du Colombier static int
pipestat(Chan * c,uchar * db,int n)1549a747e4fSDavid du Colombier pipestat(Chan *c, uchar *db, int n)
1553e12c5d1SDavid du Colombier {
15636d3592fSDavid du Colombier 	Pipe *p;
1577dd7cddfSDavid du Colombier 	Dir dir;
1587dd7cddfSDavid du Colombier 
15936d3592fSDavid du Colombier 	p = c->aux;
16036d3592fSDavid du Colombier 
1617dd7cddfSDavid du Colombier 	switch(NETTYPE(c->qid.path)){
1627dd7cddfSDavid du Colombier 	case Qdir:
1639a747e4fSDavid du Colombier 		devdir(c, c->qid, ".", 0, eve, DMDIR|0555, &dir);
1647dd7cddfSDavid du Colombier 		break;
1657dd7cddfSDavid du Colombier 	case Qdata0:
166*aa72973aSDavid du Colombier 		devdir(c, c->qid, "data", qlen(p->q[0]), eve, p->perm, &dir);
1677dd7cddfSDavid du Colombier 		break;
1687dd7cddfSDavid du Colombier 	case Qdata1:
169*aa72973aSDavid du Colombier 		devdir(c, c->qid, "data1", qlen(p->q[1]), eve, p->perm, &dir);
1707dd7cddfSDavid du Colombier 		break;
1717dd7cddfSDavid du Colombier 	default:
1727dd7cddfSDavid du Colombier 		panic("pipestat");
1737dd7cddfSDavid du Colombier 	}
1749a747e4fSDavid du Colombier 	n = convD2M(&dir, db, n);
1759a747e4fSDavid du Colombier 	if(n < BIT16SZ)
1769a747e4fSDavid du Colombier 		error(Eshortstat);
1779a747e4fSDavid du Colombier 	return n;
1783e12c5d1SDavid du Colombier }
1793e12c5d1SDavid du Colombier 
180*aa72973aSDavid du Colombier static int
pipewstat(Chan * c,uchar * db,int n)181*aa72973aSDavid du Colombier pipewstat(Chan* c, uchar* db, int n)
182*aa72973aSDavid du Colombier {
183*aa72973aSDavid du Colombier 	int m;
184*aa72973aSDavid du Colombier 	Dir *dir;
185*aa72973aSDavid du Colombier 	Pipe *p;
186*aa72973aSDavid du Colombier 
187*aa72973aSDavid du Colombier 	p = c->aux;
188*aa72973aSDavid du Colombier 	if(strcmp(up->user, eve) != 0)
189*aa72973aSDavid du Colombier 		error(Eperm);
190*aa72973aSDavid du Colombier 	if(NETTYPE(c->qid.path) == Qdir)
191*aa72973aSDavid du Colombier 		error(Eisdir);
192*aa72973aSDavid du Colombier 
193*aa72973aSDavid du Colombier 	dir = smalloc(sizeof(Dir)+n);
194*aa72973aSDavid du Colombier 	if(waserror()){
195*aa72973aSDavid du Colombier 		free(dir);
196*aa72973aSDavid du Colombier 		nexterror();
197*aa72973aSDavid du Colombier 	}
198*aa72973aSDavid du Colombier 	m = convM2D(db, n, &dir[0], (char*)&dir[1]);
199*aa72973aSDavid du Colombier 	if(m == 0)
200*aa72973aSDavid du Colombier 		error(Eshortstat);
201*aa72973aSDavid du Colombier 	if(!emptystr(dir[0].uid))
202*aa72973aSDavid du Colombier 		error("can't change owner");
203*aa72973aSDavid du Colombier 	if(dir[0].mode != ~0UL)
204*aa72973aSDavid du Colombier 		p->perm = dir[0].mode;
205*aa72973aSDavid du Colombier 	poperror();
206*aa72973aSDavid du Colombier 	free(dir);
207*aa72973aSDavid du Colombier 	return m;
208*aa72973aSDavid du Colombier }
209*aa72973aSDavid du Colombier 
2103e12c5d1SDavid du Colombier /*
2113e12c5d1SDavid du Colombier  *  if the stream doesn't exist, create it
2123e12c5d1SDavid du Colombier  */
2137dd7cddfSDavid du Colombier static Chan*
pipeopen(Chan * c,int omode)2143e12c5d1SDavid du Colombier pipeopen(Chan *c, int omode)
2153e12c5d1SDavid du Colombier {
2163e12c5d1SDavid du Colombier 	Pipe *p;
2173e12c5d1SDavid du Colombier 
2189a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR){
2193e12c5d1SDavid du Colombier 		if(omode != OREAD)
2203e12c5d1SDavid du Colombier 			error(Ebadarg);
2213e12c5d1SDavid du Colombier 		c->mode = omode;
2223e12c5d1SDavid du Colombier 		c->flag |= COPEN;
2233e12c5d1SDavid du Colombier 		c->offset = 0;
2243e12c5d1SDavid du Colombier 		return c;
2253e12c5d1SDavid du Colombier 	}
2263e12c5d1SDavid du Colombier 
2277dd7cddfSDavid du Colombier 	p = c->aux;
2283e12c5d1SDavid du Colombier 	qlock(p);
2297dd7cddfSDavid du Colombier 	switch(NETTYPE(c->qid.path)){
2307dd7cddfSDavid du Colombier 	case Qdata0:
2317dd7cddfSDavid du Colombier 		p->qref[0]++;
2327dd7cddfSDavid du Colombier 		break;
2337dd7cddfSDavid du Colombier 	case Qdata1:
2347dd7cddfSDavid du Colombier 		p->qref[1]++;
2357dd7cddfSDavid du Colombier 		break;
2363e12c5d1SDavid du Colombier 	}
2373e12c5d1SDavid du Colombier 	qunlock(p);
2383e12c5d1SDavid du Colombier 
239219b2ee8SDavid du Colombier 	c->mode = openmode(omode);
2403e12c5d1SDavid du Colombier 	c->flag |= COPEN;
2413e12c5d1SDavid du Colombier 	c->offset = 0;
2429a747e4fSDavid du Colombier 	c->iounit = qiomaxatomic;
2433e12c5d1SDavid du Colombier 	return c;
2443e12c5d1SDavid du Colombier }
2453e12c5d1SDavid du Colombier 
2467dd7cddfSDavid du Colombier static void
pipeclose(Chan * c)2473e12c5d1SDavid du Colombier pipeclose(Chan *c)
2483e12c5d1SDavid du Colombier {
2497dd7cddfSDavid du Colombier 	Pipe *p;
2503e12c5d1SDavid du Colombier 
2517dd7cddfSDavid du Colombier 	p = c->aux;
2527dd7cddfSDavid du Colombier 	qlock(p);
2537dd7cddfSDavid du Colombier 
2547dd7cddfSDavid du Colombier 	if(c->flag & COPEN){
2557dd7cddfSDavid du Colombier 		/*
2567dd7cddfSDavid du Colombier 		 *  closing either side hangs up the stream
2577dd7cddfSDavid du Colombier 		 */
2587dd7cddfSDavid du Colombier 		switch(NETTYPE(c->qid.path)){
2597dd7cddfSDavid du Colombier 		case Qdata0:
2607dd7cddfSDavid du Colombier 			p->qref[0]--;
2617dd7cddfSDavid du Colombier 			if(p->qref[0] == 0){
2627dd7cddfSDavid du Colombier 				qhangup(p->q[1], 0);
2637dd7cddfSDavid du Colombier 				qclose(p->q[0]);
2647dd7cddfSDavid du Colombier 			}
2657dd7cddfSDavid du Colombier 			break;
2667dd7cddfSDavid du Colombier 		case Qdata1:
2677dd7cddfSDavid du Colombier 			p->qref[1]--;
2687dd7cddfSDavid du Colombier 			if(p->qref[1] == 0){
2697dd7cddfSDavid du Colombier 				qhangup(p->q[0], 0);
2707dd7cddfSDavid du Colombier 				qclose(p->q[1]);
2717dd7cddfSDavid du Colombier 			}
2727dd7cddfSDavid du Colombier 			break;
2737dd7cddfSDavid du Colombier 		}
2747dd7cddfSDavid du Colombier 	}
2757dd7cddfSDavid du Colombier 
2763e12c5d1SDavid du Colombier 
2773e12c5d1SDavid du Colombier 	/*
2787dd7cddfSDavid du Colombier 	 *  if both sides are closed, they are reusable
2793e12c5d1SDavid du Colombier 	 */
2807dd7cddfSDavid du Colombier 	if(p->qref[0] == 0 && p->qref[1] == 0){
2817dd7cddfSDavid du Colombier 		qreopen(p->q[0]);
2827dd7cddfSDavid du Colombier 		qreopen(p->q[1]);
2833e12c5d1SDavid du Colombier 	}
2847dd7cddfSDavid du Colombier 
2857dd7cddfSDavid du Colombier 	/*
2867dd7cddfSDavid du Colombier 	 *  free the structure on last close
2877dd7cddfSDavid du Colombier 	 */
2887dd7cddfSDavid du Colombier 	p->ref--;
2897dd7cddfSDavid du Colombier 	if(p->ref == 0){
2907dd7cddfSDavid du Colombier 		qunlock(p);
2917dd7cddfSDavid du Colombier 		free(p->q[0]);
2927dd7cddfSDavid du Colombier 		free(p->q[1]);
2937dd7cddfSDavid du Colombier 		free(p);
2947dd7cddfSDavid du Colombier 	} else
2953e12c5d1SDavid du Colombier 		qunlock(p);
2963e12c5d1SDavid du Colombier }
2973e12c5d1SDavid du Colombier 
2987dd7cddfSDavid du Colombier static long
piperead(Chan * c,void * va,long n,vlong)2997dd7cddfSDavid du Colombier piperead(Chan *c, void *va, long n, vlong)
3003e12c5d1SDavid du Colombier {
3017dd7cddfSDavid du Colombier 	Pipe *p;
3023e12c5d1SDavid du Colombier 
3037dd7cddfSDavid du Colombier 	p = c->aux;
3047dd7cddfSDavid du Colombier 
3057dd7cddfSDavid du Colombier 	switch(NETTYPE(c->qid.path)){
3067dd7cddfSDavid du Colombier 	case Qdir:
3077dd7cddfSDavid du Colombier 		return devdirread(c, va, n, pipedir, NPIPEDIR, pipegen);
3087dd7cddfSDavid du Colombier 	case Qdata0:
3097dd7cddfSDavid du Colombier 		return qread(p->q[0], va, n);
3107dd7cddfSDavid du Colombier 	case Qdata1:
3117dd7cddfSDavid du Colombier 		return qread(p->q[1], va, n);
3127dd7cddfSDavid du Colombier 	default:
3137dd7cddfSDavid du Colombier 		panic("piperead");
3147dd7cddfSDavid du Colombier 	}
3157dd7cddfSDavid du Colombier 	return -1;	/* not reached */
3167dd7cddfSDavid du Colombier }
3177dd7cddfSDavid du Colombier 
3187dd7cddfSDavid du Colombier static Block*
pipebread(Chan * c,long n,ulong offset)3197dd7cddfSDavid du Colombier pipebread(Chan *c, long n, ulong offset)
3207dd7cddfSDavid du Colombier {
3217dd7cddfSDavid du Colombier 	Pipe *p;
3227dd7cddfSDavid du Colombier 
3237dd7cddfSDavid du Colombier 	p = c->aux;
3247dd7cddfSDavid du Colombier 
3257dd7cddfSDavid du Colombier 	switch(NETTYPE(c->qid.path)){
3267dd7cddfSDavid du Colombier 	case Qdata0:
3277dd7cddfSDavid du Colombier 		return qbread(p->q[0], n);
3287dd7cddfSDavid du Colombier 	case Qdata1:
3297dd7cddfSDavid du Colombier 		return qbread(p->q[1], n);
3307dd7cddfSDavid du Colombier 	}
3317dd7cddfSDavid du Colombier 
3327dd7cddfSDavid du Colombier 	return devbread(c, n, offset);
3333e12c5d1SDavid du Colombier }
3343e12c5d1SDavid du Colombier 
3353e12c5d1SDavid du Colombier /*
3363e12c5d1SDavid du Colombier  *  a write to a closed pipe causes a note to be sent to
3373e12c5d1SDavid du Colombier  *  the process.
3383e12c5d1SDavid du Colombier  */
3397dd7cddfSDavid du Colombier static long
pipewrite(Chan * c,void * va,long n,vlong)3407dd7cddfSDavid du Colombier pipewrite(Chan *c, void *va, long n, vlong)
3413e12c5d1SDavid du Colombier {
3427dd7cddfSDavid du Colombier 	Pipe *p;
3433e12c5d1SDavid du Colombier 
3447dd7cddfSDavid du Colombier 	if(!islo())
345567483c8SDavid du Colombier 		print("pipewrite hi %#p\n", getcallerpc(&c));
3463e12c5d1SDavid du Colombier 	if(waserror()) {
3477dd7cddfSDavid du Colombier 		/* avoid notes when pipe is a mounted queue */
3487dd7cddfSDavid du Colombier 		if((c->flag & CMSG) == 0)
3497dd7cddfSDavid du Colombier 			postnote(up, 1, "sys: write on closed pipe", NUser);
3507dd7cddfSDavid du Colombier 		nexterror();
3513e12c5d1SDavid du Colombier 	}
3527dd7cddfSDavid du Colombier 
3537dd7cddfSDavid du Colombier 	p = c->aux;
3547dd7cddfSDavid du Colombier 
3557dd7cddfSDavid du Colombier 	switch(NETTYPE(c->qid.path)){
3567dd7cddfSDavid du Colombier 	case Qdata0:
3577dd7cddfSDavid du Colombier 		n = qwrite(p->q[1], va, n);
3587dd7cddfSDavid du Colombier 		break;
3597dd7cddfSDavid du Colombier 
3607dd7cddfSDavid du Colombier 	case Qdata1:
3617dd7cddfSDavid du Colombier 		n = qwrite(p->q[0], va, n);
3627dd7cddfSDavid du Colombier 		break;
3637dd7cddfSDavid du Colombier 
3647dd7cddfSDavid du Colombier 	default:
3657dd7cddfSDavid du Colombier 		panic("pipewrite");
3667dd7cddfSDavid du Colombier 	}
3677dd7cddfSDavid du Colombier 
3683e12c5d1SDavid du Colombier 	poperror();
3693e12c5d1SDavid du Colombier 	return n;
3703e12c5d1SDavid du Colombier }
3713e12c5d1SDavid du Colombier 
3727dd7cddfSDavid du Colombier static long
pipebwrite(Chan * c,Block * bp,ulong)3737dd7cddfSDavid du Colombier pipebwrite(Chan *c, Block *bp, ulong)
3743e12c5d1SDavid du Colombier {
3757dd7cddfSDavid du Colombier 	long n;
3763e12c5d1SDavid du Colombier 	Pipe *p;
3773e12c5d1SDavid du Colombier 
3787dd7cddfSDavid du Colombier 	if(waserror()) {
3797dd7cddfSDavid du Colombier 		/* avoid notes when pipe is a mounted queue */
3807dd7cddfSDavid du Colombier 		if((c->flag & CMSG) == 0)
3817dd7cddfSDavid du Colombier 			postnote(up, 1, "sys: write on closed pipe", NUser);
3827dd7cddfSDavid du Colombier 		nexterror();
3833e12c5d1SDavid du Colombier 	}
3847dd7cddfSDavid du Colombier 
3857dd7cddfSDavid du Colombier 	p = c->aux;
3867dd7cddfSDavid du Colombier 	switch(NETTYPE(c->qid.path)){
3877dd7cddfSDavid du Colombier 	case Qdata0:
3887dd7cddfSDavid du Colombier 		n = qbwrite(p->q[1], bp);
3897dd7cddfSDavid du Colombier 		break;
3907dd7cddfSDavid du Colombier 
3917dd7cddfSDavid du Colombier 	case Qdata1:
3927dd7cddfSDavid du Colombier 		n = qbwrite(p->q[0], bp);
3937dd7cddfSDavid du Colombier 		break;
3947dd7cddfSDavid du Colombier 
3957dd7cddfSDavid du Colombier 	default:
3967dd7cddfSDavid du Colombier 		n = 0;
3977dd7cddfSDavid du Colombier 		panic("pipebwrite");
3983e12c5d1SDavid du Colombier 	}
3997dd7cddfSDavid du Colombier 
4007dd7cddfSDavid du Colombier 	poperror();
4017dd7cddfSDavid du Colombier 	return n;
4023e12c5d1SDavid du Colombier }
4037dd7cddfSDavid du Colombier 
4047dd7cddfSDavid du Colombier Dev pipedevtab = {
4057dd7cddfSDavid du Colombier 	'|',
4067dd7cddfSDavid du Colombier 	"pipe",
4077dd7cddfSDavid du Colombier 
4087dd7cddfSDavid du Colombier 	devreset,
4097dd7cddfSDavid du Colombier 	pipeinit,
4109a747e4fSDavid du Colombier 	devshutdown,
4117dd7cddfSDavid du Colombier 	pipeattach,
4127dd7cddfSDavid du Colombier 	pipewalk,
4137dd7cddfSDavid du Colombier 	pipestat,
4147dd7cddfSDavid du Colombier 	pipeopen,
4157dd7cddfSDavid du Colombier 	devcreate,
4167dd7cddfSDavid du Colombier 	pipeclose,
4177dd7cddfSDavid du Colombier 	piperead,
4187dd7cddfSDavid du Colombier 	pipebread,
4197dd7cddfSDavid du Colombier 	pipewrite,
4207dd7cddfSDavid du Colombier 	pipebwrite,
4217dd7cddfSDavid du Colombier 	devremove,
422*aa72973aSDavid du Colombier 	pipewstat,
4237dd7cddfSDavid du Colombier };
424