file.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932
  1. /*
  2. * libuci - Library for the Unified Configuration Interface
  3. * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU Lesser General Public License version 2.1
  7. * as published by the Free Software Foundation
  8. *
  9. * This program 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. */
  14. /*
  15. * This file contains the code for parsing uci config files
  16. */
  17. #define _GNU_SOURCE
  18. #include <sys/types.h>
  19. #include <sys/stat.h>
  20. #include <sys/file.h>
  21. #include <stdbool.h>
  22. #include <unistd.h>
  23. #include <fcntl.h>
  24. #include <stdio.h>
  25. #include <ctype.h>
  26. #include <glob.h>
  27. #include <string.h>
  28. #include <stdlib.h>
  29. #include "uci.h"
  30. #include "uci_internal.h"
  31. #define LINEBUF 32
  32. /*
  33. * Fetch a new line from the input stream and resize buffer if necessary
  34. */
  35. __private void uci_getln(struct uci_context *ctx, int offset)
  36. {
  37. struct uci_parse_context *pctx = ctx->pctx;
  38. char *p;
  39. int ofs;
  40. if (pctx->buf == NULL) {
  41. pctx->buf = uci_malloc(ctx, LINEBUF);
  42. pctx->bufsz = LINEBUF;
  43. }
  44. /* It takes 2 slots for fgets to read 1 char. */
  45. if (offset >= pctx->bufsz - 1) {
  46. pctx->bufsz *= 2;
  47. pctx->buf = uci_realloc(ctx, pctx->buf, pctx->bufsz);
  48. }
  49. ofs = offset;
  50. do {
  51. p = &pctx->buf[ofs];
  52. p[0] = 0;
  53. p = fgets(p, pctx->bufsz - ofs, pctx->file);
  54. if (!p || !*p)
  55. return;
  56. ofs += strlen(p);
  57. if (pctx->buf[ofs - 1] == '\n') {
  58. pctx->line++;
  59. return;
  60. }
  61. pctx->bufsz *= 2;
  62. pctx->buf = uci_realloc(ctx, pctx->buf, pctx->bufsz);
  63. if (!pctx->buf)
  64. UCI_THROW(ctx, UCI_ERR_MEM);
  65. } while (1);
  66. }
  67. /*
  68. * parse a character escaped by '\'
  69. * returns true if the escaped character is to be parsed
  70. * returns false if the escaped character is to be ignored
  71. */
  72. static bool parse_backslash(struct uci_context *ctx)
  73. {
  74. struct uci_parse_context *pctx = ctx->pctx;
  75. /* skip backslash */
  76. pctx->pos += 1;
  77. /* undecoded backslash at the end of line, fetch the next line */
  78. if (!pctx_cur_char(pctx) ||
  79. pctx_cur_char(pctx) == '\n' ||
  80. (pctx_cur_char(pctx) == '\r' &&
  81. pctx_char(pctx, pctx_pos(pctx) + 1) == '\n' &&
  82. !pctx_char(pctx, pctx_pos(pctx) + 2))) {
  83. uci_getln(ctx, pctx->pos);
  84. return false;
  85. }
  86. /* FIXME: decode escaped char, necessary? */
  87. return true;
  88. }
  89. /*
  90. * move the string pointer forward until a non-whitespace character or
  91. * EOL is reached
  92. */
  93. static void skip_whitespace(struct uci_context *ctx)
  94. {
  95. struct uci_parse_context *pctx = ctx->pctx;
  96. while (pctx_cur_char(pctx) && isspace(pctx_cur_char(pctx)))
  97. pctx->pos += 1;
  98. }
  99. static inline void addc(struct uci_context *ctx, int *pos_dest, int *pos_src)
  100. {
  101. struct uci_parse_context *pctx = ctx->pctx;
  102. pctx_char(pctx, *pos_dest) = pctx_char(pctx, *pos_src);
  103. *pos_dest += 1;
  104. *pos_src += 1;
  105. }
  106. /*
  107. * parse a double quoted string argument from the command line
  108. */
  109. static void parse_double_quote(struct uci_context *ctx, int *target)
  110. {
  111. struct uci_parse_context *pctx = ctx->pctx;
  112. char c;
  113. /* skip quote character */
  114. pctx->pos += 1;
  115. while (1) {
  116. c = pctx_cur_char(pctx);
  117. switch(c) {
  118. case '"':
  119. pctx->pos += 1;
  120. return;
  121. case 0:
  122. /* Multi-line str value */
  123. uci_getln(ctx, pctx->pos);
  124. if (!pctx_cur_char(pctx)) {
  125. uci_parse_error(ctx, "EOF with unterminated \"");
  126. }
  127. break;
  128. case '\\':
  129. if (!parse_backslash(ctx))
  130. continue;
  131. /* fall through */
  132. default:
  133. addc(ctx, target, &pctx->pos);
  134. break;
  135. }
  136. }
  137. }
  138. /*
  139. * parse a single quoted string argument from the command line
  140. */
  141. static void parse_single_quote(struct uci_context *ctx, int *target)
  142. {
  143. struct uci_parse_context *pctx = ctx->pctx;
  144. char c;
  145. /* skip quote character */
  146. pctx->pos += 1;
  147. while (1) {
  148. c = pctx_cur_char(pctx);
  149. switch(c) {
  150. case '\'':
  151. pctx->pos += 1;
  152. return;
  153. case 0:
  154. /* Multi-line str value */
  155. uci_getln(ctx, pctx->pos);
  156. if (!pctx_cur_char(pctx))
  157. uci_parse_error(ctx, "EOF with unterminated '");
  158. break;
  159. default:
  160. addc(ctx, target, &pctx->pos);
  161. }
  162. }
  163. }
  164. /*
  165. * parse a string from the command line and detect the quoting style
  166. */
  167. static void parse_str(struct uci_context *ctx, int *target)
  168. {
  169. struct uci_parse_context *pctx = ctx->pctx;
  170. bool next = true;
  171. do {
  172. switch(pctx_cur_char(pctx)) {
  173. case '\'':
  174. parse_single_quote(ctx, target);
  175. break;
  176. case '"':
  177. parse_double_quote(ctx, target);
  178. break;
  179. case '#':
  180. pctx_cur_char(pctx) = 0;
  181. /* fall through */
  182. case 0:
  183. goto done;
  184. case ';':
  185. next = false;
  186. goto done;
  187. case '\\':
  188. if (!parse_backslash(ctx))
  189. continue;
  190. /* fall through */
  191. default:
  192. addc(ctx, target, &pctx->pos);
  193. break;
  194. }
  195. } while (pctx_cur_char(pctx) && !isspace(pctx_cur_char(pctx)));
  196. done:
  197. /*
  198. * if the string was unquoted and we've stopped at a whitespace
  199. * character, skip to the next one, because the whitespace will
  200. * be overwritten by a null byte here
  201. */
  202. if (pctx_cur_char(pctx) && next)
  203. pctx->pos += 1;
  204. /* terminate the parsed string */
  205. pctx_char(pctx, *target) = 0;
  206. }
  207. /*
  208. * extract the next argument from the command line
  209. */
  210. static int next_arg(struct uci_context *ctx, bool required, bool name, bool package)
  211. {
  212. struct uci_parse_context *pctx = ctx->pctx;
  213. int val, ptr;
  214. skip_whitespace(ctx);
  215. val = ptr = pctx_pos(pctx);
  216. if (pctx_cur_char(pctx) == ';') {
  217. pctx_cur_char(pctx) = 0;
  218. pctx->pos += 1;
  219. } else {
  220. parse_str(ctx, &ptr);
  221. }
  222. if (!pctx_char(pctx, val)) {
  223. if (required)
  224. uci_parse_error(ctx, "insufficient arguments");
  225. goto done;
  226. }
  227. if (name && !uci_validate_str(pctx_str(pctx, val), name, package))
  228. uci_parse_error(ctx, "invalid character in name field");
  229. done:
  230. return val;
  231. }
  232. int uci_parse_argument(struct uci_context *ctx, FILE *stream, char **str, char **result)
  233. {
  234. int ofs_result;
  235. UCI_HANDLE_ERR(ctx);
  236. UCI_ASSERT(ctx, str != NULL);
  237. UCI_ASSERT(ctx, result != NULL);
  238. if (ctx->pctx && (ctx->pctx->file != stream))
  239. uci_cleanup(ctx);
  240. if (!ctx->pctx)
  241. uci_alloc_parse_context(ctx);
  242. ctx->pctx->file = stream;
  243. if (!*str) {
  244. ctx->pctx->pos = 0;
  245. uci_getln(ctx, 0);
  246. }
  247. ofs_result = next_arg(ctx, false, false, false);
  248. *result = pctx_str(ctx->pctx, ofs_result);
  249. *str = pctx_cur_str(ctx->pctx);
  250. return 0;
  251. }
  252. static int
  253. uci_fill_ptr(struct uci_context *ctx, struct uci_ptr *ptr, struct uci_element *e)
  254. {
  255. UCI_ASSERT(ctx, ptr != NULL);
  256. UCI_ASSERT(ctx, e != NULL);
  257. memset(ptr, 0, sizeof(struct uci_ptr));
  258. switch(e->type) {
  259. case UCI_TYPE_OPTION:
  260. ptr->o = uci_to_option(e);
  261. goto fill_option;
  262. case UCI_TYPE_SECTION:
  263. ptr->s = uci_to_section(e);
  264. goto fill_section;
  265. case UCI_TYPE_PACKAGE:
  266. ptr->p = uci_to_package(e);
  267. goto fill_package;
  268. default:
  269. UCI_THROW(ctx, UCI_ERR_INVAL);
  270. }
  271. fill_option:
  272. ptr->option = ptr->o->e.name;
  273. ptr->s = ptr->o->section;
  274. fill_section:
  275. ptr->section = ptr->s->e.name;
  276. ptr->p = ptr->s->package;
  277. fill_package:
  278. ptr->package = ptr->p->e.name;
  279. ptr->flags |= UCI_LOOKUP_DONE;
  280. return 0;
  281. }
  282. /*
  283. * verify that the end of the line or command is reached.
  284. * throw an error if extra arguments are given on the command line
  285. */
  286. static void assert_eol(struct uci_context *ctx)
  287. {
  288. char *tmp;
  289. int ofs_tmp;
  290. skip_whitespace(ctx);
  291. ofs_tmp = next_arg(ctx, false, false, false);
  292. tmp = pctx_str(ctx->pctx, ofs_tmp);
  293. if (*tmp && (ctx->flags & UCI_FLAG_STRICT))
  294. uci_parse_error(ctx, "too many arguments");
  295. }
  296. /*
  297. * switch to a different config, either triggered by uci_load, or by a
  298. * 'package <...>' statement in the import file
  299. */
  300. static void uci_switch_config(struct uci_context *ctx)
  301. {
  302. struct uci_parse_context *pctx;
  303. struct uci_element *e;
  304. const char *name;
  305. pctx = ctx->pctx;
  306. name = pctx->name;
  307. /* add the last config to main config file list */
  308. if (pctx->package) {
  309. pctx->package->backend = ctx->backend;
  310. uci_list_add(&ctx->root, &pctx->package->e.list);
  311. pctx->package = NULL;
  312. pctx->section = NULL;
  313. }
  314. if (!name)
  315. return;
  316. /*
  317. * if an older config under the same name exists, unload it
  318. * ignore errors here, e.g. if the config was not found
  319. */
  320. e = uci_lookup_list(&ctx->root, name);
  321. if (e)
  322. UCI_THROW(ctx, UCI_ERR_DUPLICATE);
  323. pctx->package = uci_alloc_package(ctx, name);
  324. }
  325. /*
  326. * parse the 'package' uci command (next config package)
  327. */
  328. static void uci_parse_package(struct uci_context *ctx, bool single)
  329. {
  330. struct uci_parse_context *pctx = ctx->pctx;
  331. int ofs_name;
  332. char *name;
  333. /* command string null-terminated by strtok */
  334. pctx->pos += strlen(pctx_cur_str(pctx)) + 1;
  335. ofs_name = next_arg(ctx, true, true, true);
  336. name = pctx_str(pctx, ofs_name);
  337. assert_eol(ctx);
  338. if (single)
  339. return;
  340. ctx->pctx->name = name;
  341. uci_switch_config(ctx);
  342. }
  343. /*
  344. * parse the 'config' uci command (open a section)
  345. */
  346. static void uci_parse_config(struct uci_context *ctx)
  347. {
  348. struct uci_parse_context *pctx = ctx->pctx;
  349. struct uci_element *e;
  350. struct uci_ptr ptr;
  351. int ofs_name, ofs_type;
  352. char *name;
  353. char *type;
  354. uci_fixup_section(ctx, ctx->pctx->section);
  355. if (!ctx->pctx->package) {
  356. if (!ctx->pctx->name)
  357. uci_parse_error(ctx, "attempting to import a file without a package name");
  358. uci_switch_config(ctx);
  359. }
  360. /* command string null-terminated by strtok */
  361. pctx->pos += strlen(pctx_cur_str(pctx)) + 1;
  362. ofs_type = next_arg(ctx, true, false, false);
  363. type = pctx_str(pctx, ofs_type);
  364. if (!uci_validate_type(type))
  365. uci_parse_error(ctx, "invalid character in type field");
  366. ofs_name = next_arg(ctx, false, true, false);
  367. type = pctx_str(pctx, ofs_type);
  368. name = pctx_str(pctx, ofs_name);
  369. assert_eol(ctx);
  370. if (!name || !name[0]) {
  371. ctx->internal = !pctx->merge;
  372. UCI_NESTED(uci_add_section, ctx, pctx->package, type, &pctx->section);
  373. } else {
  374. uci_fill_ptr(ctx, &ptr, &pctx->package->e);
  375. e = uci_lookup_list(&pctx->package->sections, name);
  376. if (e) {
  377. ptr.s = uci_to_section(e);
  378. if ((ctx->flags & UCI_FLAG_STRICT) && strcmp(ptr.s->type, type))
  379. uci_parse_error(ctx, "section of different type overwrites prior section with same name");
  380. }
  381. ptr.section = name;
  382. ptr.value = type;
  383. ctx->internal = !pctx->merge;
  384. UCI_NESTED(uci_set, ctx, &ptr);
  385. pctx->section = uci_to_section(ptr.last);
  386. }
  387. }
  388. /*
  389. * parse the 'option' uci command (open a value)
  390. */
  391. static void uci_parse_option(struct uci_context *ctx, bool list)
  392. {
  393. struct uci_parse_context *pctx = ctx->pctx;
  394. struct uci_element *e;
  395. struct uci_ptr ptr;
  396. int ofs_name, ofs_value;
  397. char *name = NULL;
  398. char *value = NULL;
  399. if (!pctx->section)
  400. uci_parse_error(ctx, "option/list command found before the first section");
  401. /* command string null-terminated by strtok */
  402. pctx->pos += strlen(pctx_cur_str(pctx)) + 1;
  403. ofs_name = next_arg(ctx, true, true, false);
  404. ofs_value = next_arg(ctx, false, false, false);
  405. name = pctx_str(pctx, ofs_name);
  406. value = pctx_str(pctx, ofs_value);
  407. assert_eol(ctx);
  408. uci_fill_ptr(ctx, &ptr, &pctx->section->e);
  409. e = uci_lookup_list(&pctx->section->options, name);
  410. if (e)
  411. ptr.o = uci_to_option(e);
  412. ptr.option = name;
  413. ptr.value = value;
  414. ctx->internal = !pctx->merge;
  415. if (list)
  416. UCI_NESTED(uci_add_list, ctx, &ptr);
  417. else
  418. UCI_NESTED(uci_set, ctx, &ptr);
  419. }
  420. /*
  421. * parse a complete input line, split up combined commands by ';'
  422. */
  423. static void uci_parse_line(struct uci_context *ctx, bool single)
  424. {
  425. struct uci_parse_context *pctx = ctx->pctx;
  426. char *word;
  427. /* Skip whitespace characters at the start of line */
  428. skip_whitespace(ctx);
  429. do {
  430. word = strtok(pctx_cur_str(pctx), " \t");
  431. if (!word)
  432. return;
  433. switch(word[0]) {
  434. case 0:
  435. case '#':
  436. return;
  437. case 'p':
  438. if ((word[1] == 0) || !strcmp(word + 1, "ackage"))
  439. uci_parse_package(ctx, single);
  440. else
  441. goto invalid;
  442. break;
  443. case 'c':
  444. if ((word[1] == 0) || !strcmp(word + 1, "onfig"))
  445. uci_parse_config(ctx);
  446. else
  447. goto invalid;
  448. break;
  449. case 'o':
  450. if ((word[1] == 0) || !strcmp(word + 1, "ption"))
  451. uci_parse_option(ctx, false);
  452. else
  453. goto invalid;
  454. break;
  455. case 'l':
  456. if ((word[1] == 0) || !strcmp(word + 1, "ist"))
  457. uci_parse_option(ctx, true);
  458. else
  459. goto invalid;
  460. break;
  461. default:
  462. goto invalid;
  463. }
  464. continue;
  465. invalid:
  466. uci_parse_error(ctx, "invalid command");
  467. } while (1);
  468. }
  469. /* max number of characters that escaping adds to the string */
  470. #define UCI_QUOTE_ESCAPE "'\\''"
  471. /*
  472. * escape an uci string for export
  473. */
  474. static const char *uci_escape(struct uci_context *ctx, const char *str)
  475. {
  476. const char *end;
  477. int ofs = 0;
  478. if (!ctx->buf) {
  479. ctx->bufsz = LINEBUF;
  480. ctx->buf = malloc(LINEBUF);
  481. if (!ctx->buf)
  482. return str;
  483. }
  484. while (1) {
  485. int len;
  486. end = strchr(str, '\'');
  487. if (!end)
  488. end = str + strlen(str);
  489. len = end - str;
  490. /* make sure that we have enough room in the buffer */
  491. while (ofs + len + sizeof(UCI_QUOTE_ESCAPE) + 1 > ctx->bufsz) {
  492. ctx->bufsz *= 2;
  493. ctx->buf = uci_realloc(ctx, ctx->buf, ctx->bufsz);
  494. }
  495. /* copy the string until the character before the quote */
  496. memcpy(&ctx->buf[ofs], str, len);
  497. ofs += len;
  498. /* end of string? return the buffer */
  499. if (*end == 0)
  500. break;
  501. memcpy(&ctx->buf[ofs], UCI_QUOTE_ESCAPE, sizeof(UCI_QUOTE_ESCAPE));
  502. ofs += strlen(&ctx->buf[ofs]);
  503. str = end + 1;
  504. }
  505. ctx->buf[ofs] = 0;
  506. return ctx->buf;
  507. }
  508. /*
  509. * export a single config package to a file stream
  510. */
  511. static void uci_export_package(struct uci_package *p, FILE *stream, bool header)
  512. {
  513. struct uci_context *ctx = p->ctx;
  514. struct uci_element *s, *o, *i;
  515. if (header)
  516. fprintf(stream, "package %s\n", uci_escape(ctx, p->e.name));
  517. uci_foreach_element(&p->sections, s) {
  518. struct uci_section *sec = uci_to_section(s);
  519. fprintf(stream, "\nconfig %s", uci_escape(ctx, sec->type));
  520. if (!sec->anonymous || (ctx->flags & UCI_FLAG_EXPORT_NAME))
  521. fprintf(stream, " '%s'", uci_escape(ctx, sec->e.name));
  522. fprintf(stream, "\n");
  523. uci_foreach_element(&sec->options, o) {
  524. struct uci_option *opt = uci_to_option(o);
  525. switch(opt->type) {
  526. case UCI_TYPE_STRING:
  527. fprintf(stream, "\toption %s", uci_escape(ctx, opt->e.name));
  528. fprintf(stream, " '%s'\n", uci_escape(ctx, opt->v.string));
  529. break;
  530. case UCI_TYPE_LIST:
  531. uci_foreach_element(&opt->v.list, i) {
  532. fprintf(stream, "\tlist %s", uci_escape(ctx, opt->e.name));
  533. fprintf(stream, " '%s'\n", uci_escape(ctx, i->name));
  534. }
  535. break;
  536. default:
  537. fprintf(stream, "\t# unknown type for option '%s'\n", uci_escape(ctx, opt->e.name));
  538. break;
  539. }
  540. }
  541. }
  542. fprintf(stream, "\n");
  543. }
  544. int uci_export(struct uci_context *ctx, FILE *stream, struct uci_package *package, bool header)
  545. {
  546. struct uci_element *e;
  547. UCI_HANDLE_ERR(ctx);
  548. UCI_ASSERT(ctx, stream != NULL);
  549. if (package)
  550. uci_export_package(package, stream, header);
  551. else {
  552. uci_foreach_element(&ctx->root, e) {
  553. uci_export_package(uci_to_package(e), stream, header);
  554. }
  555. }
  556. return 0;
  557. }
  558. int uci_import(struct uci_context *ctx, FILE *stream, const char *name, struct uci_package **package, bool single)
  559. {
  560. struct uci_parse_context *pctx;
  561. UCI_HANDLE_ERR(ctx);
  562. /* make sure no memory from previous parse attempts is leaked */
  563. uci_cleanup(ctx);
  564. uci_alloc_parse_context(ctx);
  565. pctx = ctx->pctx;
  566. pctx->file = stream;
  567. if (package && *package && single) {
  568. pctx->package = *package;
  569. pctx->merge = true;
  570. }
  571. /*
  572. * If 'name' was supplied, assume that the supplied stream does not contain
  573. * the appropriate 'package <name>' string to specify the config name
  574. * NB: the config file can still override the package name
  575. */
  576. if (name) {
  577. UCI_ASSERT(ctx, uci_validate_package(name));
  578. pctx->name = name;
  579. }
  580. while (!feof(pctx->file)) {
  581. pctx->pos = 0;
  582. uci_getln(ctx, 0);
  583. UCI_TRAP_SAVE(ctx, error);
  584. if (pctx->buf[0])
  585. uci_parse_line(ctx, single);
  586. UCI_TRAP_RESTORE(ctx);
  587. continue;
  588. error:
  589. if (ctx->flags & UCI_FLAG_PERROR)
  590. uci_perror(ctx, NULL);
  591. if ((ctx->err != UCI_ERR_PARSE) ||
  592. (ctx->flags & UCI_FLAG_STRICT))
  593. UCI_THROW(ctx, ctx->err);
  594. }
  595. uci_fixup_section(ctx, ctx->pctx->section);
  596. if (!pctx->package && name)
  597. uci_switch_config(ctx);
  598. if (package)
  599. *package = pctx->package;
  600. if (pctx->merge)
  601. pctx->package = NULL;
  602. pctx->name = NULL;
  603. uci_switch_config(ctx);
  604. /* no error happened, we can get rid of the parser context now */
  605. uci_cleanup(ctx);
  606. return 0;
  607. }
  608. static char *uci_config_path(struct uci_context *ctx, const char *name)
  609. {
  610. char *filename;
  611. UCI_ASSERT(ctx, uci_validate_package(name));
  612. filename = uci_malloc(ctx, strlen(name) + strlen(ctx->confdir) + 2);
  613. sprintf(filename, "%s/%s", ctx->confdir, name);
  614. return filename;
  615. }
  616. static void uci_file_commit(struct uci_context *ctx, struct uci_package **package, bool overwrite)
  617. {
  618. struct uci_package *p = *package;
  619. FILE *f1, *f2 = NULL;
  620. char *name = NULL;
  621. char *path = NULL;
  622. char *filename = NULL;
  623. struct stat statbuf;
  624. bool do_rename = false;
  625. if (!p->path) {
  626. if (overwrite)
  627. p->path = uci_config_path(ctx, p->e.name);
  628. else
  629. UCI_THROW(ctx, UCI_ERR_INVAL);
  630. }
  631. if ((asprintf(&filename, "%s/.%s.uci-XXXXXX", ctx->confdir, p->e.name) < 0) || !filename)
  632. UCI_THROW(ctx, UCI_ERR_MEM);
  633. /* open the config file for writing now, so that it is locked */
  634. f1 = uci_open_stream(ctx, p->path, NULL, SEEK_SET, true, true);
  635. /* flush unsaved changes and reload from delta file */
  636. UCI_TRAP_SAVE(ctx, done);
  637. if (p->has_delta) {
  638. if (!overwrite) {
  639. name = uci_strdup(ctx, p->e.name);
  640. path = uci_strdup(ctx, p->path);
  641. /* dump our own changes to the delta file */
  642. if (!uci_list_empty(&p->delta))
  643. UCI_INTERNAL(uci_save, ctx, p);
  644. /*
  645. * other processes might have modified the config
  646. * as well. dump and reload
  647. */
  648. uci_free_package(&p);
  649. uci_cleanup(ctx);
  650. UCI_INTERNAL(uci_import, ctx, f1, name, &p, true);
  651. p->path = path;
  652. p->has_delta = true;
  653. *package = p;
  654. /* freed together with the uci_package */
  655. path = NULL;
  656. }
  657. /* flush delta */
  658. if (!uci_load_delta(ctx, p, true))
  659. goto done;
  660. }
  661. if (!mktemp(filename))
  662. *filename = 0;
  663. if (!*filename) {
  664. free(filename);
  665. UCI_THROW(ctx, UCI_ERR_IO);
  666. }
  667. if ((stat(filename, &statbuf) == 0) && ((statbuf.st_mode & S_IFMT) != S_IFREG))
  668. UCI_THROW(ctx, UCI_ERR_IO);
  669. f2 = uci_open_stream(ctx, filename, p->path, SEEK_SET, true, true);
  670. uci_export(ctx, f2, p, false);
  671. fflush(f2);
  672. fsync(fileno(f2));
  673. uci_close_stream(f2);
  674. do_rename = true;
  675. UCI_TRAP_RESTORE(ctx);
  676. done:
  677. free(name);
  678. free(path);
  679. uci_close_stream(f1);
  680. if (do_rename) {
  681. path = realpath(p->path, NULL);
  682. if (!path || rename(filename, path)) {
  683. unlink(filename);
  684. UCI_THROW(ctx, UCI_ERR_IO);
  685. }
  686. free(path);
  687. }
  688. free(filename);
  689. if (ctx->err)
  690. UCI_THROW(ctx, ctx->err);
  691. }
  692. /*
  693. * This function returns the filename by returning the string
  694. * after the last '/' character. By checking for a non-'\0'
  695. * character afterwards, directories are ignored (glob marks
  696. * those with a trailing '/'
  697. */
  698. static inline char *get_filename(char *path)
  699. {
  700. char *p;
  701. p = strrchr(path, '/');
  702. p++;
  703. if (!*p)
  704. return NULL;
  705. return p;
  706. }
  707. static char **uci_list_config_files(struct uci_context *ctx)
  708. {
  709. char **configs;
  710. glob_t globbuf;
  711. int size, i;
  712. char *buf;
  713. char *dir;
  714. dir = uci_malloc(ctx, strlen(ctx->confdir) + 1 + sizeof("/*"));
  715. sprintf(dir, "%s/*", ctx->confdir);
  716. if (glob(dir, GLOB_MARK, NULL, &globbuf) != 0) {
  717. free(dir);
  718. UCI_THROW(ctx, UCI_ERR_NOTFOUND);
  719. }
  720. size = sizeof(char *) * (globbuf.gl_pathc + 1);
  721. for(i = 0; i < globbuf.gl_pathc; i++) {
  722. char *p;
  723. p = get_filename(globbuf.gl_pathv[i]);
  724. if (!p)
  725. continue;
  726. size += strlen(p) + 1;
  727. }
  728. configs = uci_malloc(ctx, size);
  729. buf = (char *) &configs[globbuf.gl_pathc + 1];
  730. for(i = 0; i < globbuf.gl_pathc; i++) {
  731. char *p;
  732. p = get_filename(globbuf.gl_pathv[i]);
  733. if (!p)
  734. continue;
  735. if (!uci_validate_package(p))
  736. continue;
  737. configs[i] = buf;
  738. strcpy(buf, p);
  739. buf += strlen(buf) + 1;
  740. }
  741. free(dir);
  742. globfree(&globbuf);
  743. return configs;
  744. }
  745. static struct uci_package *uci_file_load(struct uci_context *ctx, const char *name)
  746. {
  747. struct uci_package *package = NULL;
  748. char *filename;
  749. bool confdir;
  750. FILE *file = NULL;
  751. switch (name[0]) {
  752. case '.':
  753. /* relative path outside of /etc/config */
  754. if (name[1] != '/')
  755. UCI_THROW(ctx, UCI_ERR_NOTFOUND);
  756. /* fall through */
  757. case '/':
  758. /* absolute path outside of /etc/config */
  759. filename = uci_strdup(ctx, name);
  760. name = strrchr(name, '/') + 1;
  761. confdir = false;
  762. break;
  763. default:
  764. /* config in /etc/config */
  765. filename = uci_config_path(ctx, name);
  766. confdir = true;
  767. break;
  768. }
  769. UCI_TRAP_SAVE(ctx, done);
  770. file = uci_open_stream(ctx, filename, NULL, SEEK_SET, false, false);
  771. ctx->err = 0;
  772. UCI_INTERNAL(uci_import, ctx, file, name, &package, true);
  773. UCI_TRAP_RESTORE(ctx);
  774. if (package) {
  775. package->path = filename;
  776. package->has_delta = confdir;
  777. uci_load_delta(ctx, package, false);
  778. }
  779. done:
  780. uci_close_stream(file);
  781. if (ctx->err) {
  782. free(filename);
  783. UCI_THROW(ctx, ctx->err);
  784. }
  785. return package;
  786. }
  787. __private UCI_BACKEND(uci_file_backend, "file",
  788. .load = uci_file_load,
  789. .commit = uci_file_commit,
  790. .list_configs = uci_list_config_files,
  791. );