file.c 19 KB

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