diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
| commit | 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch) | |
| tree | c6e220ba61db3a6ea4052e6841296d829654e664 /os/port/devenv.c | |
| parent | 46439007cf417cbd9ac8049bb4122c890097a0fa (diff) | |
20060303
Diffstat (limited to 'os/port/devenv.c')
| -rw-r--r-- | os/port/devenv.c | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/os/port/devenv.c b/os/port/devenv.c new file mode 100644 index 00000000..da6373a2 --- /dev/null +++ b/os/port/devenv.c @@ -0,0 +1,338 @@ +/* + * 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; + int ve; + Egrp *eg; + Evalue *e; + + if(n <= 0) + return 0; + 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); + ve = offset+n; + if(ve > Maxenvsize) + error(Etoobig); + 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); +} |
