uci.c 20 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060
  1. /*
  2. * libuci plugin for Lua
  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 General Public License version 2
  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 General Public License for more details.
  13. */
  14. #include <sys/types.h>
  15. #include <sys/time.h>
  16. #include <stdbool.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <unistd.h>
  20. #include <stdio.h>
  21. #include <errno.h>
  22. #include <lauxlib.h>
  23. #include <uci.h>
  24. #define MODNAME "uci"
  25. #define METANAME MODNAME ".meta"
  26. //#define DEBUG 1
  27. #ifdef DEBUG
  28. #define DPRINTF(...) fprintf(stderr, __VA_ARGS__)
  29. #else
  30. #define DPRINTF(...) do {} while (0)
  31. #endif
  32. #if !defined LUA_VERSION_NUM || LUA_VERSION_NUM==501
  33. int luaopen_uci(lua_State *L);
  34. /*
  35. * ** Adapted from Lua 5.2.0
  36. * */
  37. static void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
  38. luaL_checkstack(L, nup+1, "too many upvalues");
  39. for (; l->name != NULL; l++) { /* fill the table with given functions */
  40. int i;
  41. lua_pushstring(L, l->name);
  42. for (i = 0; i < nup; i++) /* copy upvalues to the top */
  43. lua_pushvalue(L, -(nup+1));
  44. lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */
  45. lua_settable(L, -(nup + 3));
  46. }
  47. lua_pop(L, nup); /* remove upvalues */
  48. }
  49. #define lua_rawlen(L, i) lua_objlen(L, i)
  50. #endif
  51. static struct uci_context *global_ctx = NULL;
  52. static struct uci_context *
  53. find_context(lua_State *L, int *offset)
  54. {
  55. struct uci_context **ctx;
  56. if (!lua_isuserdata(L, 1)) {
  57. if (!global_ctx) {
  58. global_ctx = uci_alloc_context();
  59. if (!global_ctx) {
  60. luaL_error(L, "failed to allocate UCI context");
  61. return NULL;
  62. }
  63. }
  64. if (offset)
  65. *offset = 0;
  66. return global_ctx;
  67. }
  68. if (offset)
  69. *offset = 1;
  70. ctx = luaL_checkudata(L, 1, METANAME);
  71. if (!ctx || !*ctx) {
  72. luaL_error(L, "failed to get UCI context");
  73. return NULL;
  74. }
  75. return *ctx;
  76. }
  77. static struct uci_package *
  78. find_package(lua_State *L, struct uci_context *ctx, const char *str, bool al)
  79. {
  80. struct uci_package *p = NULL;
  81. struct uci_element *e;
  82. char *sep;
  83. char *name;
  84. sep = strchr(str, '.');
  85. if (sep) {
  86. name = malloc(1 + sep - str);
  87. if (!name) {
  88. luaL_error(L, "out of memory");
  89. return NULL;
  90. }
  91. strncpy(name, str, sep - str);
  92. name[sep - str] = 0;
  93. } else
  94. name = (char *) str;
  95. uci_foreach_element(&ctx->root, e) {
  96. if (strcmp(e->name, name) != 0)
  97. continue;
  98. p = uci_to_package(e);
  99. goto done;
  100. }
  101. if (al)
  102. uci_load(ctx, name, &p);
  103. done:
  104. if (name != str)
  105. free(name);
  106. return p;
  107. }
  108. static int
  109. lookup_extended(struct uci_context *ctx, struct uci_ptr *ptr, char *str, bool extended)
  110. {
  111. int rv;
  112. struct uci_ptr lookup;
  113. /* use a copy of the passed ptr since failing lookups will
  114. * clobber the state */
  115. lookup = *ptr;
  116. lookup.flags |= UCI_LOOKUP_EXTENDED;
  117. rv = uci_lookup_ptr(ctx, &lookup, str, extended);
  118. /* copy to passed ptr on success */
  119. if (!rv)
  120. *ptr = lookup;
  121. return rv;
  122. }
  123. static int
  124. lookup_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *str, bool extended)
  125. {
  126. if (ptr && !ptr->s && ptr->section && *ptr->section == '@')
  127. return lookup_extended(ctx, ptr, str, extended);
  128. return uci_lookup_ptr(ctx, ptr, str, extended);
  129. }
  130. static int
  131. lookup_args(lua_State *L, struct uci_context *ctx, int offset, struct uci_ptr *ptr, char **buf)
  132. {
  133. char *s = NULL;
  134. int n;
  135. n = lua_gettop(L);
  136. luaL_checkstring(L, 1 + offset);
  137. s = strdup(lua_tostring(L, 1 + offset));
  138. if (!s)
  139. goto error;
  140. memset(ptr, 0, sizeof(struct uci_ptr));
  141. if (!find_package(L, ctx, s, true))
  142. goto error;
  143. switch (n - offset) {
  144. case 4:
  145. case 3:
  146. ptr->option = luaL_checkstring(L, 3 + offset);
  147. /* fall through */
  148. case 2:
  149. ptr->section = luaL_checkstring(L, 2 + offset);
  150. ptr->package = luaL_checkstring(L, 1 + offset);
  151. if (lookup_ptr(ctx, ptr, NULL, true) != UCI_OK)
  152. goto error;
  153. break;
  154. case 1:
  155. if (lookup_ptr(ctx, ptr, s, true) != UCI_OK)
  156. goto error;
  157. break;
  158. default:
  159. luaL_error(L, "invalid argument count");
  160. goto error;
  161. }
  162. *buf = s;
  163. return 0;
  164. error:
  165. if (s)
  166. free(s);
  167. return 1;
  168. }
  169. static int
  170. uci_push_status(lua_State *L, struct uci_context *ctx, bool hasarg)
  171. {
  172. char *str = NULL;
  173. if (!hasarg)
  174. lua_pushboolean(L, (ctx->err == UCI_OK));
  175. if (ctx->err) {
  176. uci_get_errorstr(ctx, &str, MODNAME);
  177. if (str) {
  178. lua_pushstring(L, str);
  179. free(str);
  180. return 2;
  181. }
  182. }
  183. return 1;
  184. }
  185. static void
  186. uci_push_option(lua_State *L, struct uci_option *o)
  187. {
  188. struct uci_element *e;
  189. int i = 0;
  190. switch(o->type) {
  191. case UCI_TYPE_STRING:
  192. lua_pushstring(L, o->v.string);
  193. break;
  194. case UCI_TYPE_LIST:
  195. lua_newtable(L);
  196. uci_foreach_element(&o->v.list, e) {
  197. i++;
  198. lua_pushstring(L, e->name);
  199. lua_rawseti(L, -2, i);
  200. }
  201. break;
  202. default:
  203. lua_pushnil(L);
  204. break;
  205. }
  206. }
  207. static void
  208. uci_push_section(lua_State *L, struct uci_section *s, int index)
  209. {
  210. struct uci_element *e;
  211. lua_newtable(L);
  212. lua_pushboolean(L, s->anonymous);
  213. lua_setfield(L, -2, ".anonymous");
  214. lua_pushstring(L, s->type);
  215. lua_setfield(L, -2, ".type");
  216. lua_pushstring(L, s->e.name);
  217. lua_setfield(L, -2, ".name");
  218. if (index >= 0) {
  219. lua_pushinteger(L, index);
  220. lua_setfield(L, -2, ".index");
  221. }
  222. uci_foreach_element(&s->options, e) {
  223. struct uci_option *o = uci_to_option(e);
  224. uci_push_option(L, o);
  225. lua_setfield(L, -2, o->e.name);
  226. }
  227. }
  228. static void
  229. uci_push_package(lua_State *L, struct uci_package *p)
  230. {
  231. struct uci_element *e;
  232. int i = 0;
  233. lua_newtable(L);
  234. uci_foreach_element(&p->sections, e) {
  235. uci_push_section(L, uci_to_section(e), i);
  236. lua_setfield(L, -2, e->name);
  237. i++;
  238. }
  239. }
  240. static int
  241. uci_lua_unload(lua_State *L)
  242. {
  243. struct uci_context *ctx;
  244. struct uci_package *p;
  245. const char *s;
  246. int offset = 0;
  247. ctx = find_context(L, &offset);
  248. luaL_checkstring(L, 1 + offset);
  249. s = lua_tostring(L, 1 + offset);
  250. p = find_package(L, ctx, s, false);
  251. if (p) {
  252. uci_unload(ctx, p);
  253. return uci_push_status(L, ctx, false);
  254. } else {
  255. lua_pushboolean(L, 0);
  256. }
  257. return 1;
  258. }
  259. static int
  260. uci_lua_load(lua_State *L)
  261. {
  262. struct uci_context *ctx;
  263. struct uci_package *p = NULL;
  264. const char *s;
  265. int offset = 0;
  266. ctx = find_context(L, &offset);
  267. uci_lua_unload(L);
  268. lua_pop(L, 1); /* bool ret value of unload */
  269. s = lua_tostring(L, -1);
  270. uci_load(ctx, s, &p);
  271. return uci_push_status(L, ctx, false);
  272. }
  273. static int
  274. uci_lua_foreach(lua_State *L)
  275. {
  276. struct uci_context *ctx;
  277. struct uci_package *p;
  278. struct uci_element *e, *tmp;
  279. const char *package, *type;
  280. bool ret = false;
  281. int offset = 0;
  282. int i = 0;
  283. ctx = find_context(L, &offset);
  284. package = luaL_checkstring(L, 1 + offset);
  285. if (lua_isnil(L, 2 + offset))
  286. type = NULL;
  287. else
  288. type = luaL_checkstring(L, 2 + offset);
  289. if (!lua_isfunction(L, 3 + offset) || !package)
  290. return luaL_error(L, "Invalid argument");
  291. p = find_package(L, ctx, package, true);
  292. if (!p)
  293. goto done;
  294. uci_foreach_element_safe(&p->sections, tmp, e) {
  295. struct uci_section *s = uci_to_section(e);
  296. i++;
  297. if (type && (strcmp(s->type, type) != 0))
  298. continue;
  299. lua_pushvalue(L, 3 + offset); /* iterator function */
  300. uci_push_section(L, s, i - 1);
  301. if (lua_pcall(L, 1, 1, 0) == 0) {
  302. ret = true;
  303. if (lua_isboolean(L, -1) && !lua_toboolean(L, -1))
  304. break;
  305. }
  306. else
  307. {
  308. lua_error(L);
  309. break;
  310. }
  311. }
  312. done:
  313. lua_pushboolean(L, ret);
  314. return 1;
  315. }
  316. static int
  317. uci_lua_get_any(lua_State *L, bool all)
  318. {
  319. struct uci_context *ctx;
  320. struct uci_ptr ptr;
  321. int offset = 0;
  322. int nret = 1;
  323. char *s = NULL;
  324. ctx = find_context(L, &offset);
  325. if (lookup_args(L, ctx, offset, &ptr, &s))
  326. goto error;
  327. if (!all && !ptr.s) {
  328. ctx->err = UCI_ERR_INVAL;
  329. goto error;
  330. }
  331. if (!(ptr.flags & UCI_LOOKUP_COMPLETE)) {
  332. ctx->err = UCI_ERR_NOTFOUND;
  333. goto error;
  334. }
  335. if (ptr.o) {
  336. uci_push_option(L, ptr.o);
  337. } else if (ptr.s) {
  338. if (all) {
  339. uci_push_section(L, ptr.s, -1);
  340. }
  341. else {
  342. lua_pushstring(L, ptr.s->type);
  343. lua_pushstring(L, ptr.s->e.name);
  344. nret++;
  345. }
  346. } else {
  347. uci_push_package(L, ptr.p);
  348. }
  349. if (s)
  350. free(s);
  351. return nret;
  352. error:
  353. if (s)
  354. free(s);
  355. lua_pushnil(L);
  356. return uci_push_status(L, ctx, true);
  357. }
  358. static int
  359. uci_lua_get(lua_State *L)
  360. {
  361. return uci_lua_get_any(L, false);
  362. }
  363. static int
  364. uci_lua_get_all(lua_State *L)
  365. {
  366. return uci_lua_get_any(L, true);
  367. }
  368. static int
  369. uci_lua_add(lua_State *L)
  370. {
  371. struct uci_context *ctx;
  372. struct uci_section *s = NULL;
  373. struct uci_package *p;
  374. const char *package;
  375. const char *type;
  376. const char *name = NULL;
  377. int offset = 0;
  378. ctx = find_context(L, &offset);
  379. package = luaL_checkstring(L, 1 + offset);
  380. type = luaL_checkstring(L, 2 + offset);
  381. p = find_package(L, ctx, package, true);
  382. if (!p)
  383. goto fail;
  384. if (uci_add_section(ctx, p, type, &s) || !s)
  385. goto fail;
  386. name = s->e.name;
  387. lua_pushstring(L, name);
  388. return 1;
  389. fail:
  390. lua_pushnil(L);
  391. return uci_push_status(L, ctx, true);
  392. }
  393. static int
  394. uci_lua_delete(lua_State *L)
  395. {
  396. struct uci_context *ctx;
  397. struct uci_ptr ptr;
  398. int offset = 0;
  399. char *s = NULL;
  400. ctx = find_context(L, &offset);
  401. if (lookup_args(L, ctx, offset, &ptr, &s))
  402. goto error;
  403. uci_delete(ctx, &ptr);
  404. error:
  405. if (s)
  406. free(s);
  407. return uci_push_status(L, ctx, false);
  408. }
  409. static int
  410. uci_lua_rename(lua_State *L)
  411. {
  412. struct uci_context *ctx;
  413. struct uci_ptr ptr;
  414. int err = UCI_ERR_MEM;
  415. char *s = NULL;
  416. int nargs, offset = 0;
  417. ctx = find_context(L, &offset);
  418. nargs = lua_gettop(L);
  419. if (lookup_args(L, ctx, offset, &ptr, &s))
  420. goto error;
  421. switch(nargs - offset) {
  422. case 1:
  423. /* Format: uci.set("p.s.o=v") or uci.set("p.s=v") */
  424. break;
  425. case 4:
  426. /* Format: uci.set("p", "s", "o", "v") */
  427. ptr.value = luaL_checkstring(L, nargs);
  428. break;
  429. case 3:
  430. /* Format: uci.set("p", "s", "v") */
  431. ptr.value = ptr.option;
  432. ptr.option = NULL;
  433. break;
  434. default:
  435. ctx->err = UCI_ERR_INVAL;
  436. goto error;
  437. }
  438. err = lookup_ptr(ctx, &ptr, NULL, true);
  439. if (err)
  440. goto error;
  441. if (((ptr.s == NULL) && (ptr.option != NULL)) || (ptr.value == NULL)) {
  442. ctx->err = UCI_ERR_INVAL;
  443. goto error;
  444. }
  445. err = uci_rename(ctx, &ptr);
  446. if (err)
  447. goto error;
  448. error:
  449. if (s)
  450. free(s);
  451. return uci_push_status(L, ctx, false);
  452. }
  453. static int
  454. uci_lua_reorder(lua_State *L)
  455. {
  456. struct uci_context *ctx;
  457. struct uci_ptr ptr;
  458. int err = UCI_ERR_MEM;
  459. char *s = NULL;
  460. int nargs, offset = 0;
  461. ctx = find_context(L, &offset);
  462. nargs = lua_gettop(L);
  463. if (lookup_args(L, ctx, offset, &ptr, &s))
  464. goto error;
  465. switch(nargs - offset) {
  466. case 1:
  467. /* Format: uci.set("p.s=v") or uci.set("p.s=v") */
  468. if (ptr.option) {
  469. ctx->err = UCI_ERR_INVAL;
  470. goto error;
  471. }
  472. break;
  473. case 3:
  474. /* Format: uci.set("p", "s", "v") */
  475. ptr.value = ptr.option;
  476. ptr.option = NULL;
  477. break;
  478. default:
  479. ctx->err = UCI_ERR_INVAL;
  480. goto error;
  481. }
  482. err = lookup_ptr(ctx, &ptr, NULL, true);
  483. if (err)
  484. goto error;
  485. if ((ptr.s == NULL) || (ptr.value == NULL)) {
  486. ctx->err = UCI_ERR_INVAL;
  487. goto error;
  488. }
  489. err = uci_reorder_section(ctx, ptr.s, strtoul(ptr.value, NULL, 10));
  490. if (err)
  491. goto error;
  492. error:
  493. if (s)
  494. free(s);
  495. return uci_push_status(L, ctx, false);
  496. }
  497. static int
  498. uci_lua_set(lua_State *L)
  499. {
  500. struct uci_context *ctx;
  501. struct uci_ptr ptr;
  502. bool istable = false;
  503. int err = UCI_ERR_MEM;
  504. char *s = NULL;
  505. const char *v;
  506. unsigned int i;
  507. int nargs, offset = 0;
  508. ctx = find_context(L, &offset);
  509. nargs = lua_gettop(L);
  510. if (lookup_args(L, ctx, offset, &ptr, &s))
  511. goto error;
  512. switch(nargs - offset) {
  513. case 1:
  514. /* Format: uci.set("p.s.o=v") or uci.set("p.s=v") */
  515. break;
  516. case 4:
  517. /* Format: uci.set("p", "s", "o", "v") */
  518. if (lua_istable(L, nargs)) {
  519. if (lua_rawlen(L, nargs) < 1) {
  520. free(s);
  521. return luaL_error(L, "Cannot set an uci option to an empty table value");
  522. }
  523. lua_rawgeti(L, nargs, 1);
  524. ptr.value = luaL_checkstring(L, -1);
  525. lua_pop(L, 1);
  526. istable = true;
  527. } else {
  528. ptr.value = luaL_checkstring(L, nargs);
  529. }
  530. break;
  531. case 3:
  532. /* Format: uci.set("p", "s", "v") */
  533. ptr.value = ptr.option;
  534. ptr.option = NULL;
  535. break;
  536. default:
  537. ctx->err = UCI_ERR_INVAL;
  538. goto error;
  539. }
  540. err = lookup_ptr(ctx, &ptr, NULL, true);
  541. if (err)
  542. goto error;
  543. if (((ptr.s == NULL) && (ptr.option != NULL)) || (ptr.value == NULL)) {
  544. ctx->err = UCI_ERR_INVAL;
  545. goto error;
  546. }
  547. if (istable) {
  548. if (lua_rawlen(L, nargs) == 1) {
  549. i = 1;
  550. if (ptr.o) {
  551. v = ptr.value;
  552. ptr.value = NULL;
  553. err = uci_delete(ctx, &ptr);
  554. if (err)
  555. goto error;
  556. ptr.value = v;
  557. }
  558. } else {
  559. i = 2;
  560. err = uci_set(ctx, &ptr);
  561. if (err)
  562. goto error;
  563. }
  564. for (; i <= lua_rawlen(L, nargs); i++) {
  565. lua_rawgeti(L, nargs, i);
  566. ptr.value = luaL_checkstring(L, -1);
  567. err = uci_add_list(ctx, &ptr);
  568. lua_pop(L, 1);
  569. if (err)
  570. goto error;
  571. }
  572. } else {
  573. err = uci_set(ctx, &ptr);
  574. if (err)
  575. goto error;
  576. }
  577. error:
  578. if (s)
  579. free(s);
  580. return uci_push_status(L, ctx, false);
  581. }
  582. enum pkg_cmd {
  583. CMD_SAVE,
  584. CMD_COMMIT,
  585. CMD_REVERT
  586. };
  587. static int
  588. uci_lua_package_cmd(lua_State *L, enum pkg_cmd cmd)
  589. {
  590. struct uci_context *ctx;
  591. struct uci_element *e, *tmp;
  592. struct uci_ptr ptr;
  593. char *s = NULL;
  594. int nargs, offset = 0;
  595. ctx = find_context(L, &offset);
  596. nargs = lua_gettop(L);
  597. if ((cmd != CMD_REVERT) && (nargs - offset > 1))
  598. goto err;
  599. if (lookup_args(L, ctx, offset, &ptr, &s))
  600. goto err;
  601. lookup_ptr(ctx, &ptr, NULL, true);
  602. uci_foreach_element_safe(&ctx->root, tmp, e) {
  603. struct uci_package *p = uci_to_package(e);
  604. if (ptr.p && (ptr.p != p))
  605. continue;
  606. ptr.p = p;
  607. switch(cmd) {
  608. case CMD_COMMIT:
  609. uci_commit(ctx, &p, false);
  610. break;
  611. case CMD_SAVE:
  612. uci_save(ctx, p);
  613. break;
  614. case CMD_REVERT:
  615. uci_revert(ctx, &ptr);
  616. break;
  617. }
  618. }
  619. err:
  620. if (s)
  621. free(s);
  622. return uci_push_status(L, ctx, false);
  623. }
  624. static int
  625. uci_lua_save(lua_State *L)
  626. {
  627. return uci_lua_package_cmd(L, CMD_SAVE);
  628. }
  629. static int
  630. uci_lua_commit(lua_State *L)
  631. {
  632. return uci_lua_package_cmd(L, CMD_COMMIT);
  633. }
  634. static int
  635. uci_lua_revert(lua_State *L)
  636. {
  637. return uci_lua_package_cmd(L, CMD_REVERT);
  638. }
  639. static void
  640. uci_lua_add_change(lua_State *L, struct uci_element *e)
  641. {
  642. struct uci_delta *h;
  643. const char *name;
  644. const char *value;
  645. h = uci_to_delta(e);
  646. if (!h->section)
  647. return;
  648. lua_getfield(L, -1, h->section);
  649. if (lua_isnil(L, -1)) {
  650. lua_pop(L, 1);
  651. lua_newtable(L);
  652. lua_pushvalue(L, -1); /* copy for setfield */
  653. lua_setfield(L, -3, h->section);
  654. }
  655. name = h->e.name;
  656. value = h->value ? h->value : "";
  657. if (name) {
  658. lua_getfield(L, -1, name);
  659. /* this delta is a list add operation */
  660. if (h->cmd == UCI_CMD_LIST_ADD) {
  661. /* there seems to be no table yet */
  662. if (!lua_istable(L, -1)) {
  663. lua_newtable(L);
  664. /* if there is a value on the stack already, add */
  665. if (!lua_isnil(L, -2)) {
  666. lua_pushvalue(L, -2);
  667. lua_rawseti(L, -2, 1);
  668. lua_pushstring(L, value);
  669. lua_rawseti(L, -2, 2);
  670. /* this is the first table item */
  671. } else {
  672. lua_pushstring(L, value);
  673. lua_rawseti(L, -2, 1);
  674. }
  675. lua_setfield(L, -3, name);
  676. /* a table is on the top of the stack and this is a subsequent,
  677. * list_add, append this value to table */
  678. } else {
  679. lua_pushstring(L, value);
  680. lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
  681. }
  682. /* non-list change, simply set/replace field */
  683. } else {
  684. lua_pushstring(L, value);
  685. lua_setfield(L, -3, name);
  686. }
  687. lua_pop(L, 1);
  688. } else {
  689. lua_pushstring(L, value);
  690. lua_setfield(L, -2, ".type");
  691. }
  692. lua_pop(L, 1);
  693. }
  694. static void
  695. uci_lua_changes_pkg(lua_State *L, struct uci_context *ctx, const char *package)
  696. {
  697. struct uci_package *p = NULL;
  698. struct uci_element *e;
  699. bool autoload = false;
  700. p = find_package(L, ctx, package, false);
  701. if (!p) {
  702. autoload = true;
  703. p = find_package(L, ctx, package, true);
  704. if (!p)
  705. return;
  706. }
  707. if (uci_list_empty(&p->delta) && uci_list_empty(&p->saved_delta))
  708. goto done;
  709. lua_newtable(L);
  710. uci_foreach_element(&p->saved_delta, e) {
  711. uci_lua_add_change(L, e);
  712. }
  713. uci_foreach_element(&p->delta, e) {
  714. uci_lua_add_change(L, e);
  715. }
  716. lua_setfield(L, -2, p->e.name);
  717. done:
  718. if (autoload)
  719. uci_unload(ctx, p);
  720. }
  721. static int
  722. uci_lua_changes(lua_State *L)
  723. {
  724. struct uci_context *ctx;
  725. const char *package = NULL;
  726. char **config = NULL;
  727. int nargs;
  728. int i, offset = 0;
  729. ctx = find_context(L, &offset);
  730. nargs = lua_gettop(L);
  731. switch(nargs - offset) {
  732. case 1:
  733. package = luaL_checkstring(L, 1 + offset);
  734. case 0:
  735. break;
  736. default:
  737. return luaL_error(L, "invalid argument count");
  738. }
  739. lua_newtable(L);
  740. if (package) {
  741. uci_lua_changes_pkg(L, ctx, package);
  742. return 1;
  743. }
  744. if ((uci_list_configs(ctx, &config) != UCI_OK) || !config)
  745. return 1;
  746. for (i = 0; config[i] != NULL; i++) {
  747. uci_lua_changes_pkg(L, ctx, config[i]);
  748. }
  749. free(config);
  750. return 1;
  751. }
  752. static int
  753. uci_lua_get_confdir(lua_State *L)
  754. {
  755. struct uci_context *ctx = find_context(L, NULL);
  756. lua_pushstring(L, ctx->confdir);
  757. return 1;
  758. }
  759. static int
  760. uci_lua_set_confdir(lua_State *L)
  761. {
  762. struct uci_context *ctx;
  763. int offset = 0;
  764. ctx = find_context(L, &offset);
  765. luaL_checkstring(L, 1 + offset);
  766. uci_set_confdir(ctx, lua_tostring(L, -1));
  767. return uci_push_status(L, ctx, false);
  768. }
  769. static int
  770. uci_lua_get_savedir(lua_State *L)
  771. {
  772. struct uci_context *ctx = find_context(L, NULL);
  773. lua_pushstring(L, ctx->savedir);
  774. return 1;
  775. }
  776. static int
  777. uci_lua_add_delta(lua_State *L)
  778. {
  779. struct uci_context *ctx;
  780. int offset = 0;
  781. ctx = find_context(L, &offset);
  782. luaL_checkstring(L, 1 + offset);
  783. uci_add_delta_path(ctx, lua_tostring(L, -1));
  784. return uci_push_status(L, ctx, false);
  785. }
  786. static int
  787. uci_lua_set_savedir(lua_State *L)
  788. {
  789. struct uci_context *ctx;
  790. int offset = 0;
  791. ctx = find_context(L, &offset);
  792. luaL_checkstring(L, 1 + offset);
  793. uci_set_savedir(ctx, lua_tostring(L, -1));
  794. return uci_push_status(L, ctx, false);
  795. }
  796. static int
  797. uci_lua_list_configs(lua_State *L)
  798. {
  799. struct uci_context *ctx;
  800. char **configs = NULL;
  801. char **ptr;
  802. int i = 1;
  803. ctx = find_context(L, NULL);
  804. if ((uci_list_configs(ctx, &configs) != UCI_OK) || !configs)
  805. return uci_push_status(L, ctx, false);
  806. lua_newtable(L);
  807. for (ptr = configs; *ptr; ptr++) {
  808. lua_pushstring(L, *ptr);
  809. lua_rawseti(L, -2, i++);
  810. }
  811. free(configs);
  812. return 1;
  813. }
  814. static int
  815. uci_lua_gc(lua_State *L)
  816. {
  817. struct uci_context **ctx;
  818. if (!lua_isuserdata(L, 1)) {
  819. if (!global_ctx)
  820. return 0;
  821. ctx = &global_ctx;
  822. } else {
  823. ctx = luaL_checkudata(L, 1, METANAME);
  824. if (!*ctx)
  825. return 0;
  826. }
  827. uci_free_context(*ctx);
  828. *ctx = NULL;
  829. return 0;
  830. }
  831. static int
  832. uci_lua_cursor(lua_State *L)
  833. {
  834. struct uci_context **u;
  835. int argc = lua_gettop(L);
  836. u = lua_newuserdata(L, sizeof(struct uci_context *));
  837. luaL_getmetatable(L, METANAME);
  838. lua_setmetatable(L, -2);
  839. *u = uci_alloc_context();
  840. if (!*u)
  841. return luaL_error(L, "Cannot allocate UCI context");
  842. switch (argc) {
  843. case 2:
  844. if (lua_isstring(L, 2) &&
  845. (uci_set_savedir(*u, luaL_checkstring(L, 2)) != UCI_OK))
  846. return luaL_error(L, "Unable to set savedir");
  847. /* fall through */
  848. case 1:
  849. if (lua_isstring(L, 1) &&
  850. (uci_set_confdir(*u, luaL_checkstring(L, 1)) != UCI_OK))
  851. return luaL_error(L, "Unable to set confdir");
  852. break;
  853. default:
  854. break;
  855. }
  856. return 1;
  857. }
  858. static const luaL_Reg uci[] = {
  859. { "__gc", uci_lua_gc },
  860. { "close", uci_lua_gc },
  861. { "cursor", uci_lua_cursor },
  862. { "load", uci_lua_load },
  863. { "unload", uci_lua_unload },
  864. { "get", uci_lua_get },
  865. { "get_all", uci_lua_get_all },
  866. { "add", uci_lua_add },
  867. { "set", uci_lua_set },
  868. { "rename", uci_lua_rename },
  869. { "save", uci_lua_save },
  870. { "delete", uci_lua_delete },
  871. { "commit", uci_lua_commit },
  872. { "revert", uci_lua_revert },
  873. { "reorder", uci_lua_reorder },
  874. { "changes", uci_lua_changes },
  875. { "foreach", uci_lua_foreach },
  876. { "add_history", uci_lua_add_delta },
  877. { "add_delta", uci_lua_add_delta },
  878. { "get_confdir", uci_lua_get_confdir },
  879. { "set_confdir", uci_lua_set_confdir },
  880. { "get_savedir", uci_lua_get_savedir },
  881. { "set_savedir", uci_lua_set_savedir },
  882. { "list_configs", uci_lua_list_configs },
  883. { NULL, NULL },
  884. };
  885. int
  886. luaopen_uci(lua_State *L)
  887. {
  888. /* create metatable */
  889. luaL_newmetatable(L, METANAME);
  890. /* metatable.__index = metatable */
  891. lua_pushvalue(L, -1);
  892. lua_setfield(L, -2, "__index");
  893. /* fill metatable */
  894. luaL_setfuncs(L, uci, 0);
  895. lua_pop(L, 1);
  896. /* create module */
  897. lua_newtable(L);
  898. lua_pushvalue(L, -1);
  899. luaL_setfuncs(L, uci, 0);
  900. lua_setglobal(L, MODNAME);
  901. return 1;
  902. }