static void getaddr(char *path, uint8_t *ea) { Proc *up = externup(); char buf[6*2]; int n; Chan *c; snprint(up->genbuf, sizeof up->genbuf, "%s/addr", path); c = namec(up->genbuf, Aopen, OREAD, 0); if(waserror()) { cclose(c); nexterror(); } n = c->dev->read(c, buf, sizeof buf, 0); if(n != sizeof buf) error("getaddr"); if(parseether(ea, buf) < 0) error("parseether failure"); poperror(); cclose(c); }
static int32_t srvwrite(Chan *c, void *va, int32_t n, int64_t mm) { Proc *up = externup(); Srv *sp; Chan *c1; int fd; char buf[32]; if(n >= sizeof buf) error(Egreg); memmove(buf, va, n); /* so we can NUL-terminate */ buf[n] = 0; fd = strtoul(buf, 0, 0); c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */ qlock(&srvlk); if(waserror()) { qunlock(&srvlk); cclose(c1); nexterror(); } if(c1->flag & (CCEXEC|CRCLOSE)) error("posted fd has remove-on-close or close-on-exec"); if(c1->qid.type & QTAUTH) error("cannot post auth file in srv"); sp = srvlookup(nil, c->qid.path); if(sp == 0) error(Enonexist); if(sp->chan) error(Ebadusefd); sp->chan = c1; qunlock(&srvlk); poperror(); return n; }
void init0(void) { int i; char buf[2*KNAMELEN]; up->nerrlab = 0; spllo(); /* * These are o.k. because rootinit is null. * Then early kproc's will have a root and dot. */ up->slash = namec("#/", Atodir, 0, 0); pathclose(up->slash->path); up->slash->path = newpath("/"); up->dot = cclone(up->slash); chandevinit(); if(!waserror()){ snprint(buf, sizeof(buf), "%s %s", arch->id, conffile); ksetenv("terminal", buf, 0); ksetenv("cputype", "386", 0); if(cpuserver) ksetenv("service", "cpu", 0); else ksetenv("service", "terminal", 0); for(i = 0; i < nconf; i++){ if(confname[i][0] != '*') ksetenv(confname[i], confval[i], 0); ksetenv(confname[i], confval[i], 1); } poperror(); } kproc("alarm", alarmkproc, 0); touser(sp); }
static int srvwstat(Chan *c, uchar *dp, int n) { Dir *d; SrvFile *sf, *f; sf = c->aux; if(strcmp(up->env->user, sf->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); if(!emptystr(d->name)){ if(sf->dir == nil) error(Eperm); validwstatname(d->name); qlock(&dev.l); for(f = sf->dir; f != nil; f = f->entry) if(strcmp(f->name, d->name) == 0){ qunlock(&dev.l); error(Eexist); } kstrdup(&sf->name, d->name); qunlock(&dev.l); } if(d->mode != ~0UL) sf->perm = d->mode & (DMEXCL|DMAPPEND|0777); if(d->length != (vlong)-1) sf->length = d->length; poperror(); free(d); return n; }
static Chan* srvopen(Chan *c, int omode) { SrvFile *sf; openmode(omode); /* check it */ if(c->qid.type & QTDIR){ if(omode != OREAD) error(Eisdir); c->mode = omode; c->flag |= COPEN; c->offset = 0; return c; } sf = c->aux; qlock(&dev.l); if(waserror()){ qunlock(&dev.l); nexterror(); } devpermcheck(sf->user, sf->perm, omode); if(omode&ORCLOSE && strcmp(sf->user, up->env->user) != 0) error(Eperm); if(sf->perm & DMEXCL && sf->opens != 0) error(Einuse); sf->opens++; if(omode&ORCLOSE) sf->flags |= SORCLOSE; poperror(); qunlock(&dev.l); c->offset = 0; c->flag |= COPEN; c->mode = openmode(omode); return c; }
int pwait(Waitmsg *w) { int cpid; Waitq *wq; if(!canqlock(&up->qwaitr)) error(Einuse); if(waserror()) { qunlock(&up->qwaitr); nexterror(); } lock(&up->exl); if(up->nchild == 0 && up->waitq == 0) { unlock(&up->exl); error(Enochild); } unlock(&up->exl); sleep(&up->waitr, haswaitq, up); lock(&up->exl); wq = up->waitq; up->waitq = wq->next; up->nwait--; unlock(&up->exl); qunlock(&up->qwaitr); poperror(); if(w) memmove(w, &wq->w, sizeof(Waitmsg)); cpid = wq->w.pid; free(wq); return cpid; }
/* * Return a copy of configuration environment as a sequence of strings. * The strings alternate between name and value. A zero length name string * indicates the end of the list */ char * getconfenv(void) { Egrp *eg = &confegrp; Evalue *e; char *p, *q; int i, n; rlock(eg); if(waserror()) { runlock(eg); nexterror(); } /* determine size */ n = 0; for(i=0; i<eg->nent; i++){ e = eg->ent[i]; n += strlen(e->name) + e->len + 2; } p = malloc(n + 1); if(p == nil) error(Enomem); q = p; for(i=0; i<eg->nent; i++){ e = eg->ent[i]; strcpy(q, e->name); q += strlen(q) + 1; memmove(q, e->value, e->len); q[e->len] = 0; /* move up to the first null */ q += strlen(q) + 1; } *q = '\0'; poperror(); runlock(eg); return p; }
static Chan* srvopen(Chan *c, int omode) { Proc *up = externup(); Srv *sp; if(c->qid.type == QTDIR){ if(omode & ORCLOSE) error(Eperm); if(omode != OREAD) error(Eisdir); c->mode = omode; c->flag |= COPEN; c->offset = 0; return c; } qlock(&srvlk); if(waserror()){ qunlock(&srvlk); nexterror(); } sp = srvlookup(nil, c->qid.path); if(sp == 0 || sp->chan == 0) error(Eshutdown); if(omode&OTRUNC) error("srv file already exists"); if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR) error(Eperm); devpermcheck(sp->owner, sp->perm, omode); cclose(c); incref(sp->chan); qunlock(&srvlk); poperror(); return sp->chan; }
long cswrite(Chan *c, void *a, long n, vlong offset) { char *f[4]; char *s, *ns; ulong ip; int nf, port; s = malloc(n+1); if(s == nil) error(Enomem); if(waserror()){ free(s); nexterror(); } memmove(s, a, n); s[n] = 0; nf = getfields(s, f, nelem(f), 0, "!"); if(nf != 3) error("can't translate"); port = lookupport(f[2]); if(port <= 0) error("no translation for port found"); ip = lookuphost(f[1]); if(ip == 0) error("no translation for host found"); ns = smprint("/net/%s/clone %I!%d", f[0], ip, port); if(ns == nil) error(Enomem); free(c->aux); c->aux = ns; poperror(); free(s); return n; }
long syspipe(uint32 *arg) { int fd[2]; Chan *c[2]; Dev *d; static char *datastr[] = {"data", "data1"}; int *ufd; ufd = uvalidaddr(arg[0], 2*BY2WD, 1); evenaddr(arg[0]); d = devtab[devno('|', 0)]; c[0] = namec("#|", Atodir, 0, 0); c[1] = 0; fd[0] = -1; fd[1] = -1; if(waserror()){ cclose(c[0]); if(c[1]) cclose(c[1]); nexterror(); } c[1] = cclone(c[0]); if(walk(&c[0], datastr+0, 1, 1, nil) < 0) error(Egreg); if(walk(&c[1], datastr+1, 1, 1, nil) < 0) error(Egreg); c[0] = d->open(c[0], ORDWR); c[1] = d->open(c[1], ORDWR); if(newfd2(fd, c) < 0) error(Enofd); poperror(); ufd[0] = fd[0]; ufd[1] = fd[1]; return 0; }
int pprint(char *fmt, ...) { int n; Chan *c; Osenv *o; va_list arg; char buf[2*PRINTSIZE]; n = sprint(buf, "%s %ld: ", up->text, up->pid); va_start(arg, fmt); n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); o = up->env; if(o->fgrp == 0) { print("%s", buf); return 0; } c = o->fgrp->fd[2]; if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) { print("%s", buf); return 0; } if(waserror()) { print("%s", buf); return 0; } devtab[c->type]->write(c, buf, n, c->offset); poperror(); lock(c); c->offset += n; unlock(c); return n; }
long ctl(Ether *e, void *p, long n) { Cmdbuf *cb; Cmdtab *ct; Ctlr *ctlr = e->ctlr; Gbereg *reg = ctlr->reg; cb = parsecmd(p, n); if(waserror()) { free(cb); nexterror(); } ct = lookupcmd(cb, ctlmsg, nelem(ctlmsg)); switch(ct->index) { case CMjumbo: if(strcmp(cb->f[1], "on") == 0) { /* incoming packet queue doesn't expect jumbo frames */ error("jumbo disabled"); reg->psc0 = (reg->psc0 & ~PSC0mrumask) | PSC0mru(PSC0mru9022); e->maxmtu = 9022; } else if(strcmp(cb->f[1], "off") == 0) { reg->psc0 = (reg->psc0 & ~PSC0mrumask) | PSC0mru(PSC0mru1522); e->maxmtu = ETHERMAXTU; } else error(Ebadctl); break; default: error(Ebadctl); break; } free(cb); poperror(); return n; }
static int ipwstat(Chan *c, uchar *dp, int n) { Dir *d; Conv *cv; Proto *p; Fs *f; f = ipfs[c->dev]; switch(TYPE(c->qid)) { default: error(Eperm); break; case Qctl: case Qdata: break; } d = smalloc(sizeof(*d)+n); if(waserror()){ free(d); nexterror(); } n = convM2D(dp, n, d, (char*)&d[1]); if(n == 0) error(Eshortstat); p = f->p[PROTO(c->qid)]; cv = p->conv[CONV(c->qid)]; if(!iseve() && strcmp(up->env->user, cv->owner) != 0) error(Eperm); if(!emptystr(d->uid)) kstrdup(&cv->owner, d->uid); if(d->mode != ~0UL) cv->perm = d->mode & 0777; poperror(); free(d); return n; }
static long pipebwrite(Chan *c, Block *bp, ulong junk) { long n; Pipe *p; USED(junk); if(waserror()) { /* avoid exceptions when pipe is a mounted queue */ if((c->flag & CMSG) == 0) { if (up->ptype == Vm_proc) { vproc_t* r = (vproc_t*)up; if (r->kill == nil) { r->kill = "write on closed pipe"; } } } 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; }
static long eventlogread(void *a, long n) { int len; char *p, *buf; buf = smalloc(Eventlen); qlock(&events); lock(&events); p = events.rp; len = *p; if(len == 0){ n = 0; unlock(&events); } else { if(n > len) n = len; /* can't move directly into pageable space with events lock held */ memmove(buf, p+1, n); *p = 0; events.rp = p += Eventlen; if(p >= events.buf + sizeof events.buf) events.rp = events.buf; unlock(&events); /* the concern here is page faults in memmove below */ if(waserror()){ free(buf); qunlock(&events); nexterror(); } memmove(a, buf, n); poperror(); } free(buf); qunlock(&events); return n; }
static char* flushq(Ctlr *ctlr, uint qid) { TXQ *q; int i; q = &ctlr->tx[qid]; qlock(q); for(i = 0; i < 200 && !ctlr->broken; i++){ if(txqempty(q)){ qunlock(q); return nil; } if(islo() && !waserror()){ tsleep(q, txqempty, q, 10); poperror(); } } qunlock(q); if(ctlr->broken) return "flushq: broken"; return "flushq: timeout"; }
static void aoecfg(void) { int n, i; char *p, *f[32], buf[24]; if((p = getconf("aoeif")) == nil || (n = tokenize(p, f, nelem(f))) < 1) return; /* goo! */ for(i = 0; i < n; i++){ p = f[i]; if(strncmp(p, "ether", 5) == 0) snprint(buf, sizeof buf, "#l%c/ether%c", p[5], p[5]); else if(strncmp(p, "#l", 2) == 0) snprint(buf, sizeof buf, "#l%c/ether%c", p[2], p[2]); else continue; if(!waserror()){ netbind(buf); poperror(); } } }
static void audioclose(Chan *c) { Audiochan *ac; Audio *adev; ac = c->aux; adev = ac->adev; if((c->qid.path == Qaudio) && (c->flag & COPEN)){ if(adev->close){ if(!waserror()){ adev->close(adev); poperror(); } } decref(&adev->audioopen); } if(ac->owner == c){ ac->owner = nil; c->aux = nil; free(ac); } }
long fsread(Chan *c, void *va, long n, vlong offset) { int r; if(c->qid.type & QTDIR){ /* need to maintain offset only for directories */ qlock(FS(c)); if(waserror()){ qunlock(FS(c)); nexterror(); } r = fsdirread(c, va, n, offset); poperror(); qunlock(FS(c)); }else{ osenter(); r = pread(FS(c)->fd, va, n, offset); osleave(); } if(r < 0) fserr(FS(c)); return r; }
uintptr syssegattach(va_list list) { ulong attr; char *name; uintptr va; ulong len; attr = va_arg(list, ulong); name = va_arg(list, char*); va = va_arg(list, uintptr); len = va_arg(list, ulong); validaddr((uintptr)name, 1, 0); name = validnamedup(name, 1); if(waserror()){ free(name); nexterror(); } va = segattach(up, attr, name, va, len); free(name); poperror(); return va; }
static Chan* eiaopen(Chan *c, int mode) { int port = NETID(c->qid.path); c = devopen(c, mode, eiadir, ndir, devgen); switch(NETTYPE(c->qid.path)) { case Nctlqid: case Ndataqid: case Nstatqid: if(incref(&eia[port].r) != 1) break; if(waserror()) { decref(&eia[port].r); nexterror(); } openport(port); poperror(); break; } return c; }
/* * add a multicast address to an interface, called with c->car locked */ void ipifcaddmulti(Conv *c, uint8_t *ma, uint8_t *ia) { Proc *up = externup(); Ipifc *ifc; Iplifc *lifc; Conv **p; Ipmulti *multi, **l; Fs *f; f = c->p->f; for(l = &c->multi; *l; l = &(*l)->next) if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0) return; /* it's already there */ multi = *l = smalloc(sizeof(*multi)); ipmove(multi->ma, ma); ipmove(multi->ia, ia); multi->next = nil; for(p = f->ipifc->conv; *p; p++){ if((*p)->inuse == 0) continue; ifc = (Ipifc*)(*p)->ptcl; if(waserror()){ wunlock(ifc); nexterror(); } wlock(ifc); for(lifc = ifc->lifc; lifc; lifc = lifc->next) if(ipcmp(ia, lifc->local) == 0) addselfcache(f, ifc, lifc, ma, Rmulti); wunlock(ifc); poperror(); } }
long syspipe(ulong *arg) { int fd[2]; Chan *c[2]; Dev *d; static char *datastr[] = {"data", "data1"}; validaddr(arg[0], sizeof(fd), 1); validalign(arg[0], sizeof(int)); d = devtab[devno('|', 0)]; c[0] = namec("#|", Atodir, 0, 0); c[1] = 0; fd[0] = -1; fd[1] = -1; if(waserror()){ cclose(c[0]); if(c[1]) cclose(c[1]); nexterror(); } c[1] = cclone(c[0]); if(walk(&c[0], datastr+0, 1, 1, nil) < 0) error(Egreg); if(walk(&c[1], datastr+1, 1, 1, nil) < 0) error(Egreg); c[0] = d->open(c[0], ORDWR); c[1] = d->open(c[1], ORDWR); if(newfd2(fd, c) < 0) error(Enofd); poperror(); ((int*)arg[0])[0] = fd[0]; ((int*)arg[0])[1] = fd[1]; return 0; }
/* * add a multicast address to an interface, called with c locked */ void ipifcaddmulti(struct conv *c, uint8_t * ma, uint8_t * ia) { ERRSTACK(1); struct Ipifc *ifc; struct Iplifc *lifc; struct conv **p; struct Ipmulti *multi, **l; struct Fs *f; f = c->p->f; for (l = &c->multi; *l; l = &(*l)->next) if (ipcmp(ma, (*l)->ma) == 0) if (ipcmp(ia, (*l)->ia) == 0) return; /* it's already there */ multi = *l = kzmalloc(sizeof(*multi), 0); ipmove(multi->ma, ma); ipmove(multi->ia, ia); multi->next = NULL; for (p = f->ipifc->conv; *p; p++) { if ((*p)->inuse == 0) continue; ifc = (struct Ipifc *)(*p)->ptcl; if (waserror()) { wunlock(&ifc->rwlock); nexterror(); } wlock(&ifc->rwlock); for (lifc = ifc->lifc; lifc; lifc = lifc->next) if (ipcmp(ia, lifc->local) == 0) addselfcache(f, ifc, lifc, ma, Rmulti); wunlock(&ifc->rwlock); poperror(); } }
void init0(void) { char buf[2*KNAMELEN]; up->nerrlab = 0; // if(consuart == nil) // i8250console("0"); spllo(); /* * These are o.k. because rootinit is null. * Then early kproc's will have a root and dot. */ up->slash = namec("#/", Atodir, 0, 0); pathclose(up->slash->path); up->slash->path = newpath("/"); up->dot = cclone(up->slash); devtabinit(); if(!waserror()){ snprint(buf, sizeof(buf), "%s %s", "AMD64", conffile); ksetenv("terminal", buf, 0); ksetenv("cputype", "amd64", 0); if(cpuserver) ksetenv("service", "cpu", 0); else ksetenv("service", "terminal", 0); ksetenv("pgsz", "2097152", 0); confsetenv(); poperror(); } kproc("alarm", alarmkproc, 0); touser(sp); }
long sysstat(ulong *arg) { char *name; Chan *c; uint l; l = arg[2]; validaddr(arg[1], l, 1); validaddr(arg[0], 1, 0); c = namec((char*)arg[0], Aaccess, 0, 0); if(waserror()){ cclose(c); nexterror(); } l = devtab[c->type]->stat(c, (uchar*)arg[1], l); name = pathlast(c->path); if(name) l = dirsetname(name, strlen(name), (uchar*)arg[1], l, arg[2]); poperror(); cclose(c); return l; }
static long wstat(Chan *c, uchar *d, int nd) { long l; int namelen; if(waserror()){ cclose(c); nexterror(); } if(c->ismtpt){ /* * Renaming mount points is disallowed to avoid surprises * (which should be renamed? the mount point or the mounted Chan?). */ dirname(d, &namelen); if(namelen) nameerror(chanpath(c), Eismtpt); } l = devtab[c->type]->wstat(c, d, nd); poperror(); cclose(c); return l; }
static void uartclose(Chan *c) { Proc *up = externup(); Uart *p; if(c->qid.type & QTDIR) return; if((c->flag & COPEN) == 0) return; switch(UARTTYPE(c->qid.path)){ case Qdata: case Qctl: p = uart[UARTID(c->qid.path)]; qlock(&p->ql); 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->ql); break; } }
void sysfstat(Ar0* ar0, ...) { Proc *up = externup(); int fd; Chan *c; usize n; int r; uint8_t *p; va_list list; va_start(list, ar0); /* * int fstat(int fd, uchar* edir, int nedir); * should really be * usize fstat(int fd, uchar* edir, usize nedir); * but returning an unsigned is probably too * radical. */ fd = va_arg(list, int); p = va_arg(list, uint8_t*); n = va_arg(list, usize); va_end(list); p = validaddr(p, n, 1); c = fdtochan(fd, -1, 0, 1); if(waserror()) { cclose(c); nexterror(); } r = c->dev->stat(c, p, n); poperror(); cclose(c); ar0->i = r; }
static int resend(Aoedev *d, Frame *f) { ulong n; Aoeata *a; a = (Aoeata*)f->hdr; if(hset(d, f, a, a->cmd) == -1) return -1; n = f->bcnt; if(n > d->maxbcnt){ n = d->maxbcnt; /* mtu mismatch (jumbo fail?) */ if(f->dlen > n) f->dlen = n; } a->scnt = n / Aoesectsz; f->dl->resent++; f->dl->npkt++; if(waserror()) return -1; devtab[f->nl->dc->type]->bwrite(f->nl->dc, allocfb(f), 0); poperror(); return 0; }