xref: /plan9/sys/src/cmd/unix/drawterm/kern/devpipe.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1*8ccd4a63SDavid du Colombier #include	"u.h"
2*8ccd4a63SDavid du Colombier #include	"lib.h"
3*8ccd4a63SDavid du Colombier #include	"dat.h"
4*8ccd4a63SDavid du Colombier #include	"fns.h"
5*8ccd4a63SDavid du Colombier #include	"error.h"
6*8ccd4a63SDavid du Colombier 
7*8ccd4a63SDavid du Colombier #include	"netif.h"
8*8ccd4a63SDavid du Colombier 
9*8ccd4a63SDavid du Colombier typedef struct Pipe	Pipe;
10*8ccd4a63SDavid du Colombier struct Pipe
11*8ccd4a63SDavid du Colombier {
12*8ccd4a63SDavid du Colombier 	QLock lk;
13*8ccd4a63SDavid du Colombier 	Pipe	*next;
14*8ccd4a63SDavid du Colombier 	int	ref;
15*8ccd4a63SDavid du Colombier 	ulong	path;
16*8ccd4a63SDavid du Colombier 	Queue	*q[2];
17*8ccd4a63SDavid du Colombier 	int	qref[2];
18*8ccd4a63SDavid du Colombier };
19*8ccd4a63SDavid du Colombier 
20*8ccd4a63SDavid du Colombier struct
21*8ccd4a63SDavid du Colombier {
22*8ccd4a63SDavid du Colombier 	Lock lk;
23*8ccd4a63SDavid du Colombier 	ulong	path;
24*8ccd4a63SDavid du Colombier } pipealloc;
25*8ccd4a63SDavid du Colombier 
26*8ccd4a63SDavid du Colombier enum
27*8ccd4a63SDavid du Colombier {
28*8ccd4a63SDavid du Colombier 	Qdir,
29*8ccd4a63SDavid du Colombier 	Qdata0,
30*8ccd4a63SDavid du Colombier 	Qdata1,
31*8ccd4a63SDavid du Colombier };
32*8ccd4a63SDavid du Colombier 
33*8ccd4a63SDavid du Colombier Dirtab pipedir[] =
34*8ccd4a63SDavid du Colombier {
35*8ccd4a63SDavid du Colombier 	".",		{Qdir,0,QTDIR},	0,		DMDIR|0500,
36*8ccd4a63SDavid du Colombier 	"data",		{Qdata0},	0,		0600,
37*8ccd4a63SDavid du Colombier 	"data1",	{Qdata1},	0,		0600,
38*8ccd4a63SDavid du Colombier };
39*8ccd4a63SDavid du Colombier #define NPIPEDIR 3
40*8ccd4a63SDavid du Colombier 
41*8ccd4a63SDavid du Colombier static void
pipeinit(void)42*8ccd4a63SDavid du Colombier pipeinit(void)
43*8ccd4a63SDavid du Colombier {
44*8ccd4a63SDavid du Colombier 	if(conf.pipeqsize == 0){
45*8ccd4a63SDavid du Colombier 		if(conf.nmach > 1)
46*8ccd4a63SDavid du Colombier 			conf.pipeqsize = 256*1024;
47*8ccd4a63SDavid du Colombier 		else
48*8ccd4a63SDavid du Colombier 			conf.pipeqsize = 32*1024;
49*8ccd4a63SDavid du Colombier 	}
50*8ccd4a63SDavid du Colombier }
51*8ccd4a63SDavid du Colombier 
52*8ccd4a63SDavid du Colombier /*
53*8ccd4a63SDavid du Colombier  *  create a pipe, no streams are created until an open
54*8ccd4a63SDavid du Colombier  */
55*8ccd4a63SDavid du Colombier static Chan*
pipeattach(char * spec)56*8ccd4a63SDavid du Colombier pipeattach(char *spec)
57*8ccd4a63SDavid du Colombier {
58*8ccd4a63SDavid du Colombier 	Pipe *p;
59*8ccd4a63SDavid du Colombier 	Chan *c;
60*8ccd4a63SDavid du Colombier 
61*8ccd4a63SDavid du Colombier 	c = devattach('|', spec);
62*8ccd4a63SDavid du Colombier 	p = malloc(sizeof(Pipe));
63*8ccd4a63SDavid du Colombier 	if(p == 0)
64*8ccd4a63SDavid du Colombier 		exhausted("memory");
65*8ccd4a63SDavid du Colombier 	p->ref = 1;
66*8ccd4a63SDavid du Colombier 
67*8ccd4a63SDavid du Colombier 	p->q[0] = qopen(conf.pipeqsize, 0, 0, 0);
68*8ccd4a63SDavid du Colombier 	if(p->q[0] == 0){
69*8ccd4a63SDavid du Colombier 		free(p);
70*8ccd4a63SDavid du Colombier 		exhausted("memory");
71*8ccd4a63SDavid du Colombier 	}
72*8ccd4a63SDavid du Colombier 	p->q[1] = qopen(conf.pipeqsize, 0, 0, 0);
73*8ccd4a63SDavid du Colombier 	if(p->q[1] == 0){
74*8ccd4a63SDavid du Colombier 		free(p->q[0]);
75*8ccd4a63SDavid du Colombier 		free(p);
76*8ccd4a63SDavid du Colombier 		exhausted("memory");
77*8ccd4a63SDavid du Colombier 	}
78*8ccd4a63SDavid du Colombier 
79*8ccd4a63SDavid du Colombier 	lock(&pipealloc.lk);
80*8ccd4a63SDavid du Colombier 	p->path = ++pipealloc.path;
81*8ccd4a63SDavid du Colombier 	unlock(&pipealloc.lk);
82*8ccd4a63SDavid du Colombier 
83*8ccd4a63SDavid du Colombier 	mkqid(&c->qid, NETQID(2*p->path, Qdir), 0, QTDIR);
84*8ccd4a63SDavid du Colombier 	c->aux = p;
85*8ccd4a63SDavid du Colombier 	c->dev = 0;
86*8ccd4a63SDavid du Colombier 	return c;
87*8ccd4a63SDavid du Colombier }
88*8ccd4a63SDavid du Colombier 
89*8ccd4a63SDavid du Colombier static int
pipegen(Chan * c,char * name,Dirtab * tab,int ntab,int i,Dir * dp)90*8ccd4a63SDavid du Colombier pipegen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
91*8ccd4a63SDavid du Colombier {
92*8ccd4a63SDavid du Colombier 	Qid q;
93*8ccd4a63SDavid du Colombier 	int len;
94*8ccd4a63SDavid du Colombier 	Pipe *p;
95*8ccd4a63SDavid du Colombier 
96*8ccd4a63SDavid du Colombier 	USED(name);
97*8ccd4a63SDavid du Colombier 
98*8ccd4a63SDavid du Colombier 	if(i == DEVDOTDOT){
99*8ccd4a63SDavid du Colombier 		devdir(c, c->qid, "#|", 0, eve, DMDIR|0555, dp);
100*8ccd4a63SDavid du Colombier 		return 1;
101*8ccd4a63SDavid du Colombier 	}
102*8ccd4a63SDavid du Colombier 	i++;	/* skip . */
103*8ccd4a63SDavid du Colombier 	if(tab==0 || i>=ntab)
104*8ccd4a63SDavid du Colombier 		return -1;
105*8ccd4a63SDavid du Colombier 
106*8ccd4a63SDavid du Colombier 	tab += i;
107*8ccd4a63SDavid du Colombier 	p = c->aux;
108*8ccd4a63SDavid du Colombier 	switch((ulong)tab->qid.path){
109*8ccd4a63SDavid du Colombier 	case Qdata0:
110*8ccd4a63SDavid du Colombier 		len = qlen(p->q[0]);
111*8ccd4a63SDavid du Colombier 		break;
112*8ccd4a63SDavid du Colombier 	case Qdata1:
113*8ccd4a63SDavid du Colombier 		len = qlen(p->q[1]);
114*8ccd4a63SDavid du Colombier 		break;
115*8ccd4a63SDavid du Colombier 	default:
116*8ccd4a63SDavid du Colombier 		len = tab->length;
117*8ccd4a63SDavid du Colombier 		break;
118*8ccd4a63SDavid du Colombier 	}
119*8ccd4a63SDavid du Colombier 	mkqid(&q, NETQID(NETID(c->qid.path), tab->qid.path), 0, QTFILE);
120*8ccd4a63SDavid du Colombier 	devdir(c, q, tab->name, len, eve, tab->perm, dp);
121*8ccd4a63SDavid du Colombier 	return 1;
122*8ccd4a63SDavid du Colombier }
123*8ccd4a63SDavid du Colombier 
124*8ccd4a63SDavid du Colombier 
125*8ccd4a63SDavid du Colombier static Walkqid*
pipewalk(Chan * c,Chan * nc,char ** name,int nname)126*8ccd4a63SDavid du Colombier pipewalk(Chan *c, Chan *nc, char **name, int nname)
127*8ccd4a63SDavid du Colombier {
128*8ccd4a63SDavid du Colombier 	Walkqid *wq;
129*8ccd4a63SDavid du Colombier 	Pipe *p;
130*8ccd4a63SDavid du Colombier 
131*8ccd4a63SDavid du Colombier 	wq = devwalk(c, nc, name, nname, pipedir, NPIPEDIR, pipegen);
132*8ccd4a63SDavid du Colombier 	if(wq != nil && wq->clone != nil && wq->clone != c){
133*8ccd4a63SDavid du Colombier 		p = c->aux;
134*8ccd4a63SDavid du Colombier 		qlock(&p->lk);
135*8ccd4a63SDavid du Colombier 		p->ref++;
136*8ccd4a63SDavid du Colombier 		if(c->flag & COPEN){
137*8ccd4a63SDavid du Colombier 			print("channel open in pipewalk\n");
138*8ccd4a63SDavid du Colombier 			switch(NETTYPE(c->qid.path)){
139*8ccd4a63SDavid du Colombier 			case Qdata0:
140*8ccd4a63SDavid du Colombier 				p->qref[0]++;
141*8ccd4a63SDavid du Colombier 				break;
142*8ccd4a63SDavid du Colombier 			case Qdata1:
143*8ccd4a63SDavid du Colombier 				p->qref[1]++;
144*8ccd4a63SDavid du Colombier 				break;
145*8ccd4a63SDavid du Colombier 			}
146*8ccd4a63SDavid du Colombier 		}
147*8ccd4a63SDavid du Colombier 		qunlock(&p->lk);
148*8ccd4a63SDavid du Colombier 	}
149*8ccd4a63SDavid du Colombier 	return wq;
150*8ccd4a63SDavid du Colombier }
151*8ccd4a63SDavid du Colombier 
152*8ccd4a63SDavid du Colombier static int
pipestat(Chan * c,uchar * db,int n)153*8ccd4a63SDavid du Colombier pipestat(Chan *c, uchar *db, int n)
154*8ccd4a63SDavid du Colombier {
155*8ccd4a63SDavid du Colombier 	Pipe *p;
156*8ccd4a63SDavid du Colombier 	Dir dir;
157*8ccd4a63SDavid du Colombier 
158*8ccd4a63SDavid du Colombier 	p = c->aux;
159*8ccd4a63SDavid du Colombier 
160*8ccd4a63SDavid du Colombier 	switch(NETTYPE(c->qid.path)){
161*8ccd4a63SDavid du Colombier 	case Qdir:
162*8ccd4a63SDavid du Colombier 		devdir(c, c->qid, ".", 0, eve, DMDIR|0555, &dir);
163*8ccd4a63SDavid du Colombier 		break;
164*8ccd4a63SDavid du Colombier 	case Qdata0:
165*8ccd4a63SDavid du Colombier 		devdir(c, c->qid, "data", qlen(p->q[0]), eve, 0600, &dir);
166*8ccd4a63SDavid du Colombier 		break;
167*8ccd4a63SDavid du Colombier 	case Qdata1:
168*8ccd4a63SDavid du Colombier 		devdir(c, c->qid, "data1", qlen(p->q[1]), eve, 0600, &dir);
169*8ccd4a63SDavid du Colombier 		break;
170*8ccd4a63SDavid du Colombier 	default:
171*8ccd4a63SDavid du Colombier 		panic("pipestat");
172*8ccd4a63SDavid du Colombier 	}
173*8ccd4a63SDavid du Colombier 	n = convD2M(&dir, db, n);
174*8ccd4a63SDavid du Colombier 	if(n < BIT16SZ)
175*8ccd4a63SDavid du Colombier 		error(Eshortstat);
176*8ccd4a63SDavid du Colombier 	return n;
177*8ccd4a63SDavid du Colombier }
178*8ccd4a63SDavid du Colombier 
179*8ccd4a63SDavid du Colombier /*
180*8ccd4a63SDavid du Colombier  *  if the stream doesn't exist, create it
181*8ccd4a63SDavid du Colombier  */
182*8ccd4a63SDavid du Colombier static Chan*
pipeopen(Chan * c,int omode)183*8ccd4a63SDavid du Colombier pipeopen(Chan *c, int omode)
184*8ccd4a63SDavid du Colombier {
185*8ccd4a63SDavid du Colombier 	Pipe *p;
186*8ccd4a63SDavid du Colombier 
187*8ccd4a63SDavid du Colombier 	if(c->qid.type & QTDIR){
188*8ccd4a63SDavid du Colombier 		if(omode != OREAD)
189*8ccd4a63SDavid du Colombier 			error(Ebadarg);
190*8ccd4a63SDavid du Colombier 		c->mode = omode;
191*8ccd4a63SDavid du Colombier 		c->flag |= COPEN;
192*8ccd4a63SDavid du Colombier 		c->offset = 0;
193*8ccd4a63SDavid du Colombier 		return c;
194*8ccd4a63SDavid du Colombier 	}
195*8ccd4a63SDavid du Colombier 
196*8ccd4a63SDavid du Colombier 	p = c->aux;
197*8ccd4a63SDavid du Colombier 	qlock(&p->lk);
198*8ccd4a63SDavid du Colombier 	switch(NETTYPE(c->qid.path)){
199*8ccd4a63SDavid du Colombier 	case Qdata0:
200*8ccd4a63SDavid du Colombier 		p->qref[0]++;
201*8ccd4a63SDavid du Colombier 		break;
202*8ccd4a63SDavid du Colombier 	case Qdata1:
203*8ccd4a63SDavid du Colombier 		p->qref[1]++;
204*8ccd4a63SDavid du Colombier 		break;
205*8ccd4a63SDavid du Colombier 	}
206*8ccd4a63SDavid du Colombier 	qunlock(&p->lk);
207*8ccd4a63SDavid du Colombier 
208*8ccd4a63SDavid du Colombier 	c->mode = openmode(omode);
209*8ccd4a63SDavid du Colombier 	c->flag |= COPEN;
210*8ccd4a63SDavid du Colombier 	c->offset = 0;
211*8ccd4a63SDavid du Colombier 	c->iounit = qiomaxatomic;
212*8ccd4a63SDavid du Colombier 	return c;
213*8ccd4a63SDavid du Colombier }
214*8ccd4a63SDavid du Colombier 
215*8ccd4a63SDavid du Colombier static void
pipeclose(Chan * c)216*8ccd4a63SDavid du Colombier pipeclose(Chan *c)
217*8ccd4a63SDavid du Colombier {
218*8ccd4a63SDavid du Colombier 	Pipe *p;
219*8ccd4a63SDavid du Colombier 
220*8ccd4a63SDavid du Colombier 	p = c->aux;
221*8ccd4a63SDavid du Colombier 	qlock(&p->lk);
222*8ccd4a63SDavid du Colombier 
223*8ccd4a63SDavid du Colombier 	if(c->flag & COPEN){
224*8ccd4a63SDavid du Colombier 		/*
225*8ccd4a63SDavid du Colombier 		 *  closing either side hangs up the stream
226*8ccd4a63SDavid du Colombier 		 */
227*8ccd4a63SDavid du Colombier 		switch(NETTYPE(c->qid.path)){
228*8ccd4a63SDavid du Colombier 		case Qdata0:
229*8ccd4a63SDavid du Colombier 			p->qref[0]--;
230*8ccd4a63SDavid du Colombier 			if(p->qref[0] == 0){
231*8ccd4a63SDavid du Colombier 				qhangup(p->q[1], 0);
232*8ccd4a63SDavid du Colombier 				qclose(p->q[0]);
233*8ccd4a63SDavid du Colombier 			}
234*8ccd4a63SDavid du Colombier 			break;
235*8ccd4a63SDavid du Colombier 		case Qdata1:
236*8ccd4a63SDavid du Colombier 			p->qref[1]--;
237*8ccd4a63SDavid du Colombier 			if(p->qref[1] == 0){
238*8ccd4a63SDavid du Colombier 				qhangup(p->q[0], 0);
239*8ccd4a63SDavid du Colombier 				qclose(p->q[1]);
240*8ccd4a63SDavid du Colombier 			}
241*8ccd4a63SDavid du Colombier 			break;
242*8ccd4a63SDavid du Colombier 		}
243*8ccd4a63SDavid du Colombier 	}
244*8ccd4a63SDavid du Colombier 
245*8ccd4a63SDavid du Colombier 
246*8ccd4a63SDavid du Colombier 	/*
247*8ccd4a63SDavid du Colombier 	 *  if both sides are closed, they are reusable
248*8ccd4a63SDavid du Colombier 	 */
249*8ccd4a63SDavid du Colombier 	if(p->qref[0] == 0 && p->qref[1] == 0){
250*8ccd4a63SDavid du Colombier 		qreopen(p->q[0]);
251*8ccd4a63SDavid du Colombier 		qreopen(p->q[1]);
252*8ccd4a63SDavid du Colombier 	}
253*8ccd4a63SDavid du Colombier 
254*8ccd4a63SDavid du Colombier 	/*
255*8ccd4a63SDavid du Colombier 	 *  free the structure on last close
256*8ccd4a63SDavid du Colombier 	 */
257*8ccd4a63SDavid du Colombier 	p->ref--;
258*8ccd4a63SDavid du Colombier 	if(p->ref == 0){
259*8ccd4a63SDavid du Colombier 		qunlock(&p->lk);
260*8ccd4a63SDavid du Colombier 		free(p->q[0]);
261*8ccd4a63SDavid du Colombier 		free(p->q[1]);
262*8ccd4a63SDavid du Colombier 		free(p);
263*8ccd4a63SDavid du Colombier 	} else
264*8ccd4a63SDavid du Colombier 		qunlock(&p->lk);
265*8ccd4a63SDavid du Colombier }
266*8ccd4a63SDavid du Colombier 
267*8ccd4a63SDavid du Colombier static long
piperead(Chan * c,void * va,long n,vlong offset)268*8ccd4a63SDavid du Colombier piperead(Chan *c, void *va, long n, vlong offset)
269*8ccd4a63SDavid du Colombier {
270*8ccd4a63SDavid du Colombier 	Pipe *p;
271*8ccd4a63SDavid du Colombier 
272*8ccd4a63SDavid du Colombier 	USED(offset);
273*8ccd4a63SDavid du Colombier 
274*8ccd4a63SDavid du Colombier 	p = c->aux;
275*8ccd4a63SDavid du Colombier 
276*8ccd4a63SDavid du Colombier 	switch(NETTYPE(c->qid.path)){
277*8ccd4a63SDavid du Colombier 	case Qdir:
278*8ccd4a63SDavid du Colombier 		return devdirread(c, va, n, pipedir, NPIPEDIR, pipegen);
279*8ccd4a63SDavid du Colombier 	case Qdata0:
280*8ccd4a63SDavid du Colombier 		return qread(p->q[0], va, n);
281*8ccd4a63SDavid du Colombier 	case Qdata1:
282*8ccd4a63SDavid du Colombier 		return qread(p->q[1], va, n);
283*8ccd4a63SDavid du Colombier 	default:
284*8ccd4a63SDavid du Colombier 		panic("piperead");
285*8ccd4a63SDavid du Colombier 	}
286*8ccd4a63SDavid du Colombier 	return -1;	/* not reached */
287*8ccd4a63SDavid du Colombier }
288*8ccd4a63SDavid du Colombier 
289*8ccd4a63SDavid du Colombier static Block*
pipebread(Chan * c,long n,ulong offset)290*8ccd4a63SDavid du Colombier pipebread(Chan *c, long n, ulong offset)
291*8ccd4a63SDavid du Colombier {
292*8ccd4a63SDavid du Colombier 	Pipe *p;
293*8ccd4a63SDavid du Colombier 
294*8ccd4a63SDavid du Colombier 	p = c->aux;
295*8ccd4a63SDavid du Colombier 
296*8ccd4a63SDavid du Colombier 	switch(NETTYPE(c->qid.path)){
297*8ccd4a63SDavid du Colombier 	case Qdata0:
298*8ccd4a63SDavid du Colombier 		return qbread(p->q[0], n);
299*8ccd4a63SDavid du Colombier 	case Qdata1:
300*8ccd4a63SDavid du Colombier 		return qbread(p->q[1], n);
301*8ccd4a63SDavid du Colombier 	}
302*8ccd4a63SDavid du Colombier 
303*8ccd4a63SDavid du Colombier 	return devbread(c, n, offset);
304*8ccd4a63SDavid du Colombier }
305*8ccd4a63SDavid du Colombier 
306*8ccd4a63SDavid du Colombier /*
307*8ccd4a63SDavid du Colombier  *  a write to a closed pipe causes a note to be sent to
308*8ccd4a63SDavid du Colombier  *  the process.
309*8ccd4a63SDavid du Colombier  */
310*8ccd4a63SDavid du Colombier static long
pipewrite(Chan * c,void * va,long n,vlong offset)311*8ccd4a63SDavid du Colombier pipewrite(Chan *c, void *va, long n, vlong offset)
312*8ccd4a63SDavid du Colombier {
313*8ccd4a63SDavid du Colombier 	Pipe *p;
314*8ccd4a63SDavid du Colombier 
315*8ccd4a63SDavid du Colombier 	USED(offset);
316*8ccd4a63SDavid du Colombier 	if(!islo())
317*8ccd4a63SDavid du Colombier 		print("pipewrite hi %lux\n", getcallerpc(&c));
318*8ccd4a63SDavid du Colombier 
319*8ccd4a63SDavid du Colombier 	if(waserror()) {
320*8ccd4a63SDavid du Colombier 		/* avoid notes when pipe is a mounted queue */
321*8ccd4a63SDavid du Colombier 		if((c->flag & CMSG) == 0)
322*8ccd4a63SDavid du Colombier 			postnote(up, 1, "sys: write on closed pipe", NUser);
323*8ccd4a63SDavid du Colombier 		nexterror();
324*8ccd4a63SDavid du Colombier 	}
325*8ccd4a63SDavid du Colombier 
326*8ccd4a63SDavid du Colombier 	p = c->aux;
327*8ccd4a63SDavid du Colombier 
328*8ccd4a63SDavid du Colombier 	switch(NETTYPE(c->qid.path)){
329*8ccd4a63SDavid du Colombier 	case Qdata0:
330*8ccd4a63SDavid du Colombier 		n = qwrite(p->q[1], va, n);
331*8ccd4a63SDavid du Colombier 		break;
332*8ccd4a63SDavid du Colombier 
333*8ccd4a63SDavid du Colombier 	case Qdata1:
334*8ccd4a63SDavid du Colombier 		n = qwrite(p->q[0], va, n);
335*8ccd4a63SDavid du Colombier 		break;
336*8ccd4a63SDavid du Colombier 
337*8ccd4a63SDavid du Colombier 	default:
338*8ccd4a63SDavid du Colombier 		panic("pipewrite");
339*8ccd4a63SDavid du Colombier 	}
340*8ccd4a63SDavid du Colombier 
341*8ccd4a63SDavid du Colombier 	poperror();
342*8ccd4a63SDavid du Colombier 	return n;
343*8ccd4a63SDavid du Colombier }
344*8ccd4a63SDavid du Colombier 
345*8ccd4a63SDavid du Colombier static long
pipebwrite(Chan * c,Block * bp,ulong offset)346*8ccd4a63SDavid du Colombier pipebwrite(Chan *c, Block *bp, ulong offset)
347*8ccd4a63SDavid du Colombier {
348*8ccd4a63SDavid du Colombier 	long n;
349*8ccd4a63SDavid du Colombier 	Pipe *p;
350*8ccd4a63SDavid du Colombier 
351*8ccd4a63SDavid du Colombier 	USED(offset);
352*8ccd4a63SDavid du Colombier 
353*8ccd4a63SDavid du Colombier 	if(waserror()) {
354*8ccd4a63SDavid du Colombier 		/* avoid notes when pipe is a mounted queue */
355*8ccd4a63SDavid du Colombier 		if((c->flag & CMSG) == 0)
356*8ccd4a63SDavid du Colombier 			postnote(up, 1, "sys: write on closed pipe", NUser);
357*8ccd4a63SDavid du Colombier 		nexterror();
358*8ccd4a63SDavid du Colombier 	}
359*8ccd4a63SDavid du Colombier 
360*8ccd4a63SDavid du Colombier 	p = c->aux;
361*8ccd4a63SDavid du Colombier 	switch(NETTYPE(c->qid.path)){
362*8ccd4a63SDavid du Colombier 	case Qdata0:
363*8ccd4a63SDavid du Colombier 		n = qbwrite(p->q[1], bp);
364*8ccd4a63SDavid du Colombier 		break;
365*8ccd4a63SDavid du Colombier 
366*8ccd4a63SDavid du Colombier 	case Qdata1:
367*8ccd4a63SDavid du Colombier 		n = qbwrite(p->q[0], bp);
368*8ccd4a63SDavid du Colombier 		break;
369*8ccd4a63SDavid du Colombier 
370*8ccd4a63SDavid du Colombier 	default:
371*8ccd4a63SDavid du Colombier 		n = 0;
372*8ccd4a63SDavid du Colombier 		panic("pipebwrite");
373*8ccd4a63SDavid du Colombier 	}
374*8ccd4a63SDavid du Colombier 
375*8ccd4a63SDavid du Colombier 	poperror();
376*8ccd4a63SDavid du Colombier 	return n;
377*8ccd4a63SDavid du Colombier }
378*8ccd4a63SDavid du Colombier 
379*8ccd4a63SDavid du Colombier Dev pipedevtab = {
380*8ccd4a63SDavid du Colombier 	'|',
381*8ccd4a63SDavid du Colombier 	"pipe",
382*8ccd4a63SDavid du Colombier 
383*8ccd4a63SDavid du Colombier 	devreset,
384*8ccd4a63SDavid du Colombier 	pipeinit,
385*8ccd4a63SDavid du Colombier 	devshutdown,
386*8ccd4a63SDavid du Colombier 	pipeattach,
387*8ccd4a63SDavid du Colombier 	pipewalk,
388*8ccd4a63SDavid du Colombier 	pipestat,
389*8ccd4a63SDavid du Colombier 	pipeopen,
390*8ccd4a63SDavid du Colombier 	devcreate,
391*8ccd4a63SDavid du Colombier 	pipeclose,
392*8ccd4a63SDavid du Colombier 	piperead,
393*8ccd4a63SDavid du Colombier 	pipebread,
394*8ccd4a63SDavid du Colombier 	pipewrite,
395*8ccd4a63SDavid du Colombier 	pipebwrite,
396*8ccd4a63SDavid du Colombier 	devremove,
397*8ccd4a63SDavid du Colombier 	devwstat,
398*8ccd4a63SDavid du Colombier };
399