devenv.c 7.3 KB

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