/* * devenv - environment */ #include "u.h" #include "../port/lib.h" #include "../port/error.h" #include "mem.h" #include "dat.h" #include "fns.h" static void envremove(Chan*); enum { Maxenvsize = 16300, }; static int envgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp) { Egrp *eg; Evalue *e; if(s == DEVDOTDOT){ devdir(c, c->qid, "#e", 0, eve, DMDIR|0775, dp); return 1; } eg = up->env->egrp; qlock(eg); for(e = eg->entries; e != nil && s != 0; e = e->next) s--; if(e == nil) { qunlock(eg); return -1; } /* make sure name string continues to exist after we release lock */ kstrcpy(up->genbuf, e->var, sizeof up->genbuf); devdir(c, e->qid, up->genbuf, e->len, eve, 0666, dp); qunlock(eg); return 1; } static Chan* envattach(char *spec) { if(up->env == nil || up->env->egrp == nil) error(Enodev); 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->env->egrp->vers; return devstat(c, db, n, 0, 0, envgen); } static Chan * envopen(Chan *c, int mode) { Egrp *eg; Evalue *e; if(c->qid.type & QTDIR) { if(mode != OREAD) error(Eperm); c->mode = mode; c->flag |= COPEN; c->offset = 0; return c; } eg = up->env->egrp; qlock(eg); for(e = eg->entries; e != nil; e = e->next) if(e->qid.path == c->qid.path) break; if(e == nil) { qunlock(eg); error(Enonexist); } if((mode & OTRUNC) && e->val) { free(e->val); e->val = 0; e->len = 0; e->qid.vers++; } qunlock(eg); c->mode = openmode(mode); c->flag |= COPEN; c->offset = 0; return c; } static void envcreate(Chan *c, char *name, int mode, ulong) { Egrp *eg; Evalue *e, **le; if(c->qid.type != QTDIR) error(Eperm); if(strlen(name) >= sizeof(up->genbuf)) error("name too long"); /* needs to fit for stat */ mode = openmode(mode); eg = up->env->egrp; qlock(eg); if(waserror()){ qunlock(eg); nexterror(); } for(le = &eg->entries; (e = *le) != nil; le = &e->next) if(strcmp(e->var, name) == 0) error(Eexist); e = smalloc(sizeof(Evalue)); e->var = smalloc(strlen(name)+1); strcpy(e->var, name); e->val = 0; e->len = 0; e->qid.path = ++eg->path; e->next = nil; e->qid.vers = 0; *le = e; c->qid = e->qid; eg->vers++; poperror(); qunlock(eg); c->offset = 0; c->flag |= COPEN; c->mode = mode; } static void envclose(Chan *c) { if(c->flag & CRCLOSE) envremove(c); } static long envread(Chan *c, void *a, long n, vlong offset) { Egrp *eg; Evalue *e; if(c->qid.type & QTDIR) return devdirread(c, a, n, 0, 0, envgen); eg = up->env->egrp; qlock(eg); if(waserror()){ qunlock(eg); nexterror(); } for(e = eg->entries; e != nil; e = e->next) if(e->qid.path == c->qid.path) break; if(e == nil) error(Enonexist); if(offset > e->len) /* protects against overflow converting vlong to ulong */ n = 0; else if(offset + n > e->len) n = e->len - offset; if(n <= 0) n = 0; else memmove(a, e->val+offset, n); poperror(); qunlock(eg); return n; } static long envwrite(Chan *c, void *a, long n, vlong offset) { char *s; ulong ve; Egrp *eg; Evalue *e; if(n <= 0) return 0; ve = offset+n; if(ve > Maxenvsize) error(Etoobig); eg = up->env->egrp; qlock(eg); if(waserror()){ qunlock(eg); nexterror(); } for(e = eg->entries; e != nil; e = e->next) if(e->qid.path == c->qid.path) break; if(e == nil) error(Enonexist); if(ve > e->len) { s = smalloc(ve); memmove(s, e->val, e->len); if(e->val != nil) free(e->val); e->val = s; e->len = ve; } memmove(e->val+offset, a, n); e->qid.vers++; poperror(); qunlock(eg); return n; } static void envremove(Chan *c) { Egrp *eg; Evalue *e, **l; if(c->qid.type & QTDIR) error(Eperm); eg = up->env->egrp; qlock(eg); for(l = &eg->entries; (e = *l) != nil; l = &e->next) if(e->qid.path == c->qid.path) break; if(e == nil) { qunlock(eg); error(Enonexist); } *l = e->next; eg->vers++; qunlock(eg); free(e->var); if(e->val != nil) free(e->val); free(e); } Dev envdevtab = { 'e', "env", devreset, devinit, devshutdown, envattach, envwalk, envstat, envopen, envcreate, envclose, envread, devbread, envwrite, devbwrite, envremove, devwstat }; /* * kernel interface to environment variables */ Egrp* newegrp(void) { Egrp *e; e = smalloc(sizeof(Egrp)); e->ref = 1; return e; } void closeegrp(Egrp *e) { Evalue *el, *nl; if(e == nil || decref(e) != 0) return; for (el = e->entries; el != nil; el = nl) { free(el->var); if (el->val) free(el->val); nl = el->next; free(el); } free(e); } void egrpcpy(Egrp *to, Egrp *from) { Evalue *e, *ne, **last; if(from == nil) return; last = &to->entries; qlock(from); for (e = from->entries; e != nil; e = e->next) { ne = smalloc(sizeof(Evalue)); ne->var = smalloc(strlen(e->var)+1); strcpy(ne->var, e->var); if (e->val) { ne->val = smalloc(e->len); memmove(ne->val, e->val, e->len); ne->len = e->len; } ne->qid.path = ++to->path; *last = ne; last = &ne->next; } qunlock(from); } void ksetenv(char *var, char *val, int) { Chan *c; char buf[2*KNAMELEN]; snprint(buf, sizeof(buf), "#e/%s", var); if(waserror()) return; c = namec(buf, Acreate, OWRITE, 0600); poperror(); if(!waserror()){ if(!waserror()){ devtab[c->type]->write(c, val, strlen(val), 0); poperror(); } poperror(); } cclose(c); }