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 long
envstat(Chan * c,uchar * db,long n)88 envstat(Chan *c, uchar *db, long 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,int)141 envcreate(Chan *c, char *name, int omode, int)
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 long offset;
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 offset = off;
252 if(offset > e->len) /* protects against overflow converting vlong to long */
253 n = 0;
254 else if(offset + n > e->len)
255 n = e->len - offset;
256 if(n <= 0)
257 n = 0;
258 else
259 memmove(a, e->value+offset, n);
260 runlock(eg);
261 return n;
262 }
263
264 static long
envwrite(Chan * c,void * a,long n,vlong off)265 envwrite(Chan *c, void *a, long n, vlong off)
266 {
267 char *s;
268 Egrp *eg;
269 Evalue *e;
270 long len, offset;
271
272 if(n <= 0)
273 return 0;
274 offset = off;
275 if(offset > Maxenvsize || n > (Maxenvsize - offset))
276 error(Etoobig);
277
278 eg = envgrp(c);
279 wlock(eg);
280 e = envlookup(eg, nil, c->qid.path);
281 if(e == 0) {
282 wunlock(eg);
283 error(Enonexist);
284 }
285
286 len = offset+n;
287 if(len > e->len) {
288 s = smalloc(len);
289 if(e->value){
290 memmove(s, e->value, e->len);
291 free(e->value);
292 }
293 e->value = s;
294 e->len = len;
295 }
296 memmove(e->value+offset, a, n);
297 e->qid.vers++;
298 eg->vers++;
299 wunlock(eg);
300 return n;
301 }
302
303 Dev envdevtab = {
304 'e',
305 "env",
306
307 devreset,
308 devinit,
309 devshutdown,
310 envattach,
311 envwalk,
312 envstat,
313 envopen,
314 envcreate,
315 envclose,
316 envread,
317 devbread,
318 envwrite,
319 devbwrite,
320 envremove,
321 devwstat,
322 };
323
324 void
envcpy(Egrp * to,Egrp * from)325 envcpy(Egrp *to, Egrp *from)
326 {
327 int i;
328 Evalue *ne, *e;
329
330 rlock(from);
331 to->ment = (from->nent+31)&~31;
332 to->ent = smalloc(to->ment*sizeof(to->ent[0]));
333 for(i=0; i<from->nent; i++){
334 e = from->ent[i];
335 ne = smalloc(sizeof(Evalue));
336 ne->name = smalloc(strlen(e->name)+1);
337 strcpy(ne->name, e->name);
338 if(e->value){
339 ne->value = smalloc(e->len);
340 memmove(ne->value, e->value, e->len);
341 ne->len = e->len;
342 }
343 ne->qid.path = ++to->path;
344 to->ent[i] = ne;
345 }
346 to->nent = from->nent;
347 runlock(from);
348 }
349
350 void
closeegrp(Egrp * eg)351 closeegrp(Egrp *eg)
352 {
353 int i;
354 Evalue *e;
355
356 if(decref(eg) == 0){
357 for(i=0; i<eg->nent; i++){
358 e = eg->ent[i];
359 free(e->name);
360 if(e->value)
361 free(e->value);
362 free(e);
363 }
364 free(eg->ent);
365 free(eg);
366 }
367 }
368
369 static Egrp*
envgrp(Chan * c)370 envgrp(Chan *c)
371 {
372 if(c->aux == nil)
373 return up->egrp;
374 return c->aux;
375 }
376
377 static int
envwriteable(Chan * c)378 envwriteable(Chan *c)
379 {
380 return iseve() || c->aux == nil;
381 }
382
383 /*
384 * to let the kernel set environment variables
385 */
386 void
ksetenv(char * ename,char * eval,int conf)387 ksetenv(char *ename, char *eval, int conf)
388 {
389 Chan *c;
390 char buf[2*KNAMELEN];
391
392 snprint(buf, sizeof(buf), "#e%s/%s", conf?"c":"", ename);
393 c = namec(buf, Acreate, OWRITE, 0600);
394 c->dev->write(c, eval, strlen(eval), 0);
395 cclose(c);
396 }
397
398 /*
399 * Return a copy of configuration environment as a sequence of strings.
400 * The strings alternate between name and value. A zero length name string
401 * indicates the end of the list
402 */
403 char *
getconfenv(void)404 getconfenv(void)
405 {
406 Egrp *eg = &confegrp;
407 Evalue *e;
408 char *p, *q;
409 int i, n;
410
411 rlock(eg);
412 if(waserror()) {
413 runlock(eg);
414 nexterror();
415 }
416
417 /* determine size */
418 n = 0;
419 for(i=0; i<eg->nent; i++){
420 e = eg->ent[i];
421 n += strlen(e->name) + e->len + 2;
422 }
423 p = malloc(n + 1);
424 if(p == nil)
425 error(Enomem);
426 q = p;
427 for(i=0; i<eg->nent; i++){
428 e = eg->ent[i];
429 strcpy(q, e->name);
430 q += strlen(q) + 1;
431 memmove(q, e->value, e->len);
432 q[e->len] = 0;
433 /* move up to the first null */
434 q += strlen(q) + 1;
435 }
436 *q = 0;
437
438 poperror();
439 runlock(eg);
440 return p;
441 }
442