config.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  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 OSCAR lab, 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 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 General Public License for more details.
  13. You should have received a copy of the GNU 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. int klen, vlen;
  28. int entries_size;
  29. char * buf;
  30. LIST_TYPE(config) list;
  31. LISTP_TYPE(config) children;
  32. LIST_TYPE(config) siblings;
  33. };
  34. static int __add_config (struct config_store * store,
  35. const char * key, int klen,
  36. const char * val, int vlen,
  37. struct config ** entry)
  38. {
  39. LISTP_TYPE(config) * list = &store->root;
  40. struct config * e = NULL;
  41. struct config * parent = NULL;
  42. while (klen) {
  43. if (e && e->val)
  44. return -PAL_ERROR_INVAL;
  45. const char * token = key;
  46. int len = 0;
  47. for ( ; len < klen ; len++)
  48. if (token[len] == '.')
  49. break;
  50. listp_for_each_entry(e, list, siblings)
  51. if (e->klen == len && !memcmp(e->key, token, len))
  52. goto next;
  53. e = store->malloc(sizeof(struct config));
  54. if (!e)
  55. return -PAL_ERROR_NOMEM;
  56. e->key = token;
  57. e->klen = len;
  58. e->val = NULL;
  59. e->vlen = 0;
  60. e->buf = NULL;
  61. e->entries_size = 0;
  62. INIT_LIST_HEAD(e, list);
  63. listp_add_tail(e, &store->entries, list);
  64. INIT_LISTP(&e->children);
  65. INIT_LIST_HEAD(e, siblings);
  66. listp_add_tail(e, list, siblings);
  67. if (parent)
  68. parent->entries_size += (len + 1);
  69. next:
  70. if (len < klen)
  71. len++;
  72. key += len;
  73. klen -= len;
  74. list = &e->children;
  75. parent = e;
  76. }
  77. if (!e || e->val || !listp_empty(&e->children))
  78. return -PAL_ERROR_INVAL;
  79. e->val = val;
  80. e->vlen = vlen;
  81. if (entry)
  82. *entry = e;
  83. return 0;
  84. }
  85. static struct config * __get_config (struct config_store * store,
  86. const char * key)
  87. {
  88. LISTP_TYPE(config) * list = &store->root;
  89. struct config * e = NULL;
  90. while (*key) {
  91. const char * token = key;
  92. int len = 0;
  93. for ( ; token[len] ; len++)
  94. if (token[len] == '.')
  95. break;
  96. listp_for_each_entry(e, list, siblings)
  97. if (e->klen == len && !memcmp(e->key, token, len))
  98. goto next;
  99. return NULL;
  100. next:
  101. if (token[len])
  102. len++;
  103. key += len;
  104. list = &e->children;
  105. }
  106. return e;
  107. }
  108. int get_config (struct config_store * store, const char * key,
  109. char * val_buf, int size)
  110. {
  111. struct config * e = __get_config(store, key);
  112. if (!e || !e->val)
  113. return -PAL_ERROR_INVAL;
  114. if (e->vlen >= size)
  115. return -PAL_ERROR_TOOLONG;
  116. memcpy(val_buf, e->val, e->vlen);
  117. val_buf[e->vlen] = 0;
  118. return e->vlen;
  119. }
  120. int get_config_entries (struct config_store * store, const char * key,
  121. char * key_buf)
  122. {
  123. struct config * e = __get_config(store, key);
  124. if (!e || e->val)
  125. return -PAL_ERROR_INVAL;
  126. LISTP_TYPE(config) * children = &e->children;
  127. int nentries = 0;
  128. listp_for_each_entry(e, children, siblings) {
  129. memcpy(key_buf, e->key, e->klen);
  130. key_buf[e->klen] = 0;
  131. key_buf += e->klen + 1;
  132. nentries++;
  133. }
  134. return nentries;
  135. }
  136. int get_config_entries_size (struct config_store * store, const char * key)
  137. {
  138. struct config * e = __get_config(store, key);
  139. if (!e || e->val)
  140. return -PAL_ERROR_INVAL;
  141. return e->entries_size;
  142. }
  143. static int __del_config (struct config_store * store,
  144. LISTP_TYPE(config) * root, struct config * p,
  145. const char * key)
  146. {
  147. struct config * e, * found = NULL;
  148. int len = 0;
  149. for ( ; key[len] ; len++)
  150. if (key[len] == '.')
  151. break;
  152. listp_for_each_entry(e, root, siblings)
  153. if (e->klen == len && !memcmp(e->key, key, len)) {
  154. found = e;
  155. break;
  156. }
  157. if (!found)
  158. return -PAL_ERROR_INVAL;
  159. if (key[len]) {
  160. if (found->val)
  161. return -PAL_ERROR_INVAL;
  162. int ret = __del_config(store, &found->children, found, key + len + 1);
  163. if (ret < 0)
  164. return ret;
  165. if (!listp_empty(&found->children))
  166. return 0;
  167. } else {
  168. if (!found->val)
  169. return -PAL_ERROR_INVAL;
  170. }
  171. if (p)
  172. p->entries_size -= (found->klen + 1);
  173. listp_del(found, root, siblings);
  174. listp_del(found, &store->entries, list);
  175. if (found->buf)
  176. store->free(found->buf);
  177. store->free(found);
  178. return 0;
  179. }
  180. int set_config (struct config_store * store, const char * key, const char * val)
  181. {
  182. if (!key)
  183. return -PAL_ERROR_INVAL;
  184. if (!val) { /* deletion */
  185. return __del_config(store, &store->root, 0, key);
  186. }
  187. int klen = strlen(key);
  188. int vlen = strlen(val);
  189. char * buf = store->malloc(klen + vlen + 2);
  190. if (!buf)
  191. return -PAL_ERROR_NOMEM;
  192. memcpy(buf, key, klen + 1);
  193. memcpy(buf + klen + 1, val, vlen + 1);
  194. struct config * e = __get_config(store, key);
  195. if (e) {
  196. e->val = buf + klen + 1;
  197. e->vlen = vlen;
  198. e->buf = buf;
  199. } else {
  200. int ret = __add_config(store, buf, klen, buf + klen + 1, vlen, &e);
  201. if (ret < 0) {
  202. store->free(buf);
  203. return ret;
  204. }
  205. e->buf = buf;
  206. }
  207. return 0;
  208. }
  209. int read_config (struct config_store * store,
  210. int (*filter) (const char * key, int ken),
  211. const char ** errstring)
  212. {
  213. INIT_LISTP(&store->root);
  214. INIT_LISTP(&store->entries);
  215. char * ptr = store->raw_data;
  216. char * ptr_end = store->raw_data + store->raw_size;
  217. const char * err = "unknown error";
  218. #define IS_SPACE(c) ((c) == ' ' || (c) == '\t')
  219. #define IS_BREAK(c) ((c) == '\r' || (c) == '\n')
  220. #define IS_VALID(c) \
  221. (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z') || \
  222. ((c) >= '0' && (c) <= '9') || (c) == '_')
  223. register int skipping = 0;
  224. #define IS_SKIP(p) \
  225. (skipping ? ({ if (IS_BREAK(*(p))) skipping = 0; 1; }) \
  226. : ((*(p)) == '#' ? ({ skipping = 1; 1; }) : IS_BREAK(*(p))))
  227. #define RANGE (ptr < ptr_end)
  228. #define GOTO_INVAL(msg) ({ err = msg; goto inval; })
  229. #define CHECK_PTR(msg) if (!RANGE) GOTO_INVAL(msg)
  230. while (RANGE) {
  231. for ( ; RANGE && (IS_SKIP(ptr) || IS_SPACE(*ptr)) ; ptr++);
  232. if (!(RANGE))
  233. break;
  234. if (!IS_VALID(*ptr))
  235. GOTO_INVAL("invalid start of key");
  236. char * key = ptr;
  237. for ( ; RANGE ; ptr++) {
  238. char * pptr = ptr;
  239. for ( ; RANGE && IS_VALID(*ptr) ; ptr++);
  240. CHECK_PTR("stream ended at key");
  241. if (pptr == ptr)
  242. GOTO_INVAL("key token with zero length");
  243. if (*ptr != '.')
  244. break;
  245. }
  246. int klen = ptr - key;
  247. for ( ; RANGE && IS_SPACE(*ptr) ; ptr++)
  248. CHECK_PTR("stream ended at key");
  249. if (*ptr != '=')
  250. GOTO_INVAL("equal mark expected");
  251. ptr++;
  252. for ( ; RANGE && IS_SPACE(*ptr) ; ptr++);
  253. CHECK_PTR("stream ended at equal mark");
  254. char * val = NULL;
  255. int vlen;
  256. if (*ptr == '"') {
  257. int shift = 0;
  258. val = (++ptr);
  259. for ( ; RANGE && *ptr != '"' ; ptr++) {
  260. if (*ptr == '\\') {
  261. shift++;
  262. ptr++;
  263. }
  264. if (shift)
  265. *(ptr - shift) = *ptr;
  266. }
  267. CHECK_PTR("stream ended without closing quote");
  268. vlen = (ptr - shift) - val;
  269. } else {
  270. val = ptr;
  271. for ( ; RANGE && !IS_SKIP(ptr) ; ptr++);
  272. vlen = ptr - val;
  273. }
  274. ptr++;
  275. if (!filter || !filter(key, klen)) {
  276. int ret = __add_config(store, key, klen, val, vlen, NULL);
  277. if (ret < 0) {
  278. if (ret == -PAL_ERROR_TOOLONG)
  279. GOTO_INVAL("key too long");
  280. if (ret == -PAL_ERROR_INVAL)
  281. GOTO_INVAL("key format invalid");
  282. GOTO_INVAL("unknown error");
  283. }
  284. }
  285. }
  286. return 0;
  287. inval:
  288. if (errstring)
  289. *errstring = err;
  290. return -PAL_ERROR_INVAL;
  291. }
  292. int free_config (struct config_store * store)
  293. {
  294. struct config * e, * n;
  295. listp_for_each_entry_safe(e, n, &store->entries, list) {
  296. if (e->buf)
  297. store->free(e->buf);
  298. store->free(e);
  299. }
  300. INIT_LISTP(&store->root);
  301. INIT_LISTP(&store->entries);
  302. return 0;
  303. }
  304. static int __dup_config (const struct config_store * ss,
  305. const LISTP_TYPE(config) * sr,
  306. struct config_store * ts,
  307. LISTP_TYPE(config) * tr,
  308. void ** data, int * size)
  309. {
  310. struct config * e, * new;
  311. listp_for_each_entry(e, sr, siblings) {
  312. char * key = NULL, * val = NULL, * buf = NULL;
  313. int need = 0;
  314. if (e->key) {
  315. if (*size > e->klen) {
  316. key = *data;
  317. *data += e->klen;
  318. *size -= e->klen;
  319. memcpy(key, e->key, e->klen);
  320. } else
  321. need += e->klen;
  322. }
  323. if (e->val) {
  324. if (*size > e->vlen) {
  325. val = *data;
  326. *data += e->vlen;
  327. *size -= e->vlen;
  328. memcpy(val, e->val, e->vlen);
  329. } else
  330. need += e->vlen;
  331. }
  332. if (need) {
  333. buf = ts->malloc(need);
  334. if (!buf)
  335. return -PAL_ERROR_NOMEM;
  336. }
  337. if (e->key && !key) {
  338. key = buf;
  339. memcpy(key, e->key, e->klen);
  340. }
  341. if (e->val && !val) {
  342. val = buf + (key == buf ? e->klen : 0);
  343. memcpy(val, e->val, e->vlen);
  344. }
  345. new = ts->malloc(sizeof(struct config));
  346. if (!new)
  347. return -PAL_ERROR_NOMEM;
  348. new->key = key;
  349. new->klen = e->klen;
  350. new->val = val;
  351. new->vlen = e->vlen;
  352. new->buf = buf;
  353. new->entries_size = e->entries_size;
  354. INIT_LIST_HEAD(new, list);
  355. listp_add_tail(new, &ts->entries, list);
  356. INIT_LISTP(&new->children);
  357. INIT_LIST_HEAD(new, siblings);
  358. listp_add_tail(new, tr, siblings);
  359. if (!listp_empty(&e->children)) {
  360. int ret = __dup_config(ss, &e->children,
  361. ts, &new->children,
  362. data, size);
  363. if (ret < 0)
  364. return ret;
  365. }
  366. }
  367. return 0;
  368. }
  369. int copy_config (struct config_store * store, struct config_store * new_store)
  370. {
  371. INIT_LISTP(&new_store->root);
  372. INIT_LISTP(&new_store->entries);
  373. struct config * e;
  374. int size = 0;
  375. listp_for_each_entry(e, &store->entries, list) {
  376. if (e->key)
  377. size += e->klen;
  378. if (e->val)
  379. size += e->vlen;
  380. }
  381. void * data = new_store->malloc(size);
  382. if (!data)
  383. return -PAL_ERROR_NOMEM;
  384. void * dataptr = data;
  385. int datasz = size;
  386. new_store->raw_data = data;
  387. new_store->raw_size = size;
  388. return __dup_config(store, &store->root, new_store, &new_store->root,
  389. &dataptr, &datasz);
  390. }
  391. static int __write_config (void * f, int (*write) (void *, void *, int),
  392. struct config_store * store,
  393. LISTP_TYPE(config) * root,
  394. char * keybuf, int klen,
  395. unsigned long * offset)
  396. {
  397. struct config * e;
  398. int ret;
  399. char * buf = NULL;
  400. int bufsz = 0;
  401. listp_for_each_entry(e, root, siblings)
  402. if (e->val) {
  403. int total = klen + e->klen + e->vlen + 2;
  404. while (total > bufsz) {
  405. bufsz += CONFIG_MAX;
  406. buf = __alloca(CONFIG_MAX);
  407. }
  408. memcpy(buf, keybuf, klen);
  409. memcpy(buf + klen, e->key, e->klen);
  410. buf[klen + e->klen] = '=';
  411. memcpy(buf + total - e->vlen - 1, e->val, e->vlen);
  412. buf[total - 1] = '\n';
  413. ret = write(f, buf, total);
  414. if (ret < 0)
  415. return ret;
  416. *offset += total;
  417. } else {
  418. if (klen + e->klen + 1 > CONFIG_MAX)
  419. return -PAL_ERROR_TOOLONG;
  420. memcpy(keybuf + klen, e->key, e->klen);
  421. keybuf[klen + e->klen] = '.';
  422. if ((ret = __write_config(f, write, store, &e->children, keybuf,
  423. klen + e->klen + 1, offset)) < 0)
  424. return ret;
  425. }
  426. return 0;
  427. }
  428. int write_config (void * f, int (*write) (void *, void *, int),
  429. struct config_store * store)
  430. {
  431. char buf[CONFIG_MAX];
  432. unsigned long offset = 0;
  433. return __write_config(f, write, store, &store->root, buf, 0, &offset);
  434. }