vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

devenv.c (7140B)


      1 #include	"u.h"
      2 #include	"lib.h"
      3 #include	"mem.h"
      4 #include	"dat.h"
      5 #include	"fns.h"
      6 #include	"error.h"
      7 
      8 enum
      9 {
     10 	Maxenvsize = 16300,
     11 };
     12 
     13 static Egrp	*envgrp(Chan *c);
     14 static int	envwriteable(Chan *c);
     15 
     16 static Egrp	confegrp;	/* global environment group containing the kernel configuration */
     17 
     18 static Evalue*
     19 envlookup(Egrp *eg, char *name, ulong qidpath)
     20 {
     21 	Evalue *e;
     22 	int i;
     23 
     24 	for(i=0; i<eg->nent; i++){
     25 		e = eg->ent[i];
     26 		if(e->qid.path == qidpath || (name && e->name[0]==name[0] && strcmp(e->name, name) == 0))
     27 			return e;
     28 	}
     29 	return nil;
     30 }
     31 
     32 static int
     33 envgen(Chan *c, char *name, Dirtab *dt, int i, int s, Dir *dp)
     34 {
     35 	Egrp *eg;
     36 	Evalue *e;
     37 
     38 	if(s == DEVDOTDOT){
     39 		devdir(c, c->qid, "#e", 0, eve, DMDIR|0775, dp);
     40 		return 1;
     41 	}
     42 
     43 	eg = envgrp(c);
     44 	rlock(&eg->lk);
     45 	e = 0;
     46 	if(name)
     47 		e = envlookup(eg, name, -1);
     48 	else if(s < eg->nent)
     49 		e = eg->ent[s];
     50 
     51 	if(e == 0) {
     52 		runlock(&eg->lk);
     53 		return -1;
     54 	}
     55 
     56 	/* make sure name string continues to exist after we release lock */
     57 	kstrcpy(up->genbuf, e->name, sizeof up->genbuf);
     58 	devdir(c, e->qid, up->genbuf, e->len, eve, 0666, dp);
     59 	runlock(&eg->lk);
     60 	return 1;
     61 }
     62 
     63 static Chan*
     64 envattach(char *spec)
     65 {
     66 	Chan *c;
     67 	Egrp *egrp = nil;
     68 
     69 	if(spec && *spec) {
     70 		if(strcmp(spec, "c") == 0)
     71 			egrp = &confegrp;
     72 		if(egrp == nil)
     73 			error(Ebadarg);
     74 	}
     75 
     76 	c = devattach('e', spec);
     77 	c->aux = egrp;
     78 	return c;
     79 }
     80 
     81 static Walkqid*
     82 envwalk(Chan *c, Chan *nc, char **name, int nname)
     83 {
     84 	return devwalk(c, nc, name, nname, 0, 0, envgen);
     85 }
     86 
     87 static int
     88 envstat(Chan *c, uchar *db, int n)
     89 {
     90 	if(c->qid.type & QTDIR)
     91 		c->qid.vers = envgrp(c)->vers;
     92 	return devstat(c, db, n, 0, 0, envgen);
     93 }
     94 
     95 static Chan*
     96 envopen(Chan *c, int omode)
     97 {
     98 	Egrp *eg;
     99 	Evalue *e;
    100 	int trunc;
    101 
    102 	eg = envgrp(c);
    103 	if(c->qid.type & QTDIR) {
    104 		if(omode != OREAD)
    105 			error(Eperm);
    106 	}
    107 	else {
    108 		trunc = omode & OTRUNC;
    109 		if(omode != OREAD && !envwriteable(c))
    110 			error(Eperm);
    111 		if(trunc)
    112 			wlock(&eg->lk);
    113 		else
    114 			rlock(&eg->lk);
    115 		e = envlookup(eg, nil, c->qid.path);
    116 		if(e == 0) {
    117 			if(trunc)
    118 				wunlock(&eg->lk);
    119 			else
    120 				runlock(&eg->lk);
    121 			error(Enonexist);
    122 		}
    123 		if(trunc && e->value) {
    124 			e->qid.vers++;
    125 			free(e->value);
    126 			e->value = 0;
    127 			e->len = 0;
    128 		}
    129 		if(trunc)
    130 			wunlock(&eg->lk);
    131 		else
    132 			runlock(&eg->lk);
    133 	}
    134 	c->mode = openmode(omode);
    135 	c->flag |= COPEN;
    136 	c->offset = 0;
    137 	return c;
    138 }
    139 
    140 static void
    141 envcreate(Chan *c, char *name, int omode, ulong perm)
    142 {
    143 	Egrp *eg;
    144 	Evalue *e;
    145 	Evalue **ent;
    146 
    147 	if(c->qid.type != QTDIR)
    148 		error(Eperm);
    149 
    150 	omode = openmode(omode);
    151 	eg = envgrp(c);
    152 
    153 	wlock(&eg->lk);
    154 	if(waserror()) {
    155 		wunlock(&eg->lk);
    156 		nexterror();
    157 	}
    158 
    159 	if(envlookup(eg, name, -1))
    160 		error(Eexist);
    161 
    162 	e = smalloc(sizeof(Evalue));
    163 	e->name = smalloc(strlen(name)+1);
    164 	strcpy(e->name, name);
    165 
    166 	if(eg->nent == eg->ment){
    167 		eg->ment += 32;
    168 		ent = smalloc(sizeof(eg->ent[0])*eg->ment);
    169 		if(eg->nent)
    170 			memmove(ent, eg->ent, sizeof(eg->ent[0])*eg->nent);
    171 		free(eg->ent);
    172 		eg->ent = ent;
    173 	}
    174 	e->qid.path = ++eg->path;
    175 	e->qid.vers = 0;
    176 	eg->vers++;
    177 	eg->ent[eg->nent++] = e;
    178 	c->qid = e->qid;
    179 
    180 	wunlock(&eg->lk);
    181 	poperror();
    182 
    183 	c->offset = 0;
    184 	c->mode = omode;
    185 	c->flag |= COPEN;
    186 }
    187 
    188 static void
    189 envremove(Chan *c)
    190 {
    191 	int i;
    192 	Egrp *eg;
    193 	Evalue *e;
    194 
    195 	if(c->qid.type & QTDIR)
    196 		error(Eperm);
    197 
    198 	eg = envgrp(c);
    199 	wlock(&eg->lk);
    200 	e = 0;
    201 	for(i=0; i<eg->nent; i++){
    202 		if(eg->ent[i]->qid.path == c->qid.path){
    203 			e = eg->ent[i];
    204 			eg->nent--;
    205 			eg->ent[i] = eg->ent[eg->nent];
    206 			eg->vers++;
    207 			break;
    208 		}
    209 	}
    210 	wunlock(&eg->lk);
    211 	if(e == 0)
    212 		error(Enonexist);
    213 	free(e->name);
    214 	if(e->value)
    215 		free(e->value);
    216 	free(e);
    217 }
    218 
    219 static void
    220 envclose(Chan *c)
    221 {
    222 	/*
    223 	 * cclose can't fail, so errors from remove will be ignored.
    224 	 * since permissions aren't checked,
    225 	 * envremove can't not remove it if its there.
    226 	 */
    227 	if(c->flag & CRCLOSE)
    228 		envremove(c);
    229 }
    230 
    231 static long
    232 envread(Chan *c, void *a, long n, vlong off)
    233 {
    234 	Egrp *eg;
    235 	Evalue *e;
    236 	ulong offset = off;
    237 
    238 	if(c->qid.type & QTDIR)
    239 		return devdirread(c, a, n, 0, 0, envgen);
    240 
    241 	eg = envgrp(c);
    242 	rlock(&eg->lk);
    243 	e = envlookup(eg, nil, c->qid.path);
    244 	if(e == 0) {
    245 		runlock(&eg->lk);
    246 		error(Enonexist);
    247 	}
    248 
    249 	if(offset > e->len)	/* protects against overflow converting vlong to ulong */
    250 		n = 0;
    251 	else if(offset + n > e->len)
    252 		n = e->len - offset;
    253 	if(n <= 0)
    254 		n = 0;
    255 	else
    256 		memmove(a, e->value+offset, n);
    257 	runlock(&eg->lk);
    258 	return n;
    259 }
    260 
    261 static long
    262 envwrite(Chan *c, void *a, long n, vlong off)
    263 {
    264 	char *s;
    265 	ulong len;
    266 	Egrp *eg;
    267 	Evalue *e;
    268 	ulong offset = off;
    269 
    270 	if(n <= 0)
    271 		return 0;
    272 	if(offset > Maxenvsize || n > (Maxenvsize - offset))
    273 		error(Etoobig);
    274 
    275 	eg = envgrp(c);
    276 	wlock(&eg->lk);
    277 	e = envlookup(eg, nil, c->qid.path);
    278 	if(e == 0) {
    279 		wunlock(&eg->lk);
    280 		error(Enonexist);
    281 	}
    282 
    283 	len = offset+n;
    284 	if(len > e->len) {
    285 		s = smalloc(len);
    286 		if(e->value){
    287 			memmove(s, e->value, e->len);
    288 			free(e->value);
    289 		}
    290 		e->value = s;
    291 		e->len = len;
    292 	}
    293 	memmove(e->value+offset, a, n);
    294 	e->qid.vers++;
    295 	eg->vers++;
    296 	wunlock(&eg->lk);
    297 	return n;
    298 }
    299 
    300 Dev envdevtab = {
    301 	'e',
    302 	"env",
    303 
    304 	devreset,
    305 	devinit,
    306 	devshutdown,
    307 	envattach,
    308 	envwalk,
    309 	envstat,
    310 	envopen,
    311 	envcreate,
    312 	envclose,
    313 	envread,
    314 	devbread,
    315 	envwrite,
    316 	devbwrite,
    317 	envremove,
    318 	devwstat,
    319 };
    320 
    321 void
    322 envcpy(Egrp *to, Egrp *from)
    323 {
    324 	int i;
    325 	Evalue *ne, *e;
    326 
    327 	rlock(&from->lk);
    328 	to->ment = (from->nent+31)&~31;
    329 	to->ent = smalloc(to->ment*sizeof(to->ent[0]));
    330 	for(i=0; i<from->nent; i++){
    331 		e = from->ent[i];
    332 		ne = smalloc(sizeof(Evalue));
    333 		ne->name = smalloc(strlen(e->name)+1);
    334 		strcpy(ne->name, e->name);
    335 		if(e->value){
    336 			ne->value = smalloc(e->len);
    337 			memmove(ne->value, e->value, e->len);
    338 			ne->len = e->len;
    339 		}
    340 		ne->qid.path = ++to->path;
    341 		to->ent[i] = ne;
    342 	}
    343 	to->nent = from->nent;
    344 	runlock(&from->lk);
    345 }
    346 
    347 void
    348 closeegrp(Egrp *eg)
    349 {
    350 	int i;
    351 	Evalue *e;
    352 
    353 	if(decref(&eg->ref) == 0){
    354 		for(i=0; i<eg->nent; i++){
    355 			e = eg->ent[i];
    356 			free(e->name);
    357 			if(e->value)
    358 				free(e->value);
    359 			free(e);
    360 		}
    361 		free(eg->ent);
    362 		free(eg);
    363 	}
    364 }
    365 
    366 static Egrp*
    367 envgrp(Chan *c)
    368 {
    369 	if(c->aux == nil)
    370 		return up->egrp;
    371 	return c->aux;
    372 }
    373 
    374 static int
    375 envwriteable(Chan *c)
    376 {
    377 	return iseve() || c->aux == nil;
    378 }
    379 
    380 /*
    381  *  to let the kernel set environment variables
    382  */
    383 void
    384 ksetenv(char *ename, char *eval, int conf)
    385 {
    386 	Chan *c;
    387 	char buf[2*KNAMELEN];
    388 	
    389 	snprint(buf, sizeof(buf), "#e%s/%s", conf?"c":"", ename);
    390 	c = namec(buf, Acreate, OWRITE, 0600);
    391 	devtab[c->type]->write(c, eval, strlen(eval), 0);
    392 	cclose(c);
    393 }
    394 
    395 /*
    396  * Return a copy of configuration environment as a sequence of strings.
    397  * The strings alternate between name and value.  A zero length name string
    398  * indicates the end of the list
    399  */
    400 char *
    401 getconfenv(void)
    402 {
    403 	Egrp *eg = &confegrp;
    404 	Evalue *e;
    405 	char *p, *q;
    406 	int i, n;
    407 
    408 	rlock(&eg->lk);
    409 	if(waserror()) {
    410 		runlock(&eg->lk);
    411 		nexterror();
    412 	}
    413 	
    414 	/* determine size */
    415 	n = 0;
    416 	for(i=0; i<eg->nent; i++){
    417 		e = eg->ent[i];
    418 		n += strlen(e->name) + e->len + 2;
    419 	}
    420 	p = malloc(n + 1);
    421 	if(p == nil)
    422 		error(Enomem);
    423 	q = p;
    424 	for(i=0; i<eg->nent; i++){
    425 		e = eg->ent[i];
    426 		strcpy(q, e->name);
    427 		q += strlen(q) + 1;
    428 		memmove(q, e->value, e->len);
    429 		q[e->len] = 0;
    430 		/* move up to the first null */
    431 		q += strlen(q) + 1;
    432 	}
    433 	*q = 0;
    434 	
    435 	poperror();
    436 	runlock(&eg->lk);
    437 	return p;
    438 }