devenv.c 6.9 KB

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