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