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*
envlookup(Egrp * eg,char * name,ulong qidpath)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
envgen(Chan * c,char * name,Dirtab *,int,int s,Dir * dp)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*
envattach(char * spec)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*
envwalk(Chan * c,Chan * nc,char ** name,int nname)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
envstat(Chan * c,uchar * db,int n)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*
envopen(Chan * c,int omode)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
envcreate(Chan * c,char * name,int omode,ulong)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
envremove(Chan * c)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
envclose(Chan * c)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
envread(Chan * c,void * a,long n,vlong off)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
envwrite(Chan * c,void * a,long n,vlong off)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
envcpy(Egrp * to,Egrp * from)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
closeegrp(Egrp * eg)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*
envgrp(Chan * c)369 envgrp(Chan *c)
370 {
371 if(c->aux == nil)
372 return up->egrp;
373 return c->aux;
374 }
375
376 static int
envwriteable(Chan * c)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
ksetenv(char * ename,char * eval,int conf)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 *
getconfenv(void)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 }
441