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); 
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)