#include <9pm/u.h> #include <9pm/libc.h> #include "dat.h" #include "fns.h" enum { Maxenvsize = 16300, }; static int envgen(Chan *c, char *name, Dirtab *tab, int ntab, int s, Dir *dp) { Egrp *eg; Evalue *e; USED(name); USED(tab); USED(ntab); if(s == DEVDOTDOT){ devdir(c, c->qid, "#e", 0, up->user, DMDIR|0775, dp); return 1; } eg = up->egrp; qlock(&eg->lk); for(e = eg->entries; e && s; e = e->link) s--; if(e == 0) { qunlock(&eg->lk); return -1; } /* make sure name string continues to exist after we release lock */ kstrcpy(up->genbuf, e->name, sizeof up->genbuf); devdir(c, e->qid, up->genbuf, e->len, up->user, 0666, dp); qunlock(&eg->lk); return 1; } static Evalue* envlookup(Egrp *eg, char *name, ulong qidpath) { Evalue *e; for(e = eg->entries; e; e = e->link) if(e->qid.path == qidpath || (name && strcmp(e->name, name) == 0)) return e; return nil; } static Chan* envattach(char *spec) { return devattach('e', spec); } static Walkqid* envwalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, 0, 0, envgen); } static int envstat(Chan *c, uchar *db, int n) { if(c->qid.type & QTDIR) c->qid.vers = up->egrp->vers; return devstat(c, db, n, 0, 0, envgen); } static Chan* envopen(Chan *c, int omode) { Egrp *eg; Evalue *e; eg = up->egrp; if(c->qid.type & QTDIR) { if(omode != OREAD) error(Eperm); } else { qlock(&eg->lk); e = envlookup(eg, nil, c->qid.path); if(e == 0) { qunlock(&eg->lk); error(Enonexist); } if((omode & OTRUNC) && e->value) { e->qid.vers++; free(e->value); e->value = 0; e->len = 0; } qunlock(&eg->lk); } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } static void envcreate(Chan *c, char *name, int omode, ulong perm) { Egrp *eg; Evalue *e; USED(perm); if(c->qid.type != QTDIR) error(Eperm); omode = openmode(omode); eg = up->egrp; qlock(&eg->lk); if(waserror()) { qunlock(&eg->lk); nexterror(); } if(envlookup(eg, name, -1)) error(Eexist); e = smalloc(sizeof(Evalue)); e->name = smalloc(strlen(name)+1); strcpy(e->name, name); e->qid.path = ++eg->path; e->qid.vers = 0; eg->vers++; e->link = eg->entries; eg->entries = e; c->qid = e->qid; qunlock(&eg->lk); poperror(); c->offset = 0; c->mode = omode; c->flag |= COPEN; } static void envremove(Chan *c) { Egrp *eg; Evalue *e, **l; if(c->qid.type & QTDIR) error(Eperm); eg = up->egrp; qlock(&eg->lk); l = &eg->entries; for(e = *l; e; e = e->link) { if(e->qid.path == c->qid.path) break; l = &e->link; } if(e == 0) { qunlock(&eg->lk); error(Enonexist); } *l = e->link; eg->vers++; qunlock(&eg->lk); free(e->name); if(e->value) free(e->value); free(e); } static void envclose(Chan *c) { /* * cclose can't fail, so errors from remove will be ignored. * since permissions aren't checked, * envremove can't not remove it if its there. */ if(c->flag & CRCLOSE) envremove(c); } static long envread(Chan *c, void *a, long n, vlong off) { Egrp *eg; Evalue *e; ulong offset = off; if(c->qid.type & QTDIR) return devdirread(c, a, n, 0, 0, envgen); eg = up->egrp; qlock(&eg->lk); e = envlookup(eg, nil, c->qid.path); if(e == 0) { qunlock(&eg->lk); error(Enonexist); } if(offset + n > e->len) n = e->len - offset; if(n <= 0) n = 0; else memmove(a, e->value+offset, n); qunlock(&eg->lk); return n; } static long envwrite(Chan *c, void *a, long n, vlong off) { char *s; int vend; Egrp *eg; Evalue *e; ulong offset = off; if(n <= 0) return 0; vend = offset+n; if(vend > Maxenvsize) error(Etoobig); eg = up->egrp; qlock(&eg->lk); e = envlookup(eg, nil, c->qid.path); if(e == 0) { qunlock(&eg->lk); error(Enonexist); } if(vend > e->len) { s = smalloc(offset+n); if(e->value){ memmove(s, e->value, e->len); free(e->value); } e->value = s; e->len = vend; } memmove(e->value+offset, a, n); e->qid.vers++; eg->vers++; qunlock(&eg->lk); return n; } Dev devenv = { 'e', "env", devreset, envattach, envwalk, envstat, envopen, envcreate, envclose, envread, devbread, envwrite, devbwrite, envremove, devwstat, }; void envcpy(Egrp *to, Egrp *from) { Evalue **l, *ne, *e; l = &to->entries; qlock(&from->lk); for(e = from->entries; e; e = e->link) { ne = smalloc(sizeof(Evalue)); ne->name = smalloc(strlen(e->name)+1); strcpy(ne->name, e->name); if(e->value) { ne->value = smalloc(e->len); memmove(ne->value, e->value, e->len); ne->len = e->len; } ne->qid.path = ++to->path; *l = ne; l = &ne->link; } qunlock(&from->lk); } void closeegrp(Egrp *eg) { Evalue *e, *next; if(decref(&eg->ref) == 0) { for(e = eg->entries; e; e = next) { next = e->link; free(e->name); if(e->value) free(e->value); free(e); } free(eg); } } /* * to let the kernel set environment variables */ void ksetenv(char *ename, char *eval) { Chan *c; char buf[2*KNAMELEN]; c = namec(buf, Acreate, OWRITE, 0600); devtab[c->type]->write(c, eval, strlen(eval), 0); cclose(c); }