FreeBSD/Linux Kernel Cross Reference
sys/port/devenv.c
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
150 omode = openmode(omode);
151 eg = envgrp(c);
152
153 wlock(eg);
154 if(waserror()) {
155 wunlock(eg);
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);
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);
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);
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);
243 e = envlookup(eg, nil, c->qid.path);
244 if(e == 0) {
245 runlock(eg);
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);
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);
277 e = envlookup(eg, nil, c->qid.path);
278 if(e == 0) {
279 wunlock(eg);
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);
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);
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);
345 }
346
347 void
348 closeegrp(Egrp *eg)
349 {
350 int i;
351 Evalue *e;
352
353 if(decref(eg) == 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);
409 if(waserror()) {
410 runlock(eg);
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);
437 return p;
438 }
Cache object: c77f0143b97cd2000c77b8cdfe5cd355
|