123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "../port/error.h"
- enum
- {
- Maxenvsize = 16300,
- };
- static Egrp *envgrp(Chan *c);
- static int envwriteable(Chan *c);
- static Egrp confegrp; /* global environment group containing the kernel configuration */
- static Evalue*
- envlookup(Egrp *eg, char *name, uint32_t qidpath)
- {
- Evalue *e;
- int i;
- for(i=0; i<eg->nent; i++){
- e = eg->ent[i];
- if(e->qid.path == qidpath || (name && e->name[0]==name[0] && strcmp(e->name, name) == 0))
- return e;
- }
- return nil;
- }
- static int
- envgen(Chan *c, char *name, Dirtab* dir, int i, int s, Dir *dp)
- {
- Mach *m = machp();
- Egrp *eg;
- Evalue *e;
- if(s == DEVDOTDOT){
- devdir(c, c->qid, "#e", 0, eve, DMDIR|0775, dp);
- return 1;
- }
- eg = envgrp(c);
- rlock(eg);
- e = 0;
- if(name)
- e = envlookup(eg, name, -1);
- else if(s < eg->nent)
- e = eg->ent[s];
- if(e == 0) {
- runlock(eg);
- return -1;
- }
- /* make sure name string continues to exist after we release lock */
- kstrcpy(m->externup->genbuf, e->name, sizeof m->externup->genbuf);
- devdir(c, e->qid, m->externup->genbuf, e->len, eve, 0666, dp);
- runlock(eg);
- return 1;
- }
- static Chan*
- envattach(char *spec)
- {
- Chan *c;
- Egrp *egrp = nil;
- if(spec && *spec) {
- if(strcmp(spec, "c") == 0)
- egrp = &confegrp;
- if(egrp == nil)
- error(Ebadarg);
- }
- c = devattach('e', spec);
- c->aux = egrp;
- return c;
- }
- static Walkqid*
- envwalk(Chan *c, Chan *nc, char **name, int nname)
- {
- return devwalk(c, nc, name, nname, 0, 0, envgen);
- }
- static int32_t
- envstat(Chan *c, uint8_t *db, int32_t n)
- {
- if(c->qid.type & QTDIR)
- c->qid.vers = envgrp(c)->vers;
- return devstat(c, db, n, 0, 0, envgen);
- }
- static Chan*
- envopen(Chan *c, int omode)
- {
- Egrp *eg;
- Evalue *e;
- int trunc;
- eg = envgrp(c);
- if(c->qid.type & QTDIR) {
- if(omode != OREAD)
- error(Eperm);
- }
- else {
- trunc = omode & OTRUNC;
- if(omode != OREAD && !envwriteable(c))
- error(Eperm);
- if(trunc)
- wlock(eg);
- else
- rlock(eg);
- e = envlookup(eg, nil, c->qid.path);
- if(e == 0) {
- if(trunc)
- wunlock(eg);
- else
- runlock(eg);
- error(Enonexist);
- }
- if(trunc && e->value) {
- e->qid.vers++;
- free(e->value);
- e->value = 0;
- e->len = 0;
- }
- if(trunc)
- wunlock(eg);
- else
- runlock(eg);
- }
- c->mode = openmode(omode);
- c->flag |= COPEN;
- c->offset = 0;
- return c;
- }
- static void
- envcreate(Chan *c, char *name, int omode, int i)
- {
- Mach *m = machp();
- Egrp *eg;
- Evalue *e;
- Evalue **ent;
- if(c->qid.type != QTDIR)
- error(Eperm);
- omode = openmode(omode);
- eg = envgrp(c);
- wlock(eg);
- if(waserror()) {
- wunlock(eg);
- nexterror();
- }
- if(envlookup(eg, name, -1))
- error(Eexist);
- e = smalloc(sizeof(Evalue));
- e->name = smalloc(strlen(name)+1);
- strcpy(e->name, name);
- if(eg->nent == eg->ment){
- eg->ment += 32;
- ent = smalloc(sizeof(eg->ent[0])*eg->ment);
- if(eg->nent)
- memmove(ent, eg->ent, sizeof(eg->ent[0])*eg->nent);
- free(eg->ent);
- eg->ent = ent;
- }
- e->qid.path = ++eg->path;
- e->qid.vers = 0;
- eg->vers++;
- eg->ent[eg->nent++] = e;
- c->qid = e->qid;
- wunlock(eg);
- poperror();
- c->offset = 0;
- c->mode = omode;
- c->flag |= COPEN;
- }
- static void
- envremove(Chan *c)
- {
- int i;
- Egrp *eg;
- Evalue *e;
- if(c->qid.type & QTDIR)
- error(Eperm);
- eg = envgrp(c);
- wlock(eg);
- e = 0;
- for(i=0; i<eg->nent; i++){
- if(eg->ent[i]->qid.path == c->qid.path){
- e = eg->ent[i];
- eg->nent--;
- eg->ent[i] = eg->ent[eg->nent];
- eg->vers++;
- break;
- }
- }
- wunlock(eg);
- if(e == 0)
- error(Enonexist);
- 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 int32_t
- envread(Chan *c, void *a, int32_t n, int64_t off)
- {
- Egrp *eg;
- Evalue *e;
- int32_t offset;
- if(c->qid.type & QTDIR)
- return devdirread(c, a, n, 0, 0, envgen);
- eg = envgrp(c);
- rlock(eg);
- e = envlookup(eg, nil, c->qid.path);
- if(e == 0) {
- runlock(eg);
- error(Enonexist);
- }
- offset = off;
- if(offset > e->len) /* protects against overflow converting int64_t to long */
- n = 0;
- else if(offset + n > e->len)
- n = e->len - offset;
- if(n <= 0)
- n = 0;
- else
- memmove(a, e->value+offset, n);
- runlock(eg);
- return n;
- }
- static int32_t
- envwrite(Chan *c, void *a, int32_t n, int64_t off)
- {
- char *s;
- Egrp *eg;
- Evalue *e;
- int32_t len, offset;
- if(n <= 0)
- return 0;
- offset = off;
- if(offset > Maxenvsize || n > (Maxenvsize - offset))
- error(Etoobig);
- eg = envgrp(c);
- wlock(eg);
- e = envlookup(eg, nil, c->qid.path);
- if(e == 0) {
- wunlock(eg);
- error(Enonexist);
- }
- len = offset+n;
- if(len > e->len) {
- s = smalloc(len);
- if(e->value){
- memmove(s, e->value, e->len);
- free(e->value);
- }
- e->value = s;
- e->len = len;
- }
- memmove(e->value+offset, a, n);
- e->qid.vers++;
- eg->vers++;
- wunlock(eg);
- return n;
- }
- Dev envdevtab = {
- 'e',
- "env",
- devreset,
- devinit,
- devshutdown,
- envattach,
- envwalk,
- envstat,
- envopen,
- envcreate,
- envclose,
- envread,
- devbread,
- envwrite,
- devbwrite,
- envremove,
- devwstat,
- };
- void
- envcpy(Egrp *to, Egrp *from)
- {
- int i;
- Evalue *ne, *e;
- rlock(from);
- to->ment = (from->nent+31)&~31;
- to->ent = smalloc(to->ment*sizeof(to->ent[0]));
- for(i=0; i<from->nent; i++){
- e = from->ent[i];
- 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;
- to->ent[i] = ne;
- }
- to->nent = from->nent;
- runlock(from);
- }
- void
- closeegrp(Egrp *eg)
- {
- int i;
- Evalue *e;
- if(decref(eg) == 0){
- for(i=0; i<eg->nent; i++){
- e = eg->ent[i];
- free(e->name);
- if(e->value)
- free(e->value);
- free(e);
- }
- free(eg->ent);
- free(eg);
- }
- }
- static Egrp*
- envgrp(Chan *c)
- {
- Mach *m = machp();
- if(c->aux == nil)
- return m->externup->egrp;
- return c->aux;
- }
- static int
- envwriteable(Chan *c)
- {
- return iseve() || c->aux == nil;
- }
- /*
- * to let the kernel set environment variables
- */
- void
- ksetenv(char *ename, char *eval, int conf)
- {
- Chan *c;
- char buf[2*KNAMELEN];
- snprint(buf, sizeof(buf), "#e%s/%s", conf?"c":"", ename);
- c = namec(buf, Acreate, OWRITE, 0600);
- c->dev->write(c, eval, strlen(eval), 0);
- cclose(c);
- }
- /*
- * 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)
- {
- Mach *m = machp();
- 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;
- }
|