config.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. /* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
  2. /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
  3. /* Copyright (C) 2014 Stony Brook University
  4. This file is part of Graphene Library OS.
  5. Graphene Library OS is free software: you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public License
  7. as published by the Free Software Foundation, either version 3 of the
  8. License, or (at your option) any later version.
  9. Graphene Library OS is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  15. /*
  16. * config.c
  17. *
  18. * This file contains functions to read app config (manifest) file and create
  19. * a tree to lookup / access config values.
  20. */
  21. #include <list.h>
  22. #include <api.h>
  23. #include <pal_error.h>
  24. DEFINE_LIST(config);
  25. struct config {
  26. const char * key, * val;
  27. size_t klen, vlen; /* for leaf nodes, vlen stores the size of config
  28. values; for branch nodes, vlen stores the sum
  29. of config value lengths plus one of all the
  30. immediate children. */
  31. char * buf;
  32. LIST_TYPE(config) list;
  33. LISTP_TYPE(config) children;
  34. LIST_TYPE(config) siblings;
  35. };
  36. static int __add_config (struct config_store * store,
  37. const char * key, int klen,
  38. const char * val, int vlen,
  39. struct config ** entry)
  40. {
  41. LISTP_TYPE(config) * list = &store->root;
  42. struct config * e = NULL;
  43. struct config * parent = NULL;
  44. while (klen) {
  45. if (e && e->val)
  46. return -PAL_ERROR_INVAL;
  47. const char * token = key;
  48. size_t len = 0;
  49. for ( ; len < klen ; len++)
  50. if (token[len] == '.')
  51. break;
  52. listp_for_each_entry(e, list, siblings)
  53. if (e->klen == len && !memcmp(e->key, token, len))
  54. goto next;
  55. e = store->malloc(sizeof(struct config));
  56. if (!e)
  57. return -PAL_ERROR_NOMEM;
  58. e->key = token;
  59. e->klen = len;
  60. e->val = NULL;
  61. e->vlen = 0;
  62. e->buf = NULL;
  63. INIT_LIST_HEAD(e, list);
  64. listp_add_tail(e, &store->entries, list);
  65. INIT_LISTP(&e->children);
  66. INIT_LIST_HEAD(e, siblings);
  67. listp_add_tail(e, list, siblings);
  68. if (parent)
  69. parent->vlen += (len + 1);
  70. next:
  71. if (len < klen)
  72. len++;
  73. key += len;
  74. klen -= len;
  75. list = &e->children;
  76. parent = e;
  77. }
  78. if (!e || e->val || !listp_empty(&e->children))
  79. return -PAL_ERROR_INVAL;
  80. e->val = val;
  81. e->vlen = vlen;
  82. if (entry)
  83. *entry = e;
  84. return 0;
  85. }
  86. static struct config * __get_config (struct config_store * store,
  87. const char * key)
  88. {
  89. LISTP_TYPE(config) * list = &store->root;
  90. struct config * e = NULL;
  91. while (*key) {
  92. const char * token = key;
  93. int len = 0;
  94. for ( ; token[len] ; len++)
  95. if (token[len] == '.')
  96. break;
  97. listp_for_each_entry(e, list, siblings)
  98. if (e->klen == len && !memcmp(e->key, token, len))
  99. goto next;
  100. return NULL;
  101. next:
  102. if (token[len])
  103. len++;
  104. key += len;
  105. list = &e->children;
  106. }
  107. return e;
  108. }
  109. ssize_t get_config (struct config_store * store, const char * key,
  110. char * val_buf, size_t size)
  111. {
  112. struct config * e = __get_config(store, key);
  113. if (!e || !e->val)
  114. return -PAL_ERROR_INVAL;
  115. if (e->vlen >= size)
  116. return -PAL_ERROR_TOOLONG;
  117. memcpy(val_buf, e->val, e->vlen);
  118. val_buf[e->vlen] = 0;
  119. return e->vlen;
  120. }
  121. int get_config_entries (struct config_store * store, const char * key,
  122. char * key_buf, size_t key_bufsize)
  123. {
  124. struct config * e = __get_config(store, key);
  125. if (!e || e->val)
  126. return -PAL_ERROR_INVAL;
  127. LISTP_TYPE(config) * children = &e->children;
  128. int nentries = 0;
  129. listp_for_each_entry(e, children, siblings) {
  130. if (e->klen + 1 > key_bufsize)
  131. return -PAL_ERROR_TOOLONG;
  132. memcpy(key_buf, e->key, e->klen);
  133. key_buf[e->klen] = 0;
  134. key_buf += e->klen + 1;
  135. key_bufsize -= e->klen + 1;
  136. nentries++;
  137. }
  138. return nentries;
  139. }
  140. ssize_t get_config_entries_size (struct config_store * store,
  141. const char * key)
  142. {
  143. struct config * e = __get_config(store, key);
  144. if (!e || e->val)
  145. return -PAL_ERROR_INVAL;
  146. return e->vlen;
  147. }
  148. static int __del_config (struct config_store * store,
  149. LISTP_TYPE(config) * root,
  150. struct config * p, const char * key)
  151. {
  152. struct config * e, * found = NULL;
  153. int len = 0;
  154. for ( ; key[len] ; len++)
  155. if (key[len] == '.')
  156. break;
  157. listp_for_each_entry(e, root, siblings)
  158. if (e->klen == len && !memcmp(e->key, key, len)) {
  159. found = e;
  160. break;
  161. }
  162. if (!found)
  163. return -PAL_ERROR_INVAL;
  164. if (key[len]) {
  165. if (found->val)
  166. return -PAL_ERROR_INVAL;
  167. int ret = __del_config(store, &found->children, found, key + len + 1);
  168. if (ret < 0)
  169. return ret;
  170. if (!listp_empty(&found->children))
  171. return 0;
  172. } else {
  173. if (!found->val)
  174. return -PAL_ERROR_INVAL;
  175. }
  176. if (p)
  177. p->vlen -= (found->klen + 1);
  178. listp_del(found, root, siblings);
  179. listp_del(found, &store->entries, list);
  180. if (found->buf)
  181. store->free(found->buf);
  182. store->free(found);
  183. return 0;
  184. }
  185. int set_config (struct config_store * store, const char * key, const char * val)
  186. {
  187. if (!key)
  188. return -PAL_ERROR_INVAL;
  189. if (!val) { /* deletion */
  190. return __del_config(store, &store->root, 0, key);
  191. }
  192. int klen = strlen(key);
  193. int vlen = strlen(val);
  194. char * buf = store->malloc(klen + vlen + 2);
  195. if (!buf)
  196. return -PAL_ERROR_NOMEM;
  197. memcpy(buf, key, klen + 1);
  198. memcpy(buf + klen + 1, val, vlen + 1);
  199. struct config * e = __get_config(store, key);
  200. if (e) {
  201. e->val = buf + klen + 1;
  202. e->vlen = vlen;
  203. e->buf = buf;
  204. } else {
  205. int ret = __add_config(store, buf, klen, buf + klen + 1, vlen, &e);
  206. if (ret < 0) {
  207. store->free(buf);
  208. return ret;
  209. }
  210. e->buf = buf;
  211. }
  212. return 0;
  213. }
  214. int read_config (struct config_store * store,
  215. int (*filter) (const char * key, int ken),
  216. const char ** errstring)
  217. {
  218. INIT_LISTP(&store->root);
  219. INIT_LISTP(&store->entries);
  220. char * ptr = store->raw_data;
  221. char * ptr_end = store->raw_data + store->raw_size;
  222. const char * err = "unknown error";
  223. #define IS_SPACE(c) ((c) == ' ' || (c) == '\t')
  224. #define IS_BREAK(c) ((c) == '\r' || (c) == '\n')
  225. #define IS_VALID(c) \
  226. (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z') || \
  227. ((c) >= '0' && (c) <= '9') || (c) == '_')
  228. register int skipping = 0;
  229. #define IS_SKIP(p) \
  230. (skipping ? ({ if (IS_BREAK(*(p))) skipping = 0; 1; }) \
  231. : ((*(p)) == '#' ? ({ skipping = 1; 1; }) : IS_BREAK(*(p))))
  232. #define RANGE (ptr < ptr_end)
  233. #define GOTO_INVAL(msg) ({ err = msg; goto inval; })
  234. #define CHECK_PTR(msg) if (!RANGE) GOTO_INVAL(msg)
  235. while (RANGE) {
  236. for ( ; RANGE && (IS_SKIP(ptr) || IS_SPACE(*ptr)) ; ptr++);
  237. if (!(RANGE))
  238. break;
  239. if (!IS_VALID(*ptr))
  240. GOTO_INVAL("invalid start of key");
  241. char * key = ptr;
  242. for ( ; RANGE ; ptr++) {
  243. char * pptr = ptr;
  244. for ( ; RANGE && IS_VALID(*ptr) ; ptr++);
  245. CHECK_PTR("stream ended at key");
  246. if (pptr == ptr)
  247. GOTO_INVAL("key token with zero length");
  248. if (*ptr != '.')
  249. break;
  250. }
  251. int klen = ptr - key;
  252. for ( ; RANGE && IS_SPACE(*ptr) ; ptr++)
  253. CHECK_PTR("stream ended at key");
  254. if (*ptr != '=')
  255. GOTO_INVAL("equal mark expected");
  256. ptr++;
  257. for ( ; RANGE && IS_SPACE(*ptr) ; ptr++);
  258. CHECK_PTR("stream ended at equal mark");
  259. char * val = NULL;
  260. int vlen;
  261. if (*ptr == '"') {
  262. int shift = 0;
  263. val = (++ptr);
  264. for ( ; RANGE && *ptr != '"' ; ptr++) {
  265. if (*ptr == '\\') {
  266. shift++;
  267. ptr++;
  268. }
  269. if (shift)
  270. *(ptr - shift) = *ptr;
  271. }
  272. CHECK_PTR("stream ended without closing quote");
  273. vlen = (ptr - shift) - val;
  274. } else {
  275. val = ptr;
  276. for ( ; RANGE && !IS_SKIP(ptr) ; ptr++);
  277. vlen = ptr - val;
  278. }
  279. ptr++;
  280. if (!filter || !filter(key, klen)) {
  281. int ret = __add_config(store, key, klen, val, vlen, NULL);
  282. if (ret < 0) {
  283. if (ret == -PAL_ERROR_TOOLONG)
  284. GOTO_INVAL("key too long");
  285. if (ret == -PAL_ERROR_INVAL)
  286. GOTO_INVAL("key format invalid");
  287. GOTO_INVAL("unknown error");
  288. }
  289. }
  290. }
  291. return 0;
  292. inval:
  293. if (errstring)
  294. *errstring = err;
  295. return -PAL_ERROR_INVAL;
  296. }
  297. int free_config (struct config_store * store)
  298. {
  299. struct config * e, * n;
  300. listp_for_each_entry_safe(e, n, &store->entries, list) {
  301. if (e->buf)
  302. store->free(e->buf);
  303. store->free(e);
  304. }
  305. INIT_LISTP(&store->root);
  306. INIT_LISTP(&store->entries);
  307. return 0;
  308. }
  309. static int __dup_config (const struct config_store * ss,
  310. const LISTP_TYPE(config) * sr,
  311. struct config_store * ts,
  312. LISTP_TYPE(config) * tr,
  313. void ** data, int * size)
  314. {
  315. struct config * e, * new;
  316. listp_for_each_entry(e, sr, siblings) {
  317. char * key = NULL, * val = NULL, * buf = NULL;
  318. int need = 0;
  319. if (e->key) {
  320. if (*size > e->klen) {
  321. key = *data;
  322. *data += e->klen;
  323. *size -= e->klen;
  324. memcpy(key, e->key, e->klen);
  325. } else
  326. need += e->klen;
  327. }
  328. if (e->val) {
  329. if (*size > e->vlen) {
  330. val = *data;
  331. *data += e->vlen;
  332. *size -= e->vlen;
  333. memcpy(val, e->val, e->vlen);
  334. } else
  335. need += e->vlen;
  336. }
  337. if (need) {
  338. buf = ts->malloc(need);
  339. if (!buf)
  340. return -PAL_ERROR_NOMEM;
  341. }
  342. if (e->key && !key) {
  343. key = buf;
  344. memcpy(key, e->key, e->klen);
  345. }
  346. if (e->val && !val) {
  347. val = buf + (key == buf ? e->klen : 0);
  348. memcpy(val, e->val, e->vlen);
  349. }
  350. new = ts->malloc(sizeof(struct config));
  351. if (!new)
  352. return -PAL_ERROR_NOMEM;
  353. new->key = key;
  354. new->klen = e->klen;
  355. new->val = val;
  356. new->vlen = e->vlen;
  357. new->buf = buf;
  358. INIT_LIST_HEAD(new, list);
  359. listp_add_tail(new, &ts->entries, list);
  360. INIT_LISTP(&new->children);
  361. INIT_LIST_HEAD(new, siblings);
  362. listp_add_tail(new, tr, siblings);
  363. if (!listp_empty(&e->children)) {
  364. int ret = __dup_config(ss, &e->children,
  365. ts, &new->children,
  366. data, size);
  367. if (ret < 0)
  368. return ret;
  369. }
  370. }
  371. return 0;
  372. }
  373. int copy_config (struct config_store * store, struct config_store * new_store)
  374. {
  375. INIT_LISTP(&new_store->root);
  376. INIT_LISTP(&new_store->entries);
  377. struct config * e;
  378. int size = 0;
  379. listp_for_each_entry(e, &store->entries, list) {
  380. if (e->key)
  381. size += e->klen;
  382. if (e->val)
  383. size += e->vlen;
  384. }
  385. void * data = new_store->malloc(size);
  386. if (!data)
  387. return -PAL_ERROR_NOMEM;
  388. void * dataptr = data;
  389. int datasz = size;
  390. new_store->raw_data = data;
  391. new_store->raw_size = size;
  392. return __dup_config(store, &store->root, new_store, &new_store->root,
  393. &dataptr, &datasz);
  394. }
  395. static int __write_config (void * f, int (*write) (void *, void *, int),
  396. struct config_store * store,
  397. LISTP_TYPE(config) * root,
  398. char * keybuf, int klen,
  399. unsigned long * offset)
  400. {
  401. struct config * e;
  402. int ret;
  403. char * buf = NULL;
  404. int bufsz = 0;
  405. listp_for_each_entry(e, root, siblings)
  406. if (e->val) {
  407. int total = klen + e->klen + e->vlen + 2;
  408. while (total > bufsz) {
  409. bufsz += CONFIG_MAX;
  410. buf = __alloca(CONFIG_MAX);
  411. }
  412. memcpy(buf, keybuf, klen);
  413. memcpy(buf + klen, e->key, e->klen);
  414. buf[klen + e->klen] = '=';
  415. memcpy(buf + total - e->vlen - 1, e->val, e->vlen);
  416. buf[total - 1] = '\n';
  417. ret = write(f, buf, total);
  418. if (ret < 0)
  419. return ret;
  420. *offset += total;
  421. } else {
  422. if (klen + e->klen + 1 > CONFIG_MAX)
  423. return -PAL_ERROR_TOOLONG;
  424. memcpy(keybuf + klen, e->key, e->klen);
  425. keybuf[klen + e->klen] = '.';
  426. if ((ret = __write_config(f, write, store, &e->children, keybuf,
  427. klen + e->klen + 1, offset)) < 0)
  428. return ret;
  429. }
  430. return 0;
  431. }
  432. int write_config (void * f, int (*write) (void *, void *, int),
  433. struct config_store * store)
  434. {
  435. char buf[CONFIG_MAX];
  436. unsigned long offset = 0;
  437. return __write_config(f, write, store, &store->root, buf, 0, &offset);
  438. }