devenv.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "u.h"
  10. #include "../port/lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include "../port/error.h"
  15. enum
  16. {
  17. Maxenvsize = 16300,
  18. };
  19. static Egrp *envgrp(Chan *c);
  20. static int envwriteable(Chan *c);
  21. static Egrp confegrp; /* global environment group containing the kernel configuration */
  22. static Evalue*
  23. envlookup(Egrp *eg, char *name, uint32_t qidpath)
  24. {
  25. Evalue *e;
  26. int i;
  27. for(i=0; i<eg->nent; i++){
  28. e = eg->ent[i];
  29. if(e->qid.path == qidpath || (name && e->name[0]==name[0] && strcmp(e->name, name) == 0))
  30. return e;
  31. }
  32. return nil;
  33. }
  34. static int
  35. envgen(Chan *c, char *name, Dirtab* dir, int i, int s, Dir *dp)
  36. {
  37. Proc *up = externup();
  38. Egrp *eg;
  39. Evalue *e;
  40. if(s == DEVDOTDOT){
  41. devdir(c, c->qid, "#e", 0, eve, DMDIR|0775, dp);
  42. return 1;
  43. }
  44. eg = envgrp(c);
  45. rlock(&eg->rwl);
  46. e = 0;
  47. if(name)
  48. e = envlookup(eg, name, -1);
  49. else if(s < eg->nent)
  50. e = eg->ent[s];
  51. if(e == 0) {
  52. runlock(&eg->rwl);
  53. return -1;
  54. }
  55. /* make sure name string continues to exist after we release lock */
  56. kstrcpy(up->genbuf, e->name, sizeof up->genbuf);
  57. devdir(c, e->qid, up->genbuf, e->len, eve, 0666, dp);
  58. runlock(&eg->rwl);
  59. return 1;
  60. }
  61. static Chan*
  62. envattach(char *spec)
  63. {
  64. Chan *c;
  65. Egrp *egrp = nil;
  66. if(spec && *spec) {
  67. if(strcmp(spec, "c") == 0)
  68. egrp = &confegrp;
  69. if(egrp == nil)
  70. error(Ebadarg);
  71. }
  72. c = devattach('e', spec);
  73. c->aux = egrp;
  74. return c;
  75. }
  76. static Walkqid*
  77. envwalk(Chan *c, Chan *nc, char **name, int nname)
  78. {
  79. return devwalk(c, nc, name, nname, 0, 0, envgen);
  80. }
  81. static int32_t
  82. envstat(Chan *c, uint8_t *db, int32_t n)
  83. {
  84. if(c->qid.type & QTDIR)
  85. c->qid.vers = envgrp(c)->vers;
  86. return devstat(c, db, n, 0, 0, envgen);
  87. }
  88. static Chan*
  89. envopen(Chan *c, int omode)
  90. {
  91. Egrp *eg;
  92. Evalue *e;
  93. int trunc;
  94. eg = envgrp(c);
  95. if(c->qid.type & QTDIR) {
  96. if(omode != OREAD)
  97. error(Eperm);
  98. }
  99. else {
  100. trunc = omode & OTRUNC;
  101. if(omode != OREAD && !envwriteable(c))
  102. error(Eperm);
  103. if(trunc)
  104. wlock(&eg->rwl);
  105. else
  106. rlock(&eg->rwl);
  107. e = envlookup(eg, nil, c->qid.path);
  108. if(e == 0) {
  109. if(trunc)
  110. wunlock(&eg->rwl);
  111. else
  112. runlock(&eg->rwl);
  113. error(Enonexist);
  114. }
  115. if(trunc && e->value) {
  116. e->qid.vers++;
  117. free(e->value);
  118. e->value = 0;
  119. e->len = 0;
  120. }
  121. if(trunc)
  122. wunlock(&eg->rwl);
  123. else
  124. runlock(&eg->rwl);
  125. }
  126. c->mode = openmode(omode);
  127. c->flag |= COPEN;
  128. c->offset = 0;
  129. return c;
  130. }
  131. static void
  132. envcreate(Chan *c, char *name, int omode, int i)
  133. {
  134. Proc *up = externup();
  135. Egrp *eg;
  136. Evalue *e;
  137. Evalue **ent;
  138. if(c->qid.type != QTDIR)
  139. error(Eperm);
  140. omode = openmode(omode);
  141. eg = envgrp(c);
  142. wlock(&eg->rwl);
  143. if(waserror()) {
  144. wunlock(&eg->rwl);
  145. nexterror();
  146. }
  147. if(envlookup(eg, name, -1))
  148. error(Eexist);
  149. e = smalloc(sizeof(Evalue));
  150. e->name = smalloc(strlen(name)+1);
  151. strcpy(e->name, name);
  152. if(eg->nent == eg->ment){
  153. eg->ment += 32;
  154. ent = smalloc(sizeof(eg->ent[0])*eg->ment);
  155. if(eg->nent)
  156. memmove(ent, eg->ent, sizeof(eg->ent[0])*eg->nent);
  157. free(eg->ent);
  158. eg->ent = ent;
  159. }
  160. e->qid.path = ++eg->path;
  161. e->qid.vers = 0;
  162. eg->vers++;
  163. eg->ent[eg->nent++] = e;
  164. c->qid = e->qid;
  165. wunlock(&eg->rwl);
  166. poperror();
  167. c->offset = 0;
  168. c->mode = omode;
  169. c->flag |= COPEN;
  170. }
  171. static void
  172. envremove(Chan *c)
  173. {
  174. int i;
  175. Egrp *eg;
  176. Evalue *e;
  177. if(c->qid.type & QTDIR)
  178. error(Eperm);
  179. eg = envgrp(c);
  180. wlock(&eg->rwl);
  181. e = 0;
  182. for(i=0; i<eg->nent; i++){
  183. if(eg->ent[i]->qid.path == c->qid.path){
  184. e = eg->ent[i];
  185. eg->nent--;
  186. eg->ent[i] = eg->ent[eg->nent];
  187. eg->vers++;
  188. break;
  189. }
  190. }
  191. wunlock(&eg->rwl);
  192. if(e == 0)
  193. error(Enonexist);
  194. free(e->name);
  195. if(e->value)
  196. free(e->value);
  197. free(e);
  198. }
  199. static void
  200. envclose(Chan *c)
  201. {
  202. /*
  203. * cclose can't fail, so errors from remove will be ignored.
  204. * since permissions aren't checked,
  205. * envremove can't not remove it if its there.
  206. */
  207. if(c->flag & CRCLOSE)
  208. envremove(c);
  209. }
  210. static int32_t
  211. envread(Chan *c, void *a, int32_t n, int64_t off)
  212. {
  213. Egrp *eg;
  214. Evalue *e;
  215. int32_t offset;
  216. if(c->qid.type & QTDIR)
  217. return devdirread(c, a, n, 0, 0, envgen);
  218. eg = envgrp(c);
  219. rlock(&eg->rwl);
  220. e = envlookup(eg, nil, c->qid.path);
  221. if(e == 0) {
  222. runlock(&eg->rwl);
  223. error(Enonexist);
  224. }
  225. offset = off;
  226. if(offset > e->len) /* protects against overflow converting int64_t to long */
  227. n = 0;
  228. else if(offset + n > e->len)
  229. n = e->len - offset;
  230. if(n <= 0)
  231. n = 0;
  232. else
  233. memmove(a, e->value+offset, n);
  234. runlock(&eg->rwl);
  235. return n;
  236. }
  237. static int32_t
  238. envwrite(Chan *c, void *a, int32_t n, int64_t off)
  239. {
  240. char *s;
  241. Egrp *eg;
  242. Evalue *e;
  243. int32_t len, offset;
  244. if(n <= 0)
  245. return 0;
  246. offset = off;
  247. if(offset > Maxenvsize || n > (Maxenvsize - offset))
  248. error(Etoobig);
  249. eg = envgrp(c);
  250. wlock(&eg->rwl);
  251. e = envlookup(eg, nil, c->qid.path);
  252. if(e == 0) {
  253. wunlock(&eg->rwl);
  254. error(Enonexist);
  255. }
  256. len = offset+n;
  257. if(len > e->len) {
  258. s = smalloc(len);
  259. if(e->value){
  260. memmove(s, e->value, e->len);
  261. free(e->value);
  262. }
  263. e->value = s;
  264. e->len = len;
  265. }
  266. memmove(e->value+offset, a, n);
  267. e->qid.vers++;
  268. eg->vers++;
  269. wunlock(&eg->rwl);
  270. return n;
  271. }
  272. Dev envdevtab = {
  273. .dc = 'e',
  274. .name = "env",
  275. .reset = devreset,
  276. .init = devinit,
  277. .shutdown = devshutdown,
  278. .attach = envattach,
  279. .walk = envwalk,
  280. .stat = envstat,
  281. .open = envopen,
  282. .create = envcreate,
  283. .close = envclose,
  284. .read = envread,
  285. .bread = devbread,
  286. .write = envwrite,
  287. .bwrite = devbwrite,
  288. .remove = envremove,
  289. .wstat = devwstat,
  290. };
  291. void
  292. envcpy(Egrp *to, Egrp *from)
  293. {
  294. int i;
  295. Evalue *ne, *e;
  296. rlock(&from->rwl);
  297. to->ment = (from->nent+31)&~31;
  298. to->ent = smalloc(to->ment*sizeof(to->ent[0]));
  299. for(i=0; i<from->nent; i++){
  300. e = from->ent[i];
  301. ne = smalloc(sizeof(Evalue));
  302. ne->name = smalloc(strlen(e->name)+1);
  303. strcpy(ne->name, e->name);
  304. if(e->value){
  305. ne->value = smalloc(e->len);
  306. memmove(ne->value, e->value, e->len);
  307. ne->len = e->len;
  308. }
  309. ne->qid.path = ++to->path;
  310. to->ent[i] = ne;
  311. }
  312. to->nent = from->nent;
  313. runlock(&from->rwl);
  314. }
  315. void
  316. closeegrp(Egrp *eg)
  317. {
  318. int i;
  319. Evalue *e;
  320. if(decref(&eg->r) == 0){
  321. for(i=0; i<eg->nent; i++){
  322. e = eg->ent[i];
  323. free(e->name);
  324. if(e->value)
  325. free(e->value);
  326. free(e);
  327. }
  328. free(eg->ent);
  329. free(eg);
  330. }
  331. }
  332. static Egrp*
  333. envgrp(Chan *c)
  334. {
  335. Proc *up = externup();
  336. if(c->aux == nil)
  337. return up->egrp;
  338. return c->aux;
  339. }
  340. static int
  341. envwriteable(Chan *c)
  342. {
  343. return iseve() || c->aux == nil;
  344. }
  345. /*
  346. * to let the kernel set environment variables
  347. */
  348. void
  349. ksetenv(char *ename, char *eval, int conf)
  350. {
  351. Chan *c;
  352. char buf[2*KNAMELEN];
  353. snprint(buf, sizeof(buf), "#e%s/%s", conf?"c":"", ename);
  354. c = namec(buf, Acreate, OWRITE, 0600);
  355. c->dev->write(c, eval, strlen(eval), 0);
  356. cclose(c);
  357. }
  358. /*
  359. * Return a copy of configuration environment as a sequence of strings.
  360. * The strings alternate between name and value. A zero length name string
  361. * indicates the end of the list
  362. */
  363. char *
  364. getconfenv(void)
  365. {
  366. Proc *up = externup();
  367. Egrp *eg = &confegrp;
  368. Evalue *e;
  369. char *p, *q;
  370. int i, n;
  371. rlock(&eg->rwl);
  372. if(waserror()) {
  373. runlock(&eg->rwl);
  374. nexterror();
  375. }
  376. /* determine size */
  377. n = 0;
  378. for(i=0; i<eg->nent; i++){
  379. e = eg->ent[i];
  380. n += strlen(e->name) + e->len + 2;
  381. }
  382. p = malloc(n + 1);
  383. if(p == nil)
  384. error(Enomem);
  385. q = p;
  386. for(i=0; i<eg->nent; i++){
  387. e = eg->ent[i];
  388. strcpy(q, e->name);
  389. q += strlen(q) + 1;
  390. memmove(q, e->value, e->len);
  391. q[e->len] = 0;
  392. /* move up to the first null */
  393. q += strlen(q) + 1;
  394. }
  395. *q = 0;
  396. poperror();
  397. runlock(&eg->rwl);
  398. return p;
  399. }