kscheme.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <assert.h>
  5. #include <faux/str.h>
  6. #include <faux/list.h>
  7. #include <faux/error.h>
  8. #include <klish/khelper.h>
  9. #include <klish/kplugin.h>
  10. #include <klish/kptype.h>
  11. #include <klish/kview.h>
  12. #include <klish/kscheme.h>
  13. struct kscheme_s {
  14. faux_list_t *plugins;
  15. faux_list_t *ptypes;
  16. faux_list_t *views;
  17. };
  18. // Simple methods
  19. // PLUGIN list
  20. KGET(scheme, faux_list_t *, plugins);
  21. KCMP_NESTED(scheme, plugin, name);
  22. KCMP_NESTED_BY_KEY(scheme, plugin, name);
  23. KADD_NESTED(scheme, plugin);
  24. KFIND_NESTED(scheme, plugin);
  25. KNESTED_LEN(scheme, plugin);
  26. KNESTED_ITER(scheme, plugin);
  27. KNESTED_EACH(scheme, plugin);
  28. // PTYPE list
  29. KGET(scheme, faux_list_t *, ptypes);
  30. KCMP_NESTED(scheme, ptype, name);
  31. KCMP_NESTED_BY_KEY(scheme, ptype, name);
  32. KADD_NESTED(scheme, ptype);
  33. KFIND_NESTED(scheme, ptype);
  34. KNESTED_LEN(scheme, ptype);
  35. KNESTED_ITER(scheme, ptype);
  36. KNESTED_EACH(scheme, ptype);
  37. // VIEW list
  38. KGET(scheme, faux_list_t *, views);
  39. KCMP_NESTED(scheme, view, name);
  40. KCMP_NESTED_BY_KEY(scheme, view, name);
  41. KADD_NESTED(scheme, view);
  42. KFIND_NESTED(scheme, view);
  43. KNESTED_LEN(scheme, view);
  44. KNESTED_ITER(scheme, view);
  45. KNESTED_EACH(scheme, view);
  46. kscheme_t *kscheme_new(void)
  47. {
  48. kscheme_t *scheme = NULL;
  49. scheme = faux_zmalloc(sizeof(*scheme));
  50. assert(scheme);
  51. if (!scheme)
  52. return NULL;
  53. // PLUGIN list
  54. scheme->plugins = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
  55. kscheme_plugin_compare, kscheme_plugin_kcompare,
  56. (void (*)(void *))kplugin_free);
  57. assert(scheme->plugins);
  58. // PTYPE list
  59. scheme->ptypes = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
  60. kscheme_ptype_compare, kscheme_ptype_kcompare,
  61. (void (*)(void *))kptype_free);
  62. assert(scheme->ptypes);
  63. // VIEW list
  64. scheme->views = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
  65. kscheme_view_compare, kscheme_view_kcompare,
  66. (void (*)(void *))kview_free);
  67. assert(scheme->views);
  68. return scheme;
  69. }
  70. void kscheme_free(kscheme_t *scheme)
  71. {
  72. if (!scheme)
  73. return;
  74. faux_list_free(scheme->plugins);
  75. faux_list_free(scheme->ptypes);
  76. faux_list_free(scheme->views);
  77. faux_free(scheme);
  78. }
  79. #define TAG "PLUGIN"
  80. bool_t kscheme_load_plugins(kscheme_t *scheme, kcontext_t *context,
  81. faux_error_t *error)
  82. {
  83. bool_t retcode = BOOL_TRUE;
  84. kscheme_plugins_node_t *iter = NULL;
  85. kplugin_t *plugin = NULL;
  86. assert(scheme);
  87. if (!scheme)
  88. return BOOL_FALSE;
  89. assert(scheme->plugins);
  90. if (!context)
  91. return BOOL_FALSE;
  92. iter = kscheme_plugins_iter(scheme);
  93. while ((plugin = kscheme_plugins_each(&iter))) {
  94. int init_retcode = 0;
  95. if (!kplugin_load(plugin)) {
  96. faux_error_sprintf(error,
  97. TAG ": Can't load plugin \"%s\"",
  98. kplugin_name(plugin));
  99. retcode = BOOL_FALSE;
  100. continue; // Try to load all plugins
  101. }
  102. if ((init_retcode = kplugin_init(plugin, context)) < 0) {
  103. faux_error_sprintf(error,
  104. TAG ": Can't init plugin \"%s\" (%d)",
  105. kplugin_name(plugin), init_retcode);
  106. retcode = BOOL_FALSE;
  107. continue;
  108. }
  109. }
  110. return retcode;
  111. }
  112. bool_t kscheme_fini_plugins(kscheme_t *scheme, kcontext_t *context,
  113. faux_error_t *error)
  114. {
  115. kscheme_plugins_node_t *iter = NULL;
  116. kplugin_t *plugin = NULL;
  117. assert(scheme);
  118. if (!scheme)
  119. return BOOL_FALSE;
  120. assert(scheme->plugins);
  121. if (!context)
  122. return BOOL_FALSE;
  123. iter = kscheme_plugins_iter(scheme);
  124. while ((plugin = kscheme_plugins_each(&iter))) {
  125. int fini_retcode = -1;
  126. if ((fini_retcode = kplugin_fini(plugin, context)) < 0) {
  127. faux_error_sprintf(error,
  128. TAG ": Can't fini plugin \"%s\" (%d)",
  129. kplugin_name(plugin), fini_retcode);
  130. }
  131. }
  132. return BOOL_TRUE;
  133. }
  134. bool_t kscheme_fini(kscheme_t *scheme, kcontext_t *context, faux_error_t *error)
  135. {
  136. assert(scheme);
  137. if (!scheme)
  138. return BOOL_FALSE;
  139. if (!context)
  140. return BOOL_FALSE;
  141. if (!kscheme_fini_plugins(scheme, context, error))
  142. return BOOL_FALSE;
  143. return BOOL_TRUE;
  144. }
  145. /** @brief Prepares schema for execution.
  146. *
  147. * It loads plugins, link unresolved symbols, then iterates all the
  148. * objects and link them to each other, check access
  149. * permissions. Without this function the schema is not fully functional.
  150. */
  151. bool_t kscheme_prepare(kscheme_t *scheme, kcontext_t *context, faux_error_t *error)
  152. {
  153. kscheme_views_node_t *views_iter = NULL;
  154. kview_t *view = NULL;
  155. assert(scheme);
  156. if (!scheme)
  157. return BOOL_FALSE;
  158. if (!context)
  159. return BOOL_FALSE;
  160. if (!kscheme_load_plugins(scheme, context, error))
  161. return BOOL_FALSE;
  162. // Iterate VIEWs
  163. views_iter = kscheme_views_iter(scheme);
  164. while ((view = kscheme_views_each(&views_iter))) {
  165. kview_commands_node_t *commands_iter = NULL;
  166. kcommand_t *command = NULL;
  167. printf("VIEW: %s\n", kview_name(view));
  168. // Iterate COMMANDs
  169. commands_iter = kview_commands_iter(view);
  170. while ((command = kview_commands_each(&commands_iter))) {
  171. // kview_commands_node_t *commands_iter = NULL;
  172. // kcommand_t *command = NULL;
  173. printf("COMMAND: %s\n", kcommand_name(command));
  174. }
  175. }
  176. #if 0
  177. clish_command_t *cmd;
  178. clish_view_t *view;
  179. clish_nspace_t *nspace;
  180. lub_list_t *view_tree, *nspace_tree;
  181. lub_list_node_t *nspace_iter, *view_iter;
  182. lub_bintree_t *cmd_tree;
  183. lub_bintree_iterator_t cmd_iter;
  184. clish_hook_access_fn_t *access_fn = NULL;
  185. clish_paramv_t *paramv;
  186. int i = 0;
  187. /* Iterate the VIEWs */
  188. view_tree = this->view_tree;
  189. view_iter = lub_list_iterator_init(view_tree);
  190. while(view_iter) {
  191. lub_list_node_t *old_view_iter;
  192. view = (clish_view_t *)lub_list_node__get_data(view_iter);
  193. old_view_iter = view_iter;
  194. view_iter = lub_list_node__get_next(view_iter);
  195. /* Check access rights for the VIEW */
  196. if (access_fn && clish_view__get_access(view) &&
  197. access_fn(this, clish_view__get_access(view))) {
  198. #ifdef DEBUG
  199. fprintf(stderr, "Warning: Access denied. Remove VIEW \"%s\"\n",
  200. clish_view__get_name(view));
  201. #endif
  202. lub_list_del(view_tree, old_view_iter);
  203. lub_list_node_free(old_view_iter);
  204. clish_view_delete(view);
  205. continue;
  206. }
  207. /* Iterate the NAMESPACEs */
  208. nspace_tree = clish_view__get_nspaces(view);
  209. nspace_iter = lub_list__get_head(nspace_tree);
  210. while(nspace_iter) {
  211. clish_view_t *ref_view;
  212. lub_list_node_t *old_nspace_iter;
  213. nspace = (clish_nspace_t *)lub_list_node__get_data(nspace_iter);
  214. old_nspace_iter = nspace_iter;
  215. nspace_iter = lub_list_node__get_next(nspace_iter);
  216. /* Resolve NAMESPACEs and remove unresolved ones */
  217. ref_view = clish_shell_find_view(this, clish_nspace__get_view_name(nspace));
  218. if (!ref_view) {
  219. #ifdef DEBUG
  220. fprintf(stderr, "Warning: Remove unresolved NAMESPACE \"%s\" from \"%s\" VIEW\n",
  221. clish_nspace__get_view_name(nspace), clish_view__get_name(view));
  222. #endif
  223. lub_list_del(nspace_tree, old_nspace_iter);
  224. lub_list_node_free(old_nspace_iter);
  225. clish_nspace_delete(nspace);
  226. continue;
  227. }
  228. clish_nspace__set_view(nspace, ref_view);
  229. clish_nspace__set_view_name(nspace, NULL); /* Free some memory */
  230. /* Check access rights for the NAMESPACE */
  231. if (access_fn && (
  232. /* Check NAMESPASE owned access */
  233. (clish_nspace__get_access(nspace) && access_fn(this, clish_nspace__get_access(nspace)))
  234. ||
  235. /* Check referenced VIEW's access */
  236. (clish_view__get_access(ref_view) && access_fn(this, clish_view__get_access(ref_view)))
  237. )) {
  238. #ifdef DEBUG
  239. fprintf(stderr, "Warning: Access denied. Remove NAMESPACE \"%s\" from \"%s\" VIEW\n",
  240. clish_nspace__get_view_name(nspace), clish_view__get_name(view));
  241. #endif
  242. lub_list_del(nspace_tree, old_nspace_iter);
  243. lub_list_node_free(old_nspace_iter);
  244. clish_nspace_delete(nspace);
  245. continue;
  246. }
  247. }
  248. /* Iterate the COMMANDs */
  249. cmd_tree = clish_view__get_tree(view);
  250. cmd = lub_bintree_findfirst(cmd_tree);
  251. for (lub_bintree_iterator_init(&cmd_iter, cmd_tree, cmd);
  252. cmd; cmd = lub_bintree_iterator_next(&cmd_iter)) {
  253. int cmd_is_alias = clish_command__get_alias(cmd)?1:0;
  254. clish_param_t *args = NULL;
  255. /* Check access rights for the COMMAND */
  256. if (access_fn && clish_command__get_access(cmd) &&
  257. access_fn(this, clish_command__get_access(cmd))) {
  258. #ifdef DEBUG
  259. fprintf(stderr, "Warning: Access denied. Remove COMMAND \"%s\" from VIEW \"%s\"\n",
  260. clish_command__get_name(cmd), clish_view__get_name(view));
  261. #endif
  262. lub_bintree_remove(cmd_tree, cmd);
  263. clish_command_delete(cmd);
  264. continue;
  265. }
  266. /* Resolve command aliases */
  267. if (cmd_is_alias) {
  268. clish_view_t *aview;
  269. clish_command_t *cmdref;
  270. const char *alias_view = clish_command__get_alias_view(cmd);
  271. if (!alias_view)
  272. aview = clish_command__get_pview(cmd);
  273. else
  274. aview = clish_shell_find_view(this, alias_view);
  275. if (!aview /* Removed or broken VIEW */
  276. ||
  277. /* Removed or broken referenced COMMAND */
  278. !(cmdref = clish_view_find_command(aview, clish_command__get_alias(cmd), BOOL_FALSE))
  279. ) {
  280. #ifdef DEBUG
  281. fprintf(stderr, "Warning: Remove unresolved link \"%s\" from \"%s\" VIEW\n",
  282. clish_command__get_name(cmd), clish_view__get_name(view));
  283. #endif
  284. lub_bintree_remove(cmd_tree, cmd);
  285. clish_command_delete(cmd);
  286. continue;
  287. /*fprintf(stderr, CLISH_XML_ERROR_STR"Broken VIEW for alias \"%s\"\n",
  288. clish_command__get_name(cmd));
  289. return -1; */
  290. /*fprintf(stderr, CLISH_XML_ERROR_STR"Broken alias \"%s\"\n",
  291. clish_command__get_name(cmd));
  292. return -1; */
  293. }
  294. if (!clish_command_alias_to_link(cmd, cmdref)) {
  295. fprintf(stderr, CLISH_XML_ERROR_STR"Something wrong with alias \"%s\"\n",
  296. clish_command__get_name(cmd));
  297. return -1;
  298. }
  299. /* Check access rights for newly constructed COMMAND.
  300. Now the link has access filed from referenced command.
  301. */
  302. if (access_fn && clish_command__get_access(cmd) &&
  303. access_fn(this, clish_command__get_access(cmd))) {
  304. #ifdef DEBUG
  305. fprintf(stderr, "Warning: Access denied. Remove COMMAND \"%s\" from VIEW \"%s\"\n",
  306. clish_command__get_name(cmd), clish_view__get_name(view));
  307. #endif
  308. lub_bintree_remove(cmd_tree, cmd);
  309. clish_command_delete(cmd);
  310. continue;
  311. }
  312. }
  313. if (cmd_is_alias) /* Don't duplicate paramv processing for aliases */
  314. continue;
  315. /* Iterate PARAMeters */
  316. paramv = clish_command__get_paramv(cmd);
  317. if (iterate_paramv(this, paramv, access_fn) < 0)
  318. return -1;
  319. /* Resolve PTYPE for args */
  320. if ((args = clish_command__get_args(cmd))) {
  321. if (!resolve_ptype(this, args))
  322. return -1;
  323. }
  324. }
  325. }
  326. #endif
  327. return BOOL_TRUE;
  328. }