Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include	"u.h"
2
#include	"../port/lib.h"
3
#include	"mem.h"
4
#include	"dat.h"
5
#include	"fns.h"
6
#include	"../port/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*, int, 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);
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);
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);
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);
113
		else
114
			rlock(eg);
115
		e = envlookup(eg, nil, c->qid.path);
116
		if(e == 0) {
117
			if(trunc)
118
				wunlock(eg);
119
			else
120
				runlock(eg);
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);
131
		else
132
			runlock(eg);
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)
142
{
143
	Egrp *eg;
144
	Evalue *e;
145
	Evalue **ent;
146
 
147
	if(c->qid.type != QTDIR)
148
		error(Eperm);
149
	if(strlen(name) >= sizeof up->genbuf)
150
		error("name too long");			/* protect envgen */
151
 
152
	omode = openmode(omode);
153
	eg = envgrp(c);
154
 
155
	wlock(eg);
156
	if(waserror()) {
157
		wunlock(eg);
158
		nexterror();
159
	}
160
 
161
	if(envlookup(eg, name, -1))
162
		error(Eexist);
163
 
164
	e = smalloc(sizeof(Evalue));
165
	e->name = smalloc(strlen(name)+1);
166
	strcpy(e->name, name);
167
 
168
	if(eg->nent == eg->ment){
169
		eg->ment += 32;
170
		ent = smalloc(sizeof(eg->ent[0])*eg->ment);
171
		if(eg->nent)
172
			memmove(ent, eg->ent, sizeof(eg->ent[0])*eg->nent);
173
		free(eg->ent);
174
		eg->ent = ent;
175
	}
176
	e->qid.path = ++eg->path;
177
	e->qid.vers = 0;
178
	eg->vers++;
179
	eg->ent[eg->nent++] = e;
180
	c->qid = e->qid;
181
 
182
	wunlock(eg);
183
	poperror();
184
 
185
	c->offset = 0;
186
	c->mode = omode;
187
	c->flag |= COPEN;
188
}
189
 
190
static void
191
envremove(Chan *c)
192
{
193
	int i;
194
	Egrp *eg;
195
	Evalue *e;
196
 
197
	if(c->qid.type & QTDIR)
198
		error(Eperm);
199
 
200
	eg = envgrp(c);
201
	wlock(eg);
202
	e = 0;
203
	for(i=0; i<eg->nent; i++){
204
		if(eg->ent[i]->qid.path == c->qid.path){
205
			e = eg->ent[i];
206
			eg->nent--;
207
			eg->ent[i] = eg->ent[eg->nent];
208
			eg->vers++;
209
			break;
210
		}
211
	}
212
	wunlock(eg);
213
	if(e == 0)
214
		error(Enonexist);
215
	free(e->name);
216
	if(e->value)
217
		free(e->value);
218
	free(e);
219
}
220
 
221
static void
222
envclose(Chan *c)
223
{
224
	/*
225
	 * cclose can't fail, so errors from remove will be ignored.
226
	 * since permissions aren't checked,
227
	 * envremove can't not remove it if its there.
228
	 */
229
	if(c->flag & CRCLOSE)
230
		envremove(c);
231
}
232
 
233
static long
234
envread(Chan *c, void *a, long n, vlong off)
235
{
236
	Egrp *eg;
237
	Evalue *e;
238
	ulong offset = off;
239
 
240
	if(c->qid.type & QTDIR)
241
		return devdirread(c, a, n, 0, 0, envgen);
242
 
243
	eg = envgrp(c);
244
	rlock(eg);
245
	e = envlookup(eg, nil, c->qid.path);
246
	if(e == 0) {
247
		runlock(eg);
248
		error(Enonexist);
249
	}
250
 
251
	if(offset > e->len)	/* protects against overflow converting vlong to ulong */
252
		n = 0;
253
	else if(offset + n > e->len)
254
		n = e->len - offset;
255
	if(n <= 0)
256
		n = 0;
257
	else
258
		memmove(a, e->value+offset, n);
259
	runlock(eg);
260
	return n;
261
}
262
 
263
static long
264
envwrite(Chan *c, void *a, long n, vlong off)
265
{
266
	char *s;
267
	ulong len;
268
	Egrp *eg;
269
	Evalue *e;
270
	ulong offset = off;
271
 
272
	if(n <= 0)
273
		return 0;
274
	if(offset > Maxenvsize || n > (Maxenvsize - offset))
275
		error(Etoobig);
276
 
277
	eg = envgrp(c);
278
	wlock(eg);
279
	e = envlookup(eg, nil, c->qid.path);
280
	if(e == 0) {
281
		wunlock(eg);
282
		error(Enonexist);
283
	}
284
 
285
	len = offset+n;
286
	if(len > e->len) {
287
		s = smalloc(len);
288
		if(e->value){
289
			memmove(s, e->value, e->len);
290
			free(e->value);
291
		}
292
		e->value = s;
293
		e->len = len;
294
	}
295
	memmove(e->value+offset, a, n);
296
	e->qid.vers++;
297
	eg->vers++;
298
	wunlock(eg);
299
	return n;
300
}
301
 
302
Dev envdevtab = {
303
	'e',
304
	"env",
305
 
306
	devreset,
307
	devinit,
308
	devshutdown,
309
	envattach,
310
	envwalk,
311
	envstat,
312
	envopen,
313
	envcreate,
314
	envclose,
315
	envread,
316
	devbread,
317
	envwrite,
318
	devbwrite,
319
	envremove,
320
	devwstat,
321
};
322
 
323
void
324
envcpy(Egrp *to, Egrp *from)
325
{
326
	int i;
327
	Evalue *ne, *e;
328
 
329
	rlock(from);
330
	to->ment = (from->nent+31)&~31;
331
	to->ent = smalloc(to->ment*sizeof(to->ent[0]));
332
	for(i=0; i<from->nent; i++){
333
		e = from->ent[i];
334
		ne = smalloc(sizeof(Evalue));
335
		ne->name = smalloc(strlen(e->name)+1);
336
		strcpy(ne->name, e->name);
337
		if(e->value){
338
			ne->value = smalloc(e->len);
339
			memmove(ne->value, e->value, e->len);
340
			ne->len = e->len;
341
		}
342
		ne->qid.path = ++to->path;
343
		to->ent[i] = ne;
344
	}
345
	to->nent = from->nent;
346
	runlock(from);
347
}
348
 
349
void
350
closeegrp(Egrp *eg)
351
{
352
	int i;
353
	Evalue *e;
354
 
355
	if(decref(eg) == 0){
356
		for(i=0; i<eg->nent; i++){
357
			e = eg->ent[i];
358
			free(e->name);
359
			if(e->value)
360
				free(e->value);
361
			free(e);
362
		}
363
		free(eg->ent);
364
		free(eg);
365
	}
366
}
367
 
368
static Egrp*
369
envgrp(Chan *c)
370
{
371
	if(c->aux == nil)
372
		return up->egrp;
373
	return c->aux;
374
}
375
 
376
static int
377
envwriteable(Chan *c)
378
{
379
	return iseve() || c->aux == nil;
380
}
381
 
382
/*
383
 *  to let the kernel set environment variables
384
 */
385
void
386
ksetenv(char *ename, char *eval, int conf)
387
{
388
	Chan *c;
389
	char buf[2*KNAMELEN];
390
 
391
	snprint(buf, sizeof(buf), "#e%s/%s", conf?"c":"", ename);
392
	c = namec(buf, Acreate, OWRITE, 0600);
393
	devtab[c->type]->write(c, eval, strlen(eval), 0);
394
	cclose(c);
395
}
396
 
397
/*
398
 * Return a copy of configuration environment as a sequence of strings.
399
 * The strings alternate between name and value.  A zero length name string
400
 * indicates the end of the list
401
 */
402
char *
403
getconfenv(void)
404
{
405
	Egrp *eg = &confegrp;
406
	Evalue *e;
407
	char *p, *q;
408
	int i, n;
409
 
410
	rlock(eg);
411
	if(waserror()) {
412
		runlock(eg);
413
		nexterror();
414
	}
415
 
416
	/* determine size */
417
	n = 0;
418
	for(i=0; i<eg->nent; i++){
419
		e = eg->ent[i];
420
		n += strlen(e->name) + e->len + 2;
421
	}
422
	p = malloc(n + 1);
423
	if(p == nil)
424
		error(Enomem);
425
	q = p;
426
	for(i=0; i<eg->nent; i++){
427
		e = eg->ent[i];
428
		strcpy(q, e->name);
429
		q += strlen(q) + 1;
430
		memmove(q, e->value, e->len);
431
		q[e->len] = 0;
432
		/* move up to the first null */
433
		q += strlen(q) + 1;
434
	}
435
	*q = 0;
436
 
437
	poperror();
438
	runlock(eg);
439
	return p;
440
}