static int pipetapfd(struct chan *chan, struct fd_tap *tap, int cmd) { int ret; Pipe *p; int which = 1; uint64_t kludge; p = chan->aux; kludge = (uint64_t)p; #define DEVPIPE_LEGAL_DATA_TAPS (FDTAP_FILT_READABLE | FDTAP_FILT_WRITABLE | \ FDTAP_FILT_HANGUP | FDTAP_FILT_ERROR) switch (NETTYPE(chan->qid.path)) { case Qdata0: which = 0; /* fall through */ case Qdata1: kludge |= which; if (tap->filter & ~DEVPIPE_LEGAL_DATA_TAPS) { set_errno(ENOSYS); set_errstr("Unsupported #%s data tap %p, must be %p", devname(), tap->filter, DEVPIPE_LEGAL_DATA_TAPS); return -1; } spin_lock(&p->tap_lock); switch (cmd) { case (FDTAP_CMD_ADD): if (SLIST_EMPTY(&p->data_taps[which])) qio_set_wake_cb(p->q[which], pipe_wake_cb, (void *)kludge); SLIST_INSERT_HEAD(&p->data_taps[which], tap, link); ret = 0; break; case (FDTAP_CMD_REM): SLIST_REMOVE(&p->data_taps[which], tap, fd_tap, link); if (SLIST_EMPTY(&p->data_taps[which])) qio_set_wake_cb(p->q[which], 0, (void *)kludge); ret = 0; break; default: set_errno(ENOSYS); set_errstr("Unsupported #%s data tap command %p", devname(), cmd); ret = -1; } spin_unlock(&p->tap_lock); return ret; default: set_errno(ENOSYS); set_errstr("Can't tap #%s file type %d", devname(), NETTYPE(chan->qid.path)); return -1; } }
long netifread(struct netif *nif, struct chan *c, void *a, long n, uint32_t offset) { int i, j; struct netfile *f; char *p; if (c->qid.type & QTDIR) return devdirread(c, a, n, (struct dirtab *)nif, 0, netifgen); switch (NETTYPE(c->qid.path)) { case Ndataqid: f = nif->f[NETID(c->qid.path)]; return qread(f->in, a, n); case Nctlqid: return readnum(offset, a, n, NETID(c->qid.path), NUMSIZE); case Nstatqid: p = kzmalloc(READSTR, 0); if (p == NULL) return 0; j = snprintf(p, READSTR, "in: %d\n", nif->inpackets); j += snprintf(p + j, READSTR - j, "link: %d\n", nif->link); j += snprintf(p + j, READSTR - j, "out: %d\n", nif->outpackets); j += snprintf(p + j, READSTR - j, "crc errs: %d\n", nif->crcs); j += snprintf(p + j, READSTR - j, "overflows: %d\n", nif->overflows); j += snprintf(p + j, READSTR - j, "soft overflows: %d\n", nif->soverflows); j += snprintf(p + j, READSTR - j, "framing errs: %d\n", nif->frames); j += snprintf(p + j, READSTR - j, "buffer errs: %d\n", nif->buffs); j += snprintf(p + j, READSTR - j, "output errs: %d\n", nif->oerrs); j += snprintf(p + j, READSTR - j, "prom: %d\n", nif->prom); j += snprintf(p + j, READSTR - j, "mbps: %d\n", nif->mbps); j += snprintf(p + j, READSTR - j, "addr: "); for (i = 0; i < nif->alen; i++) j += snprintf(p + j, READSTR - j, "%02.2x", nif->addr[i]); snprintf(p + j, READSTR - j, "\n"); n = readstr(offset, a, n, p); kfree(p); return n; case Naddrqid: p = kzmalloc(READSTR, 0); if (p == NULL) return 0; j = 0; for (i = 0; i < nif->alen; i++) j += snprintf(p + j, READSTR - j, "%02.2x", nif->addr[i]); n = readstr(offset, a, n, p); kfree(p); return n; case Ntypeqid: f = nif->f[NETID(c->qid.path)]; return readnum(offset, a, n, f->type, NUMSIZE); case Nifstatqid: return 0; } error(Ebadarg); return -1; /* not reached */ }
static long pipebwrite(struct chan *c, struct block *bp, uint32_t junk) { long n; Pipe *p; //Prog *r; p = c->aux; switch (NETTYPE(c->qid.path)) { case Qdata0: if (c->flag & O_NONBLOCK) n = qbwrite_nonblock(p->q[1], bp); else n = qbwrite(p->q[1], bp); break; case Qdata1: if (c->flag & O_NONBLOCK) n = qbwrite_nonblock(p->q[0], bp); else n = qbwrite(p->q[0], bp); break; default: n = 0; panic("pipebwrite"); } return n; }
static long piperead(struct chan *c, void *va, long n, int64_t ignored) { Pipe *p; p = c->aux; switch (NETTYPE(c->qid.path)) { case Qdir: return devdirread(c, va, n, p->pipedir, ARRAY_SIZE(pipedir), pipegen); case Qdata0: if (c->flag & O_NONBLOCK) return qread_nonblock(p->q[0], va, n); else return qread(p->q[0], va, n); case Qdata1: if (c->flag & O_NONBLOCK) return qread_nonblock(p->q[1], va, n); else return qread(p->q[1], va, n); default: panic("piperead"); } return -1; /* not reached */ }
/* * A write to a closed pipe causes an EPIPE error to be thrown. */ static long pipewrite(struct chan *c, void *va, long n, int64_t ignored) { Pipe *p; //Prog *r; p = c->aux; switch (NETTYPE(c->qid.path)) { case Qdata0: if (c->flag & O_NONBLOCK) n = qwrite_nonblock(p->q[1], va, n); else n = qwrite(p->q[1], va, n); break; case Qdata1: if (c->flag & O_NONBLOCK) n = qwrite_nonblock(p->q[0], va, n); else n = qwrite(p->q[0], va, n); break; default: panic("pipewrite"); } return n; }
static struct walkqid *pipewalk(struct chan *c, struct chan *nc, char **name, int nname) { struct walkqid *wq; Pipe *p; p = c->aux; wq = devwalk(c, nc, name, nname, p->pipedir, ARRAY_SIZE(pipedir), pipegen); if (wq != NULL && wq->clone != NULL && wq->clone != c) { qlock(&p->qlock); kref_get(&p->ref, 1); if (c->flag & COPEN) { switch (NETTYPE(c->qid.path)) { case Qdata0: p->qref[0]++; break; case Qdata1: p->qref[1]++; break; } } qunlock(&p->qlock); } return wq; }
static int pipestat(struct chan *c, uint8_t * db, int n) { Pipe *p; struct dir dir; struct dirtab *tab; int perm; p = c->aux; tab = p->pipedir; switch (NETTYPE(c->qid.path)) { case Qdir: devdir(c, c->qid, ".", 0, eve, DMDIR | 0555, &dir); break; case Qdata0: perm = tab[1].perm; perm |= qreadable(p->q[0]) ? DMREADABLE : 0; perm |= qwritable(p->q[0]) ? DMWRITABLE : 0; devdir(c, c->qid, tab[1].name, qlen(p->q[0]), eve, perm, &dir); break; case Qdata1: perm = tab[2].perm; perm |= qreadable(p->q[1]) ? DMREADABLE : 0; perm |= qwritable(p->q[1]) ? DMWRITABLE : 0; devdir(c, c->qid, tab[2].name, qlen(p->q[1]), eve, perm, &dir); break; default: panic("pipestat"); } n = convD2M(&dir, db, n); if (n < BIT16SZ) error(ENODATA, ERROR_FIXME); return n; }
static int uartstat(Chan *c, uchar *dp, int n) { if(NETTYPE(c->qid.path) == Ndataqid) setlength(NETID(c->qid.path)); return devstat(c, dp, n, uartdir, ndir, devgen); }
static long uartwrite(Chan *c, void *buf, long n, vlong offset) { Uart *p; char cmd[32]; USED(offset); if(c->qid.type & QTDIR) error(Eperm); p = uart[NETID(c->qid.path)]; switch(NETTYPE(c->qid.path)){ case Ndataqid: return qwrite(p->oq, buf, n); case Nctlqid: if(n >= sizeof(cmd)) n = sizeof(cmd)-1; memmove(cmd, buf, n); cmd[n] = 0; uartctl(p, cmd); return n; } }
Block* netifbread(Netif *nif, Chan *c, long n, vlong offset) { Netfile *f; Block *bp; if((c->qid.type & QTDIR) || NETTYPE(c->qid.path) != Ndataqid) return devbread(c, n, offset); f = nif->f[NETID(c->qid.path)]; if(f->fat){ /* * Frame at a time (fat) allows us to provide * non-blocking performance with blocking semantics * for consumers that know ahead of time data is * contained within a single frame. Once empty, we * get in line with other blocking reads and wait our * turn. */ for(;;){ if(bp = qget(f->iq)) return bp; if(waserror()) return nil; qsleep(f->iq); poperror(); } } return qbread(f->iq, n); }
static long eiawrite(Chan *c, void *buf, long n, vlong offset) { ssize_t cnt; char cmd[Maxctl]; int port = NETID(c->qid.path); USED(offset); if(c->qid.type & QTDIR) error(Eperm); switch(NETTYPE(c->qid.path)) { case Ndataqid: osenter(); cnt = write(eia[port].fd, buf, n); osleave(); if(cnt == -1) oserror(); return cnt; case Nctlqid: if(n >= (long)sizeof(cmd)) n = sizeof(cmd)-1; memmove(cmd, buf, n); cmd[n] = 0; wrctl(port, cmd); return n; } return 0; }
static long eiaread(Chan *c, void *buf, long n, vlong offset) { ssize_t cnt; int port = NETID(c->qid.path); if(c->qid.type & QTDIR) return devdirread(c, buf, n, eiadir, ndir, devgen); switch(NETTYPE(c->qid.path)) { case Ndataqid: osenter(); cnt = read(eia[port].fd, buf, n); osleave(); if(cnt == -1) oserror(); return cnt; case Nctlqid: return readnum(offset, buf, n, port, NUMSIZE); case Nstatqid: return rdstat(port, buf, n, offset); } return 0; }
static int pipewstat(struct chan *c, uint8_t *dp, int n) { ERRSTACK(2); struct dir *d; Pipe *p; int d1; if (c->qid.type & QTDIR) error(EPERM, ERROR_FIXME); p = c->aux; if (strcmp(current->user, p->user) != 0) error(EPERM, ERROR_FIXME); d = kzmalloc(sizeof(*d) + n, 0); if (waserror()) { kfree(d); nexterror(); } n = convM2D(dp, n, d, (char *)&d[1]); if (n == 0) error(ENODATA, ERROR_FIXME); d1 = NETTYPE(c->qid.path) == Qdata1; if (!emptystr(d->name)) { validwstatname(d->name); if (strlen(d->name) >= KNAMELEN) error(ENAMETOOLONG, ERROR_FIXME); if (strncmp(p->pipedir[1 + !d1].name, d->name, KNAMELEN) == 0) error(EEXIST, ERROR_FIXME); strncpy(p->pipedir[1 + d1].name, d->name, KNAMELEN); } if (d->mode != ~0UL) p->pipedir[d1 + 1].perm = d->mode & 0777; poperror(); kfree(d); return n; }
static long eiaread(Chan *c, void *buf, long n, vlong offset) { DWORD cnt; int port = NETID(c->qid.path); BOOL good; if(c->qid.type & QTDIR) return devdirread(c, buf, n, eiadir, ndir, devgen); switch(NETTYPE(c->qid.path)) { case Ndataqid: cnt = 0; // if ReadFile timeouts and cnt==0 then just re-read // this will give osleave() a chance to detect an // interruption (i.e. killprog) while(cnt==0) { osenter(); good = ReadFile(eia[port].comfh, buf, n, &cnt, NULL); SleepEx(0,FALSE); //allow another thread access to port osleave(); if(!good) oserror(); } return cnt; case Nctlqid: return readnum(offset, buf, n, eia[port].id, NUMSIZE); case Nstatqid: return rdstat(port, buf, n, offset); } return 0; }
static int pipegen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp) { int id, len; Qid qid; Pipe *p; USED(name); if(i == DEVDOTDOT){ devdir(c, c->qid, "#|", 0, eve, 0555, dp); return 1; } i++; /* skip . */ if(tab==0 || i>=ntab) return -1; tab += i; p = c->aux; switch(NETTYPE(tab->qid.path)){ case Qdata0: len = qlen(p->q[0]); break; case Qdata1: len = qlen(p->q[1]); break; default: len = tab->length; break; } id = NETID(c->qid.path); qid.path = NETQID(id, tab->qid.path); qid.vers = 0; qid.type = QTFILE; devdir(c, qid, tab->name, len, eve, tab->perm, dp); return 1; }
static long pipebwrite(Chan *c, Block *bp, ulong) { long n; Pipe *p; if(waserror()) { /* avoid notes when pipe is a mounted queue */ if((c->flag & CMSG) == 0) postnote(up, 1, "sys: write on closed pipe", NUser); nexterror(); } p = c->aux; switch(NETTYPE(c->qid.path)){ case Qdata0: n = qbwrite(p->q[1], bp); break; case Qdata1: n = qbwrite(p->q[0], bp); break; default: n = 0; panic("pipebwrite"); } poperror(); return n; }
/* * if the stream doesn't exist, create it */ static Chan* pipeopen(Chan *c, int omode) { Pipe *p; if(c->qid.type & QTDIR){ if(omode != OREAD) error(Ebadarg); c->mode = omode; c->flag |= COPEN; c->offset = 0; return c; } p = c->aux; qlock(p); switch(NETTYPE(c->qid.path)){ case Qdata0: p->qref[0]++; break; case Qdata1: p->qref[1]++; break; } qunlock(p); c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; c->iounit = qiomaxatomic; return c; }
/* * a write to a closed pipe causes a note to be sent to * the process. */ static long pipewrite(Chan *c, void *va, long n, vlong) { Pipe *p; if(!islo()) print("pipewrite hi %#p\n", getcallerpc(&c)); if(waserror()) { /* avoid notes when pipe is a mounted queue */ if((c->flag & CMSG) == 0) postnote(up, 1, "sys: write on closed pipe", NUser); nexterror(); } p = c->aux; switch(NETTYPE(c->qid.path)){ case Qdata0: n = qwrite(p->q[1], va, n); break; case Qdata1: n = qwrite(p->q[0], va, n); break; default: panic("pipewrite"); } poperror(); return n; }
static int pipestat(Chan *c, uchar *db, int n) { Pipe *p; Dir dir; p = c->aux; switch(NETTYPE(c->qid.path)){ case Qdir: devdir(c, c->qid, ".", 0, eve, DMDIR|0555, &dir); break; case Qdata0: devdir(c, c->qid, "data", qlen(p->q[0]), eve, p->perm, &dir); break; case Qdata1: devdir(c, c->qid, "data1", qlen(p->q[1]), eve, p->perm, &dir); break; default: panic("pipestat"); } n = convD2M(&dir, db, n); if(n < BIT16SZ) error(Eshortstat); return n; }
static int pipewstat(Chan* c, uchar* db, int n) { int m; Dir *dir; Pipe *p; p = c->aux; if(strcmp(up->user, eve) != 0) error(Eperm); if(NETTYPE(c->qid.path) == Qdir) error(Eisdir); dir = smalloc(sizeof(Dir)+n); if(waserror()){ free(dir); nexterror(); } m = convM2D(db, n, &dir[0], (char*)&dir[1]); if(m == 0) error(Eshortstat); if(!emptystr(dir[0].uid)) error("can't change owner"); if(dir[0].mode != ~0UL) p->perm = dir[0].mode; poperror(); free(dir); return m; }
static Walkqid* pipewalk(Chan *c, Chan *nc, char **name, int nname) { Walkqid *wq; Pipe *p; wq = devwalk(c, nc, name, nname, pipedir, NPIPEDIR, pipegen); if(wq != nil && wq->clone != nil && wq->clone != c){ p = c->aux; qlock(p); p->ref++; if(c->flag & COPEN){ print("channel open in pipewalk\n"); switch(NETTYPE(c->qid.path)){ case Qdata0: p->qref[0]++; break; case Qdata1: p->qref[1]++; break; } } qunlock(p); } return wq; }
static int pipewstat(Chan *c, uchar *dp, int n) { Dir *d; Pipe *p; int d1; if (c->qid.type&QTDIR) error(Eperm); p = c->aux; if(strcmp(up->env->user, p->user) != 0) error(Eperm); d = smalloc(sizeof(*d)+n); if(waserror()){ free(d); nexterror(); } n = convM2D(dp, n, d, (char*)&d[1]); if(n == 0) error(Eshortstat); d1 = NETTYPE(c->qid.path) == Qdata1; if(!emptystr(d->name)){ validwstatname(d->name); if(strlen(d->name) >= KNAMELEN) error(Efilename); if(strcmp(p->pipedir[1+!d1].name, d->name) == 0) error(Eexist); kstrcpy(p->pipedir[1+d1].name, d->name, KNAMELEN); } if(d->mode != ~0U) p->pipedir[d1 + 1].perm = d->mode & 0777; poperror(); free(d); return n; }
static Walkqid* pipewalk(Chan *c, Chan *nc, char **name, int nname) { Walkqid *wq; Pipe *p; p = c->aux; wq = devwalk(c, nc, name, nname, p->pipedir, nelem(pipedir), pipegen); if(wq != nil && wq->clone != nil && wq->clone != c){ qlock(&p->l); p->ref++; if(c->flag & COPEN){ switch(NETTYPE(c->qid.path)){ case Qdata0: p->qref[0]++; break; case Qdata1: p->qref[1]++; break; } } qunlock(&p->l); } return wq; }
static void uartclose(Chan *c) { Uart *p; if(c->qid.type & QTDIR) return; if((c->flag & COPEN) == 0) return; switch(NETTYPE(c->qid.path)){ case Ndataqid: case Nctlqid: p = uart[NETID(c->qid.path)]; qlock(p); if(--(p->opens) == 0){ qclose(p->iq); ilock(&p->rlock); p->ir = p->iw = p->istage; iunlock(&p->rlock); /* */ qhangup(p->oq, nil); if(!waserror()){ uartdrainoutput(p); poperror(); } qclose(p->oq); uartdisable(p); p->dcd = p->dsr = p->dohup = 0; } qunlock(p); break; } }
Block* netifbread(Netif *nif, Chan *c, long n, ulong offset) { if((c->qid.type & QTDIR) || NETTYPE(c->qid.path) != Ndataqid) return devbread(c, n, offset); return qbread(nif->f[NETID(c->qid.path)]->in, n); }
struct block *netifbread(struct ether *nif, struct chan *c, long n, uint32_t offset) { if ((c->qid.type & QTDIR) || NETTYPE(c->qid.path) != Ndataqid) return devbread(c, n, offset); return qbread(nif->f[NETID(c->qid.path)]->in, n); }
Block* netifbread(Netif *nif, Chan *c, int32_t n, int64_t offset) { if((c->qid.type & QTDIR) || NETTYPE(c->qid.path) != Ndataqid) return devbread(c, n, offset); return qbread(nif->f[NETID(c->qid.path)]->iq, n); }
Chan* netifopen(Netif *nif, Chan *c, int omode) { Proc *up = externup(); int id; Netfile *f; id = 0; if(c->qid.type & QTDIR){ if(omode != OREAD) error(Eperm); } else { switch(NETTYPE(c->qid.path)){ case Ndataqid: case Nctlqid: id = NETID(c->qid.path); openfile(nif, id); break; case Ncloneqid: id = openfile(nif, -1); c->qid.path = NETQID(id, Nctlqid); break; default: if(omode != OREAD) error(Ebadarg); } switch(NETTYPE(c->qid.path)){ case Ndataqid: case Nctlqid: f = nif->f[id]; if(netown(f, up->user, omode&7) < 0){ netifclose(nif, c); error(Eperm); } break; } } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; c->iounit = qiomaxatomic; return c; }
static int eiawstat(Chan *c, uchar *dp, int n) { Dir d; int i; if(!iseve()) error(Eperm); if(c->qid.type & QTDIR) error(Eperm); if(NETTYPE(c->qid.path) == Nstatqid) error(Eperm); n = convM2D(dp, n, &d, nil); i = Nqid*NETID(c->qid.path)+NETTYPE(c->qid.path)-Ndataqid; if(d.mode != ~0UL) eiadir[i+1].perm = d.mode&0666; return n; }
void netifclose(Netif *nif, Chan *c) { Netfile *f; int t; Netaddr *ap; if((c->flag & COPEN) == 0) return; t = NETTYPE(c->qid.path); if(t != Ndataqid && t != Nctlqid) return; f = nif->f[NETID(c->qid.path)]; qlock(&f->q); if(--(f->inuse) == 0){ if(f->prom){ qlock(&nif->q); if(--(nif->prom) == 0 && nif->promiscuous != nil) nif->promiscuous(nif->arg, 0); qunlock(&nif->q); f->prom = 0; } if(f->scan){ qlock(&nif->q); if(--(nif->_scan) == 0 && nif->scanbs != nil) nif->scanbs(nif->arg, 0); qunlock(&nif->q); f->prom = 0; f->scan = 0; } if(f->nmaddr){ qlock(&nif->q); t = 0; for(ap = nif->maddr; ap; ap = ap->next){ if(f->maddr[t/8] & (1<<(t%8))) netmulti(nif, f, ap->addr, 0); } qunlock(&nif->q); f->nmaddr = 0; } if(f->type < 0){ qlock(&nif->q); --(nif->all); qunlock(&nif->q); } f->owner[0] = 0; f->type = 0; f->bridge = 0; f->headersonly = 0; qclose(f->iq); } qunlock(&f->q); }