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 }