devenv.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       devenv.c (7140B)
       ---
            1 #include        "u.h"
            2 #include        "lib.h"
            3 #include        "mem.h"
            4 #include        "dat.h"
            5 #include        "fns.h"
            6 #include        "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 *dt, int i, 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->lk);
           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->lk);
           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->lk);
           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->lk);
          113                 else
          114                         rlock(&eg->lk);
          115                 e = envlookup(eg, nil, c->qid.path);
          116                 if(e == 0) {
          117                         if(trunc)
          118                                 wunlock(&eg->lk);
          119                         else
          120                                 runlock(&eg->lk);
          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->lk);
          131                 else
          132                         runlock(&eg->lk);
          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 perm)
          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->lk);
          154         if(waserror()) {
          155                 wunlock(&eg->lk);
          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->lk);
          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->lk);
          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->lk);
          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->lk);
          243         e = envlookup(eg, nil, c->qid.path);
          244         if(e == 0) {
          245                 runlock(&eg->lk);
          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->lk);
          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->lk);
          277         e = envlookup(eg, nil, c->qid.path);
          278         if(e == 0) {
          279                 wunlock(&eg->lk);
          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->lk);
          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->lk);
          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->lk);
          345 }
          346 
          347 void
          348 closeegrp(Egrp *eg)
          349 {
          350         int i;
          351         Evalue *e;
          352 
          353         if(decref(&eg->ref) == 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->lk);
          409         if(waserror()) {
          410                 runlock(&eg->lk);
          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->lk);
          437         return p;
          438 }