file.c 21 KB

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