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