110-plugin_support.patch 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. --- a/Makefile
  2. +++ b/Makefile
  3. @@ -7,7 +7,7 @@ DEBUG_TYPECAST=0
  4. include Makefile.inc
  5. -LIBS=-lc
  6. +LIBS=-lc -ldl
  7. SHLIB_FILE=libuci.$(SHLIB_EXT).$(VERSION)
  8. define add_feature
  9. @@ -23,6 +23,7 @@ ucimap.o: ucimap.c uci.h uci_config.h uc
  10. uci_config.h: FORCE
  11. @rm -f "[email protected]"
  12. + @echo "#define UCI_PREFIX \"$(prefix)\"" > "[email protected]"
  13. $(call add_feature,PLUGIN_SUPPORT)
  14. $(call add_feature,DEBUG)
  15. $(call add_feature,DEBUG_TYPECAST)
  16. @@ -33,10 +34,10 @@ uci_config.h: FORCE
  17. fi
  18. uci: cli.o libuci.$(SHLIB_EXT)
  19. - $(CC) -o $@ $< -L. -luci
  20. + $(CC) -o $@ $< -L. -luci $(LIBS)
  21. uci-static: cli.o libuci.a
  22. - $(CC) $(CFLAGS) -o $@ $^
  23. + $(CC) $(CFLAGS) -o $@ $^ $(LIBS)
  24. libuci-static.o: libuci.c $(LIBUCI_DEPS)
  25. $(CC) $(CFLAGS) -c -o $@ $<
  26. --- a/cli.c
  27. +++ b/cli.c
  28. @@ -27,6 +27,7 @@ static enum {
  29. CLI_FLAG_NOCOMMIT = (1 << 2),
  30. CLI_FLAG_BATCH = (1 << 3),
  31. CLI_FLAG_SHOW_EXT = (1 << 4),
  32. + CLI_FLAG_NOPLUGINS= (1 << 5),
  33. } flags;
  34. static FILE *input;
  35. @@ -136,6 +137,7 @@ static void uci_usage(void)
  36. "\t-c <path> set the search path for config files (default: /etc/config)\n"
  37. "\t-d <str> set the delimiter for list values in uci show\n"
  38. "\t-f <file> use <file> as input instead of stdin\n"
  39. + "\t-L do not load any plugins\n"
  40. "\t-m when importing, merge data into an existing package\n"
  41. "\t-n name unnamed sections on export (default)\n"
  42. "\t-N don't name unnamed sections\n"
  43. @@ -603,7 +605,7 @@ int main(int argc, char **argv)
  44. return 1;
  45. }
  46. - while((c = getopt(argc, argv, "c:d:f:mnNp:P:sSqX")) != -1) {
  47. + while((c = getopt(argc, argv, "c:d:f:LmnNp:P:sSqX")) != -1) {
  48. switch(c) {
  49. case 'c':
  50. uci_set_confdir(ctx, optarg);
  51. @@ -618,6 +620,9 @@ int main(int argc, char **argv)
  52. return 1;
  53. }
  54. break;
  55. + case 'L':
  56. + flags |= CLI_FLAG_NOPLUGINS;
  57. + break;
  58. case 'm':
  59. flags |= CLI_FLAG_MERGE;
  60. break;
  61. @@ -662,6 +667,10 @@ int main(int argc, char **argv)
  62. uci_usage();
  63. return 0;
  64. }
  65. +
  66. + if (!(flags & CLI_FLAG_NOPLUGINS))
  67. + uci_load_plugins(ctx, NULL);
  68. +
  69. ret = uci_cmd(argc - 1, argv + 1);
  70. if (input != stdin)
  71. fclose(input);
  72. --- a/history.c
  73. +++ b/history.c
  74. @@ -406,6 +406,17 @@ int uci_save(struct uci_context *ctx, st
  75. if ((asprintf(&filename, "%s/%s", ctx->savedir, p->e.name) < 0) || !filename)
  76. UCI_THROW(ctx, UCI_ERR_MEM);
  77. + uci_foreach_element(&ctx->hooks, tmp) {
  78. + struct uci_hook *hook = uci_to_hook(tmp);
  79. +
  80. + if (!hook->ops->set)
  81. + continue;
  82. +
  83. + uci_foreach_element(&p->history, e) {
  84. + hook->ops->set(hook->ops, p, uci_to_history(e));
  85. + }
  86. + }
  87. +
  88. ctx->err = 0;
  89. UCI_TRAP_SAVE(ctx, done);
  90. f = uci_open_stream(ctx, filename, SEEK_END, true, true);
  91. --- a/libuci.c
  92. +++ b/libuci.c
  93. @@ -22,6 +22,8 @@
  94. #include <string.h>
  95. #include <stdlib.h>
  96. #include <stdio.h>
  97. +#include <dlfcn.h>
  98. +#include <glob.h>
  99. #include "uci.h"
  100. static const char *uci_confdir = UCI_CONFDIR;
  101. @@ -39,6 +41,7 @@ static const char *uci_errstr[] = {
  102. };
  103. static void uci_cleanup(struct uci_context *ctx);
  104. +static void uci_unload_plugin(struct uci_context *ctx, struct uci_plugin *p);
  105. #include "uci_internal.h"
  106. #include "util.c"
  107. @@ -56,6 +59,8 @@ struct uci_context *uci_alloc_context(vo
  108. uci_list_init(&ctx->root);
  109. uci_list_init(&ctx->history_path);
  110. uci_list_init(&ctx->backends);
  111. + uci_list_init(&ctx->hooks);
  112. + uci_list_init(&ctx->plugins);
  113. ctx->flags = UCI_FLAG_STRICT | UCI_FLAG_SAVED_HISTORY;
  114. ctx->confdir = (char *) uci_confdir;
  115. @@ -86,6 +91,9 @@ void uci_free_context(struct uci_context
  116. uci_free_element(e);
  117. }
  118. UCI_TRAP_RESTORE(ctx);
  119. + uci_foreach_element_safe(&ctx->root, tmp, e) {
  120. + uci_unload_plugin(ctx, uci_to_plugin(e));
  121. + }
  122. free(ctx);
  123. ignore:
  124. @@ -209,9 +217,16 @@ int uci_commit(struct uci_context *ctx,
  125. int uci_load(struct uci_context *ctx, const char *name, struct uci_package **package)
  126. {
  127. struct uci_package *p;
  128. + struct uci_element *e;
  129. +
  130. UCI_HANDLE_ERR(ctx);
  131. UCI_ASSERT(ctx, ctx->backend && ctx->backend->load);
  132. p = ctx->backend->load(ctx, name);
  133. + uci_foreach_element(&ctx->hooks, e) {
  134. + struct uci_hook *h = uci_to_hook(e);
  135. + if (h->ops->load)
  136. + h->ops->load(h->ops, p);
  137. + }
  138. if (package)
  139. *package = p;
  140. @@ -280,3 +295,94 @@ int uci_set_backend(struct uci_context *
  141. ctx->backend = uci_to_backend(e);
  142. return 0;
  143. }
  144. +
  145. +int uci_add_hook(struct uci_context *ctx, const struct uci_hook_ops *ops)
  146. +{
  147. + struct uci_element *e;
  148. + struct uci_hook *h;
  149. +
  150. + UCI_HANDLE_ERR(ctx);
  151. +
  152. + /* check for duplicate elements */
  153. + uci_foreach_element(&ctx->hooks, e) {
  154. + h = uci_to_hook(e);
  155. + if (h->ops == ops)
  156. + return UCI_ERR_INVAL;
  157. + }
  158. +
  159. + h = uci_alloc_element(ctx, hook, "", 0);
  160. + h->ops = ops;
  161. + uci_list_init(&h->e.list);
  162. + uci_list_add(&ctx->hooks, &h->e.list);
  163. +
  164. + return 0;
  165. +}
  166. +
  167. +int uci_remove_hook(struct uci_context *ctx, const struct uci_hook_ops *ops)
  168. +{
  169. + struct uci_element *e;
  170. +
  171. + uci_foreach_element(&ctx->hooks, e) {
  172. + struct uci_hook *h = uci_to_hook(e);
  173. + if (h->ops == ops) {
  174. + uci_list_del(&e->list);
  175. + return 0;
  176. + }
  177. + }
  178. + return UCI_ERR_NOTFOUND;
  179. +}
  180. +
  181. +int uci_load_plugin(struct uci_context *ctx, const char *filename)
  182. +{
  183. + struct uci_plugin *p;
  184. + const struct uci_plugin_ops *ops;
  185. + void *dlh;
  186. +
  187. + UCI_HANDLE_ERR(ctx);
  188. + dlh = dlopen(filename, RTLD_GLOBAL|RTLD_NOW);
  189. + if (!dlh)
  190. + UCI_THROW(ctx, UCI_ERR_NOTFOUND);
  191. +
  192. + ops = dlsym(dlh, "uci_plugin");
  193. + if (!ops || !ops->attach || (ops->attach(ctx) != 0)) {
  194. + if (!ops)
  195. + fprintf(stderr, "No ops\n");
  196. + else if (!ops->attach)
  197. + fprintf(stderr, "No attach\n");
  198. + else
  199. + fprintf(stderr, "Other weirdness\n");
  200. + dlclose(dlh);
  201. + UCI_THROW(ctx, UCI_ERR_INVAL);
  202. + }
  203. +
  204. + p = uci_alloc_element(ctx, plugin, filename, 0);
  205. + p->dlh = dlh;
  206. + p->ops = ops;
  207. + uci_list_add(&ctx->plugins, &p->e.list);
  208. +
  209. + return 0;
  210. +}
  211. +
  212. +static void uci_unload_plugin(struct uci_context *ctx, struct uci_plugin *p)
  213. +{
  214. + if (p->ops->detach)
  215. + p->ops->detach(ctx);
  216. + dlclose(p->dlh);
  217. + uci_free_element(&p->e);
  218. +}
  219. +
  220. +int uci_load_plugins(struct uci_context *ctx, const char *pattern)
  221. +{
  222. + glob_t gl;
  223. + int i;
  224. +
  225. + if (!pattern)
  226. + pattern = UCI_PREFIX "/lib/uci_*.so";
  227. +
  228. + memset(&gl, 0, sizeof(gl));
  229. + glob(pattern, 0, NULL, &gl);
  230. + for (i = 0; i < gl.gl_pathc; i++)
  231. + uci_load_plugin(ctx, gl.gl_pathv[i]);
  232. +
  233. + return 0;
  234. +}
  235. --- a/uci.h
  236. +++ b/uci.h
  237. @@ -56,6 +56,8 @@ struct uci_list
  238. };
  239. struct uci_ptr;
  240. +struct uci_plugin;
  241. +struct uci_hook_ops;
  242. struct uci_element;
  243. struct uci_package;
  244. struct uci_section;
  245. @@ -275,6 +277,43 @@ extern int uci_set_backend(struct uci_co
  246. */
  247. extern bool uci_validate_text(const char *str);
  248. +
  249. +/**
  250. + * uci_add_hook: add a uci hook
  251. + * @ctx: uci context
  252. + * @ops: uci hook ops
  253. + *
  254. + * NB: allocated and freed by the caller
  255. + */
  256. +extern int uci_add_hook(struct uci_context *ctx, const struct uci_hook_ops *ops);
  257. +
  258. +/**
  259. + * uci_remove_hook: remove a uci hook
  260. + * @ctx: uci context
  261. + * @ops: uci hook ops
  262. + */
  263. +extern int uci_remove_hook(struct uci_context *ctx, const struct uci_hook_ops *ops);
  264. +
  265. +/**
  266. + * uci_load_plugin: load an uci plugin
  267. + * @ctx: uci context
  268. + * @filename: path to the uci plugin
  269. + *
  270. + * NB: plugin will be unloaded automatically when the context is freed
  271. + */
  272. +int uci_load_plugin(struct uci_context *ctx, const char *filename);
  273. +
  274. +/**
  275. + * uci_load_plugins: load all uci plugins from a directory
  276. + * @ctx: uci context
  277. + * @pattern: pattern of uci plugin files (optional)
  278. + *
  279. + * if pattern is NULL, then uci_load_plugins will call uci_load_plugin
  280. + * for uci_*.so in <prefix>/lib/
  281. + */
  282. +int uci_load_plugins(struct uci_context *ctx, const char *pattern);
  283. +
  284. +
  285. /* UCI data structures */
  286. enum uci_type {
  287. UCI_TYPE_UNSPEC = 0,
  288. @@ -285,6 +324,8 @@ enum uci_type {
  289. UCI_TYPE_PATH = 5,
  290. UCI_TYPE_BACKEND = 6,
  291. UCI_TYPE_ITEM = 7,
  292. + UCI_TYPE_HOOK = 8,
  293. + UCI_TYPE_PLUGIN = 9,
  294. };
  295. enum uci_option_type {
  296. @@ -346,6 +387,9 @@ struct uci_context
  297. bool internal, nested;
  298. char *buf;
  299. int bufsz;
  300. +
  301. + struct uci_list hooks;
  302. + struct uci_list plugins;
  303. };
  304. struct uci_package
  305. @@ -420,6 +464,31 @@ struct uci_ptr
  306. const char *value;
  307. };
  308. +struct uci_hook_ops
  309. +{
  310. + void (*load)(const struct uci_hook_ops *ops, struct uci_package *p);
  311. + void (*set)(const struct uci_hook_ops *ops, struct uci_package *p, struct uci_history *e);
  312. +};
  313. +
  314. +struct uci_hook
  315. +{
  316. + struct uci_element e;
  317. + const struct uci_hook_ops *ops;
  318. +};
  319. +
  320. +struct uci_plugin_ops
  321. +{
  322. + int (*attach)(struct uci_context *ctx);
  323. + void (*detach)(struct uci_context *ctx);
  324. +};
  325. +
  326. +struct uci_plugin
  327. +{
  328. + struct uci_element e;
  329. + const struct uci_plugin_ops *ops;
  330. + void *dlh;
  331. +};
  332. +
  333. /* linked list handling */
  334. #ifndef offsetof
  335. @@ -490,6 +559,8 @@ struct uci_ptr
  336. #define uci_type_package UCI_TYPE_PACKAGE
  337. #define uci_type_section UCI_TYPE_SECTION
  338. #define uci_type_option UCI_TYPE_OPTION
  339. +#define uci_type_hook UCI_TYPE_HOOK
  340. +#define uci_type_plugin UCI_TYPE_PLUGIN
  341. /* element typecasting */
  342. #ifdef UCI_DEBUG_TYPECAST
  343. @@ -499,6 +570,8 @@ static const char *uci_typestr[] = {
  344. [uci_type_package] = "package",
  345. [uci_type_section] = "section",
  346. [uci_type_option] = "option",
  347. + [uci_type_hook] = "hook",
  348. + [uci_type_plugin] = "plugin",
  349. };
  350. static void uci_typecast_error(int from, int to)
  351. @@ -520,6 +593,8 @@ BUILD_CAST(history)
  352. BUILD_CAST(package)
  353. BUILD_CAST(section)
  354. BUILD_CAST(option)
  355. +BUILD_CAST(hook)
  356. +BUILD_CAST(plugin)
  357. #else
  358. #define uci_to_backend(ptr) container_of(ptr, struct uci_backend, e)
  359. @@ -527,6 +602,8 @@ BUILD_CAST(option)
  360. #define uci_to_package(ptr) container_of(ptr, struct uci_package, e)
  361. #define uci_to_section(ptr) container_of(ptr, struct uci_section, e)
  362. #define uci_to_option(ptr) container_of(ptr, struct uci_option, e)
  363. +#define uci_to_hook(ptr) container_of(ptr, struct uci_hook, e)
  364. +#define uci_to_plugin(ptr) container_of(ptr, struct uci_plugin, e)
  365. #endif
  366. /**
  367. --- a/lua/uci.c
  368. +++ b/lua/uci.c
  369. @@ -765,6 +765,20 @@ uci_lua_add_history(lua_State *L)
  370. }
  371. static int
  372. +uci_lua_load_plugins(lua_State *L)
  373. +{
  374. + struct uci_context *ctx;
  375. + int ret, offset = 0;
  376. + const char *str = NULL;
  377. +
  378. + ctx = find_context(L, &offset);
  379. + if (lua_isstring(L, -1))
  380. + str = lua_tostring(L, -1);
  381. + ret = uci_load_plugins(ctx, str);
  382. + return uci_push_status(L, ctx, false);
  383. +}
  384. +
  385. +static int
  386. uci_lua_set_savedir(lua_State *L)
  387. {
  388. struct uci_context *ctx;
  389. @@ -831,6 +845,7 @@ static const luaL_Reg uci[] = {
  390. { "changes", uci_lua_changes },
  391. { "foreach", uci_lua_foreach },
  392. { "add_history", uci_lua_add_history },
  393. + { "load_plugins", uci_lua_load_plugins },
  394. { "get_confdir", uci_lua_get_confdir },
  395. { "set_confdir", uci_lua_set_confdir },
  396. { "get_savedir", uci_lua_get_savedir },