config.c 14 KB

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