uci.c 20 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072
  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_element *e = NULL;
  321. struct uci_ptr ptr;
  322. int offset = 0;
  323. int nret = 1;
  324. char *s = NULL;
  325. int err = UCI_ERR_NOTFOUND;
  326. ctx = find_context(L, &offset);
  327. if (lookup_args(L, ctx, offset, &ptr, &s))
  328. goto error;
  329. lookup_ptr(ctx, &ptr, NULL, true);
  330. if (!all && !ptr.s) {
  331. ctx->err = UCI_ERR_INVAL;
  332. goto error;
  333. }
  334. if (!(ptr.flags & UCI_LOOKUP_COMPLETE)) {
  335. ctx->err = UCI_ERR_NOTFOUND;
  336. goto error;
  337. }
  338. err = UCI_OK;
  339. e = ptr.last;
  340. switch(e->type) {
  341. case UCI_TYPE_PACKAGE:
  342. uci_push_package(L, ptr.p);
  343. break;
  344. case UCI_TYPE_SECTION:
  345. if (all) {
  346. uci_push_section(L, ptr.s, -1);
  347. }
  348. else {
  349. lua_pushstring(L, ptr.s->type);
  350. lua_pushstring(L, ptr.s->e.name);
  351. nret++;
  352. }
  353. break;
  354. case UCI_TYPE_OPTION:
  355. uci_push_option(L, ptr.o);
  356. break;
  357. default:
  358. ctx->err = UCI_ERR_INVAL;
  359. goto error;
  360. }
  361. if (s)
  362. free(s);
  363. if (!err)
  364. return nret;
  365. error:
  366. if (s)
  367. free(s);
  368. lua_pushnil(L);
  369. return uci_push_status(L, ctx, true);
  370. }
  371. static int
  372. uci_lua_get(lua_State *L)
  373. {
  374. return uci_lua_get_any(L, false);
  375. }
  376. static int
  377. uci_lua_get_all(lua_State *L)
  378. {
  379. return uci_lua_get_any(L, true);
  380. }
  381. static int
  382. uci_lua_add(lua_State *L)
  383. {
  384. struct uci_context *ctx;
  385. struct uci_section *s = NULL;
  386. struct uci_package *p;
  387. const char *package;
  388. const char *type;
  389. const char *name = NULL;
  390. int offset = 0;
  391. ctx = find_context(L, &offset);
  392. package = luaL_checkstring(L, 1 + offset);
  393. type = luaL_checkstring(L, 2 + offset);
  394. p = find_package(L, ctx, package, true);
  395. if (!p)
  396. goto fail;
  397. if (uci_add_section(ctx, p, type, &s) || !s)
  398. goto fail;
  399. name = s->e.name;
  400. lua_pushstring(L, name);
  401. return 1;
  402. fail:
  403. lua_pushnil(L);
  404. return uci_push_status(L, ctx, true);
  405. }
  406. static int
  407. uci_lua_delete(lua_State *L)
  408. {
  409. struct uci_context *ctx;
  410. struct uci_ptr ptr;
  411. int offset = 0;
  412. char *s = NULL;
  413. ctx = find_context(L, &offset);
  414. if (lookup_args(L, ctx, offset, &ptr, &s))
  415. goto error;
  416. uci_delete(ctx, &ptr);
  417. error:
  418. if (s)
  419. free(s);
  420. return uci_push_status(L, ctx, false);
  421. }
  422. static int
  423. uci_lua_rename(lua_State *L)
  424. {
  425. struct uci_context *ctx;
  426. struct uci_ptr ptr;
  427. int err = UCI_ERR_MEM;
  428. char *s = NULL;
  429. int nargs, offset = 0;
  430. ctx = find_context(L, &offset);
  431. nargs = lua_gettop(L);
  432. if (lookup_args(L, ctx, offset, &ptr, &s))
  433. goto error;
  434. switch(nargs - offset) {
  435. case 1:
  436. /* Format: uci.set("p.s.o=v") or uci.set("p.s=v") */
  437. break;
  438. case 4:
  439. /* Format: uci.set("p", "s", "o", "v") */
  440. ptr.value = luaL_checkstring(L, nargs);
  441. break;
  442. case 3:
  443. /* Format: uci.set("p", "s", "v") */
  444. ptr.value = ptr.option;
  445. ptr.option = NULL;
  446. break;
  447. default:
  448. ctx->err = UCI_ERR_INVAL;
  449. goto error;
  450. }
  451. err = lookup_ptr(ctx, &ptr, NULL, true);
  452. if (err)
  453. goto error;
  454. if (((ptr.s == NULL) && (ptr.option != NULL)) || (ptr.value == NULL)) {
  455. ctx->err = UCI_ERR_INVAL;
  456. goto error;
  457. }
  458. err = uci_rename(ctx, &ptr);
  459. if (err)
  460. goto error;
  461. error:
  462. if (s)
  463. free(s);
  464. return uci_push_status(L, ctx, false);
  465. }
  466. static int
  467. uci_lua_reorder(lua_State *L)
  468. {
  469. struct uci_context *ctx;
  470. struct uci_ptr ptr;
  471. int err = UCI_ERR_MEM;
  472. char *s = NULL;
  473. int nargs, offset = 0;
  474. ctx = find_context(L, &offset);
  475. nargs = lua_gettop(L);
  476. if (lookup_args(L, ctx, offset, &ptr, &s))
  477. goto error;
  478. switch(nargs - offset) {
  479. case 1:
  480. /* Format: uci.set("p.s=v") or uci.set("p.s=v") */
  481. if (ptr.option) {
  482. ctx->err = UCI_ERR_INVAL;
  483. goto error;
  484. }
  485. break;
  486. case 3:
  487. /* Format: uci.set("p", "s", "v") */
  488. ptr.value = ptr.option;
  489. ptr.option = NULL;
  490. break;
  491. default:
  492. ctx->err = UCI_ERR_INVAL;
  493. goto error;
  494. }
  495. err = lookup_ptr(ctx, &ptr, NULL, true);
  496. if (err)
  497. goto error;
  498. if ((ptr.s == NULL) || (ptr.value == NULL)) {
  499. ctx->err = UCI_ERR_INVAL;
  500. goto error;
  501. }
  502. err = uci_reorder_section(ctx, ptr.s, strtoul(ptr.value, NULL, 10));
  503. if (err)
  504. goto error;
  505. error:
  506. if (s)
  507. free(s);
  508. return uci_push_status(L, ctx, false);
  509. }
  510. static int
  511. uci_lua_set(lua_State *L)
  512. {
  513. struct uci_context *ctx;
  514. struct uci_ptr ptr;
  515. bool istable = false;
  516. int err = UCI_ERR_MEM;
  517. char *s = NULL;
  518. const char *v;
  519. unsigned int i;
  520. int nargs, offset = 0;
  521. ctx = find_context(L, &offset);
  522. nargs = lua_gettop(L);
  523. if (lookup_args(L, ctx, offset, &ptr, &s))
  524. goto error;
  525. switch(nargs - offset) {
  526. case 1:
  527. /* Format: uci.set("p.s.o=v") or uci.set("p.s=v") */
  528. break;
  529. case 4:
  530. /* Format: uci.set("p", "s", "o", "v") */
  531. if (lua_istable(L, nargs)) {
  532. if (lua_rawlen(L, nargs) < 1) {
  533. free(s);
  534. return luaL_error(L, "Cannot set an uci option to an empty table value");
  535. }
  536. lua_rawgeti(L, nargs, 1);
  537. ptr.value = luaL_checkstring(L, -1);
  538. lua_pop(L, 1);
  539. istable = true;
  540. } else {
  541. ptr.value = luaL_checkstring(L, nargs);
  542. }
  543. break;
  544. case 3:
  545. /* Format: uci.set("p", "s", "v") */
  546. ptr.value = ptr.option;
  547. ptr.option = NULL;
  548. break;
  549. default:
  550. ctx->err = UCI_ERR_INVAL;
  551. goto error;
  552. }
  553. err = lookup_ptr(ctx, &ptr, NULL, true);
  554. if (err)
  555. goto error;
  556. if (((ptr.s == NULL) && (ptr.option != NULL)) || (ptr.value == NULL)) {
  557. ctx->err = UCI_ERR_INVAL;
  558. goto error;
  559. }
  560. if (istable) {
  561. if (lua_rawlen(L, nargs) == 1) {
  562. i = 1;
  563. if (ptr.o) {
  564. v = ptr.value;
  565. ptr.value = NULL;
  566. err = uci_delete(ctx, &ptr);
  567. if (err)
  568. goto error;
  569. ptr.value = v;
  570. }
  571. } else {
  572. i = 2;
  573. err = uci_set(ctx, &ptr);
  574. if (err)
  575. goto error;
  576. }
  577. for (; i <= lua_rawlen(L, nargs); i++) {
  578. lua_rawgeti(L, nargs, i);
  579. ptr.value = luaL_checkstring(L, -1);
  580. err = uci_add_list(ctx, &ptr);
  581. lua_pop(L, 1);
  582. if (err)
  583. goto error;
  584. }
  585. } else {
  586. err = uci_set(ctx, &ptr);
  587. if (err)
  588. goto error;
  589. }
  590. error:
  591. if (s)
  592. free(s);
  593. return uci_push_status(L, ctx, false);
  594. }
  595. enum pkg_cmd {
  596. CMD_SAVE,
  597. CMD_COMMIT,
  598. CMD_REVERT
  599. };
  600. static int
  601. uci_lua_package_cmd(lua_State *L, enum pkg_cmd cmd)
  602. {
  603. struct uci_context *ctx;
  604. struct uci_element *e, *tmp;
  605. struct uci_ptr ptr;
  606. char *s = NULL;
  607. int nargs, offset = 0;
  608. ctx = find_context(L, &offset);
  609. nargs = lua_gettop(L);
  610. if ((cmd != CMD_REVERT) && (nargs - offset > 1))
  611. goto err;
  612. if (lookup_args(L, ctx, offset, &ptr, &s))
  613. goto err;
  614. lookup_ptr(ctx, &ptr, NULL, true);
  615. uci_foreach_element_safe(&ctx->root, tmp, e) {
  616. struct uci_package *p = uci_to_package(e);
  617. if (ptr.p && (ptr.p != p))
  618. continue;
  619. ptr.p = p;
  620. switch(cmd) {
  621. case CMD_COMMIT:
  622. uci_commit(ctx, &p, false);
  623. break;
  624. case CMD_SAVE:
  625. uci_save(ctx, p);
  626. break;
  627. case CMD_REVERT:
  628. uci_revert(ctx, &ptr);
  629. break;
  630. }
  631. }
  632. err:
  633. if (s)
  634. free(s);
  635. return uci_push_status(L, ctx, false);
  636. }
  637. static int
  638. uci_lua_save(lua_State *L)
  639. {
  640. return uci_lua_package_cmd(L, CMD_SAVE);
  641. }
  642. static int
  643. uci_lua_commit(lua_State *L)
  644. {
  645. return uci_lua_package_cmd(L, CMD_COMMIT);
  646. }
  647. static int
  648. uci_lua_revert(lua_State *L)
  649. {
  650. return uci_lua_package_cmd(L, CMD_REVERT);
  651. }
  652. static void
  653. uci_lua_add_change(lua_State *L, struct uci_element *e)
  654. {
  655. struct uci_delta *h;
  656. const char *name;
  657. const char *value;
  658. h = uci_to_delta(e);
  659. if (!h->section)
  660. return;
  661. lua_getfield(L, -1, h->section);
  662. if (lua_isnil(L, -1)) {
  663. lua_pop(L, 1);
  664. lua_newtable(L);
  665. lua_pushvalue(L, -1); /* copy for setfield */
  666. lua_setfield(L, -3, h->section);
  667. }
  668. name = h->e.name;
  669. value = h->value ? h->value : "";
  670. if (name) {
  671. lua_getfield(L, -1, name);
  672. /* this delta is a list add operation */
  673. if (h->cmd == UCI_CMD_LIST_ADD) {
  674. /* there seems to be no table yet */
  675. if (!lua_istable(L, -1)) {
  676. lua_newtable(L);
  677. /* if there is a value on the stack already, add */
  678. if (!lua_isnil(L, -2)) {
  679. lua_pushvalue(L, -2);
  680. lua_rawseti(L, -2, 1);
  681. lua_pushstring(L, value);
  682. lua_rawseti(L, -2, 2);
  683. /* this is the first table item */
  684. } else {
  685. lua_pushstring(L, value);
  686. lua_rawseti(L, -2, 1);
  687. }
  688. lua_setfield(L, -3, name);
  689. /* a table is on the top of the stack and this is a subsequent,
  690. * list_add, append this value to table */
  691. } else {
  692. lua_pushstring(L, value);
  693. lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
  694. }
  695. /* non-list change, simply set/replace field */
  696. } else {
  697. lua_pushstring(L, value);
  698. lua_setfield(L, -3, name);
  699. }
  700. lua_pop(L, 1);
  701. } else {
  702. lua_pushstring(L, value);
  703. lua_setfield(L, -2, ".type");
  704. }
  705. lua_pop(L, 1);
  706. }
  707. static void
  708. uci_lua_changes_pkg(lua_State *L, struct uci_context *ctx, const char *package)
  709. {
  710. struct uci_package *p = NULL;
  711. struct uci_element *e;
  712. bool autoload = false;
  713. p = find_package(L, ctx, package, false);
  714. if (!p) {
  715. autoload = true;
  716. p = find_package(L, ctx, package, true);
  717. if (!p)
  718. return;
  719. }
  720. if (uci_list_empty(&p->delta) && uci_list_empty(&p->saved_delta))
  721. goto done;
  722. lua_newtable(L);
  723. uci_foreach_element(&p->saved_delta, e) {
  724. uci_lua_add_change(L, e);
  725. }
  726. uci_foreach_element(&p->delta, e) {
  727. uci_lua_add_change(L, e);
  728. }
  729. lua_setfield(L, -2, p->e.name);
  730. done:
  731. if (autoload)
  732. uci_unload(ctx, p);
  733. }
  734. static int
  735. uci_lua_changes(lua_State *L)
  736. {
  737. struct uci_context *ctx;
  738. const char *package = NULL;
  739. char **config = NULL;
  740. int nargs;
  741. int i, offset = 0;
  742. ctx = find_context(L, &offset);
  743. nargs = lua_gettop(L);
  744. switch(nargs - offset) {
  745. case 1:
  746. package = luaL_checkstring(L, 1 + offset);
  747. case 0:
  748. break;
  749. default:
  750. return luaL_error(L, "invalid argument count");
  751. }
  752. lua_newtable(L);
  753. if (package) {
  754. uci_lua_changes_pkg(L, ctx, package);
  755. return 1;
  756. }
  757. if ((uci_list_configs(ctx, &config) != UCI_OK) || !config)
  758. return 1;
  759. for (i = 0; config[i] != NULL; i++) {
  760. uci_lua_changes_pkg(L, ctx, config[i]);
  761. }
  762. free(config);
  763. return 1;
  764. }
  765. static int
  766. uci_lua_get_confdir(lua_State *L)
  767. {
  768. struct uci_context *ctx = find_context(L, NULL);
  769. lua_pushstring(L, ctx->confdir);
  770. return 1;
  771. }
  772. static int
  773. uci_lua_set_confdir(lua_State *L)
  774. {
  775. struct uci_context *ctx;
  776. int offset = 0;
  777. ctx = find_context(L, &offset);
  778. luaL_checkstring(L, 1 + offset);
  779. uci_set_confdir(ctx, lua_tostring(L, -1));
  780. return uci_push_status(L, ctx, false);
  781. }
  782. static int
  783. uci_lua_get_savedir(lua_State *L)
  784. {
  785. struct uci_context *ctx = find_context(L, NULL);
  786. lua_pushstring(L, ctx->savedir);
  787. return 1;
  788. }
  789. static int
  790. uci_lua_add_delta(lua_State *L)
  791. {
  792. struct uci_context *ctx;
  793. int offset = 0;
  794. ctx = find_context(L, &offset);
  795. luaL_checkstring(L, 1 + offset);
  796. uci_add_delta_path(ctx, lua_tostring(L, -1));
  797. return uci_push_status(L, ctx, false);
  798. }
  799. static int
  800. uci_lua_set_savedir(lua_State *L)
  801. {
  802. struct uci_context *ctx;
  803. int offset = 0;
  804. ctx = find_context(L, &offset);
  805. luaL_checkstring(L, 1 + offset);
  806. uci_set_savedir(ctx, lua_tostring(L, -1));
  807. return uci_push_status(L, ctx, false);
  808. }
  809. static int
  810. uci_lua_list_configs(lua_State *L)
  811. {
  812. struct uci_context *ctx;
  813. char **configs = NULL;
  814. char **ptr;
  815. int i = 1;
  816. ctx = find_context(L, NULL);
  817. if ((uci_list_configs(ctx, &configs) != UCI_OK) || !configs)
  818. return uci_push_status(L, ctx, false);
  819. lua_newtable(L);
  820. for (ptr = configs; *ptr; ptr++) {
  821. lua_pushstring(L, *ptr);
  822. lua_rawseti(L, -2, i++);
  823. }
  824. free(configs);
  825. return 1;
  826. }
  827. static int
  828. uci_lua_gc(lua_State *L)
  829. {
  830. struct uci_context **ctx;
  831. if (!lua_isuserdata(L, 1)) {
  832. if (!global_ctx)
  833. return 0;
  834. ctx = &global_ctx;
  835. } else {
  836. ctx = luaL_checkudata(L, 1, METANAME);
  837. if (!*ctx)
  838. return 0;
  839. }
  840. uci_free_context(*ctx);
  841. *ctx = NULL;
  842. return 0;
  843. }
  844. static int
  845. uci_lua_cursor(lua_State *L)
  846. {
  847. struct uci_context **u;
  848. int argc = lua_gettop(L);
  849. u = lua_newuserdata(L, sizeof(struct uci_context *));
  850. luaL_getmetatable(L, METANAME);
  851. lua_setmetatable(L, -2);
  852. *u = uci_alloc_context();
  853. if (!*u)
  854. return luaL_error(L, "Cannot allocate UCI context");
  855. switch (argc) {
  856. case 2:
  857. if (lua_isstring(L, 2) &&
  858. (uci_set_savedir(*u, luaL_checkstring(L, 2)) != UCI_OK))
  859. return luaL_error(L, "Unable to set savedir");
  860. /* fall through */
  861. case 1:
  862. if (lua_isstring(L, 1) &&
  863. (uci_set_confdir(*u, luaL_checkstring(L, 1)) != UCI_OK))
  864. return luaL_error(L, "Unable to set confdir");
  865. break;
  866. default:
  867. break;
  868. }
  869. return 1;
  870. }
  871. static const luaL_Reg uci[] = {
  872. { "__gc", uci_lua_gc },
  873. { "close", uci_lua_gc },
  874. { "cursor", uci_lua_cursor },
  875. { "load", uci_lua_load },
  876. { "unload", uci_lua_unload },
  877. { "get", uci_lua_get },
  878. { "get_all", uci_lua_get_all },
  879. { "add", uci_lua_add },
  880. { "set", uci_lua_set },
  881. { "rename", uci_lua_rename },
  882. { "save", uci_lua_save },
  883. { "delete", uci_lua_delete },
  884. { "commit", uci_lua_commit },
  885. { "revert", uci_lua_revert },
  886. { "reorder", uci_lua_reorder },
  887. { "changes", uci_lua_changes },
  888. { "foreach", uci_lua_foreach },
  889. { "add_history", uci_lua_add_delta },
  890. { "add_delta", uci_lua_add_delta },
  891. { "get_confdir", uci_lua_get_confdir },
  892. { "set_confdir", uci_lua_set_confdir },
  893. { "get_savedir", uci_lua_get_savedir },
  894. { "set_savedir", uci_lua_set_savedir },
  895. { "list_configs", uci_lua_list_configs },
  896. { NULL, NULL },
  897. };
  898. int
  899. luaopen_uci(lua_State *L)
  900. {
  901. /* create metatable */
  902. luaL_newmetatable(L, METANAME);
  903. /* metatable.__index = metatable */
  904. lua_pushvalue(L, -1);
  905. lua_setfield(L, -2, "__index");
  906. /* fill metatable */
  907. luaL_setfuncs(L, uci, 0);
  908. lua_pop(L, 1);
  909. /* create module */
  910. lua_newtable(L);
  911. lua_pushvalue(L, -1);
  912. luaL_setfuncs(L, uci, 0);
  913. lua_setglobal(L, MODNAME);
  914. return 1;
  915. }