| plan 9 kernel history: overview | file list | diff list |
1991/1018/port/devenv.c (diff list | history)
| port/devenv.c on 1990/0227 | ||
| 1990/0227 | #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "errno.h" #include "devtab.h" struct Envval { | |
| 1991/1018 | Envval *next; /* for hashing & easy deletion from hash list */ Envval *prev; ulong len; /* length of val that is valid */ int ref; char *val; | |
| 1990/0227 | }; | |
| 1991/1018 | enum{ MAXENV = (BY2PG - sizeof(Envval)), EVHASH = 64, EVFREE = 16, ALIGN = 16, }; | |
| 1990/0227 | struct { | |
| 1991/1018 | Envval *free[EVFREE+1]; char *block; /* the free page we are allocating from */ char *lim; /* end of block */ | |
| 1990/0227 | }envalloc; | |
| 1991/1018 | QLock evlock; Envval evhash[EVHASH]; char *evscratch; /* for constructing the contents of a file */ | |
| 1990/0227 | ||
| 1991/1018 | Envval *newev(char*, ulong); Envval *evalloc(ulong); void evfree(Envval*); | |
| 1990/0227 | void envreset(void) { | |
| 1991/1018 | evscratch = ialloc(BY2PG, 0); | |
| 1990/0227 | } void envinit(void) { } int envgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp) { | |
| 1991/0705 | Egrp *eg; | |
| 1991/1018 | Env *e; | |
| 1990/0227 | int ans; | |
| 1991/0705 | eg = u->p->egrp; | |
| 1991/1018 | qlock(&eg->ev); | |
| 1991/0705 | if(s >= eg->nenv) | |
| 1990/0227 | ans = -1; else{ | |
| 1991/1018 | e = &eg->etab[s]; if(!e->name) | |
| 1990/0227 | ans = 0; else{ | |
| 1991/1018 | devdir(c, (Qid){s+1, (ulong)e->val}, e->name->val, e->val? e->val->len : 0, 0666, dp); | |
| 1990/0227 | ans = 1; } } | |
| 1991/1018 | qunlock(&eg->ev); | |
| 1990/0227 | return ans; } Chan* envattach(char *spec) { return devattach('e', spec); } Chan* envclone(Chan *c, Chan *nc) { return devclone(c, nc); } int envwalk(Chan *c, char *name) { | |
| 1991/1018 | return devwalk(c, name, 0, 0, envgen); | |
| 1990/0227 | } void envstat(Chan *c, char *db) { devstat(c, db, 0, 0, envgen); } Chan * envopen(Chan *c, int omode) { | |
| 1991/0705 | Egrp *eg; | |
| 1991/1018 | Env *e; int mode; | |
| 1990/0227 | ||
| 1991/1018 | mode = openmode(omode); if(c->qid.path & CHDIR){ if(omode != OREAD) | |
| 1990/11211 | error(Eperm); | |
| 1991/1018 | }else{ | |
| 1991/0705 | eg = u->p->egrp; | |
| 1991/1018 | qlock(&eg->ev); e = &eg->etab[c->qid.path-1]; if(!e->name){ qunlock(&eg->ev); error(Enonexist); | |
| 1990/0227 | } | |
| 1991/1018 | if(omode == (OWRITE|OTRUNC) && e->val){ qlock(&evlock); evfree(e->val); qunlock(&evlock); e->val = 0; | |
| 1990/0227 | } | |
| 1991/1018 | qunlock(&eg->ev); | |
| 1990/0227 | } | |
| 1991/1018 | c->mode = mode; | |
| 1990/0227 | c->flag |= COPEN; c->offset = 0; return c; } void envcreate(Chan *c, char *name, int omode, ulong perm) { | |
| 1991/0705 | Egrp *eg; | |
| 1991/1018 | Env *e, *ne; | |
| 1990/0227 | int i; | |
| 1990/11211 | if(c->qid.path != CHDIR) error(Eperm); | |
| 1991/1018 | omode = openmode(omode); | |
| 1991/0705 | eg = u->p->egrp; | |
| 1991/1018 | qlock(&eg->ev); e = eg->etab; ne = 0; for(i = 0; i < eg->nenv; i++, e++) if(e->name == 0) ne = e; else if(strcmp(e->name->val, name) == 0){ qunlock(&eg->ev); error(Einuse); } if(ne) e = ne; else if(eg->nenv == conf.npgenv){ print("out of egroup envs\n"); qunlock(&eg->ev); | |
| 1990/11211 | error(Enoenv); | |
| 1990/0227 | } | |
| 1991/1018 | i = e - eg->etab + 1; e->val = 0; qlock(&evlock); e->name = newev(name, strlen(name)+1); qunlock(&evlock); if(i > eg->nenv) eg->nenv = i; qunlock(&eg->ev); c->qid = (Qid){i, 0}; | |
| 1990/0227 | c->offset = 0; | |
| 1991/1018 | c->mode = omode; | |
| 1990/0227 | c->flag |= COPEN; } void envremove(Chan *c) { | |
| 1991/0705 | Egrp *eg; | |
| 1991/1018 | Env *e; | |
| 1990/0227 | ||
| 1990/11211 | if(c->qid.path & CHDIR) error(Eperm); | |
| 1991/0705 | eg = u->p->egrp; | |
| 1991/1018 | qlock(&eg->ev); e = &eg->etab[c->qid.path-1]; if(!e->name){ qunlock(&eg->ev); | |
| 1990/11211 | error(Enonexist); | |
| 1990/0227 | } envpgclose(e); | |
| 1991/1018 | qunlock(&eg->ev); | |
| 1990/0227 | } void envwstat(Chan *c, char *db) | |
| 1991/1018 | { error(Eperm); | |
| 1990/0227 | } void envclose(Chan * c) { | |
| 1991/1018 | } | |
| 1990/0227 | ||
| 1991/1018 | void envpgcopy(Env *t, Env *f) { qlock(&evlock); if(t->name = f->name) t->name->ref++; if(t->val = f->val) t->val->ref++; qunlock(&evlock); | |
| 1990/0227 | } void envpgclose(Env *e) { | |
| 1991/1018 | qlock(&evlock); if(e->name) evfree(e->name); if(e->val) evfree(e->val); e->name = e->val = 0; qunlock(&evlock); | |
| 1990/0227 | } long | |
| 1991/1018 | envread(Chan *c, void *a, long n, ulong offset) | |
| 1990/0227 | { | |
| 1991/1018 | Egrp *eg; | |
| 1990/0227 | Env *e; Envval *ev; long vn; | |
| 1990/11211 | if(c->qid.path & CHDIR) | |
| 1990/0227 | return devdirread(c, a, n, 0, 0, envgen); | |
| 1991/0705 | eg = u->p->egrp; | |
| 1991/1018 | qlock(&eg->ev); e = &eg->etab[c->qid.path-1]; if(!e->name){ qunlock(&eg->ev); error(Enonexist); | |
| 1990/0227 | } ev = e->val; | |
| 1991/1018 | vn = ev ? ev->len : 0; if(offset + n > vn) | |
| 1991/0411 | n = vn - offset; | |
| 1990/0227 | if(n <= 0) n = 0; else | |
| 1991/1018 | memmove(a, ev->val + offset, n); qunlock(&eg->ev); | |
| 1990/0227 | return n; } long | |
| 1991/1018 | envwrite(Chan *c, void *a, long n, ulong offset) | |
| 1990/0227 | { | |
| 1991/1018 | Egrp *eg; | |
| 1990/0227 | Env *e; Envval *ev; | |
| 1991/1018 | ulong olen; | |
| 1990/0227 | if(n <= 0) return 0; | |
| 1991/1018 | if(offset + n > MAXENV) error(Etoobig); | |
| 1991/0705 | eg = u->p->egrp; | |
| 1991/1018 | qlock(&eg->ev); e = &eg->etab[c->qid.path-1]; if(!e->name){ qunlock(&eg->ev); error(Enonexist); | |
| 1990/0227 | } ev = e->val; | |
| 1991/1018 | olen = ev ? ev->len : 0; qlock(&evlock); if(offset == 0 && n >= olen) e->val = newev(a, n); else{ if(olen > offset) olen = offset; if(ev) memmove(evscratch, ev->val, olen); if(olen < offset) memset(evscratch + olen, '\0', offset - olen); memmove(evscratch + offset, a, n); e->val = newev(evscratch, offset + n); } if(ev) evfree(ev); qunlock(&evlock); qunlock(&eg->ev); | |
| 1990/0227 | return n; } | |
| 1991/1018 | /* * called with evlock qlocked */ Envval * newev(char *s, ulong n) | |
| 1990/0227 | { Envval *ev; | |
| 1991/1018 | uchar *t; int h; | |
| 1990/0227 | ||
| 1991/1018 | h = 0; for(t = (uchar*)s; t - (uchar*)s < n; t++) h = (h << 1) ^ *t; h &= EVHASH - 1; for(ev = evhash[h].next; ev; ev = ev->next) if(ev->len == n && memcmp(ev->val, s, n) == 0){ ev->ref++; return ev; } ev = evalloc(n); ev->len = n; memmove(ev->val, s, n); if(ev->next = evhash[h].next) ev->next->prev = ev; evhash[h].next = ev; ev->prev = &evhash[h]; return ev; } /* * called only from newev */ Envval * evalloc(ulong n) { Envval *ev, **p; char *b, *lim; ulong size; n = (n - 1) / ALIGN; size = (n + 1) * ALIGN; p = &envalloc.free[n < EVFREE ? n : EVFREE]; for(ev = *p; ev; ev = *p){ if(ev->len == size){ *p = ev->next; ev->ref = 1; return ev; } p = &ev->next; } /* * make sure we have enough space to allocate the buffer. * if not, use the remaining space for the smallest buffers */ if(size > MAXENV) panic("evalloc"); b = envalloc.block; lim = envalloc.lim; if(!b || lim < b + size + sizeof *ev){ p = &envalloc.free[0]; while(lim >= b + ALIGN + sizeof *ev){ ev = (Envval*)b; ev->len = ALIGN; ev->val = b + sizeof *ev; ev->next = *p; *p = ev; b += ALIGN + sizeof *ev; } b = (char*)VA(kmap(newpage(0, 0, 0))); envalloc.lim = b + BY2PG; } ev = (Envval*)b; ev->val = b + sizeof *ev; ev->ref = 1; envalloc.block = b + size + sizeof *ev; return ev; } /* * called with evlock qlocked */ void evfree(Envval *ev) { int n; if(--ev->ref > 0) return; if(ev->prev) ev->prev->next = ev->next; if(ev->next) ev->next->prev = ev->prev; n = (ev->len + ALIGN - 1) & ~(ALIGN - 1); ev->len = n; n = (n - 1) / ALIGN; if(n > EVFREE) n = EVFREE; ev->next = envalloc.free[n]; envalloc.free[n] = ev; | |
| 1990/0227 | } | |
| 1991/0927 | /* * to let the kernel set environment variables */ void ksetenv(char *ename, char *eval) { Chan *c; char buf[2*NAMELEN]; sprint(buf, "#e/%s", ename); c = namec(buf, Acreate, OWRITE, 0600); (*devtab[c->type].write)(c, eval, strlen(eval), 0); close(c); } | |