plugin.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. /*
  2. * plugin.c
  3. */
  4. #ifdef HAVE_CONFIG_H
  5. #include "config.h"
  6. #endif /* HAVE_CONFIG_H */
  7. #include "private.h"
  8. #include "lub/string.h"
  9. #include "lub/list.h"
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <stdio.h>
  13. #include <assert.h>
  14. #ifdef HAVE_DLFCN_H
  15. #include <dlfcn.h>
  16. #endif
  17. /**********************************************************
  18. * SYM functions *
  19. **********************************************************/
  20. /*--------------------------------------------------------- */
  21. int clish_sym_compare(const void *first, const void *second)
  22. {
  23. const clish_sym_t *f = (const clish_sym_t *)first;
  24. const clish_sym_t *s = (const clish_sym_t *)second;
  25. return strcmp(f->name, s->name);
  26. }
  27. /*--------------------------------------------------------- */
  28. clish_sym_t *clish_sym_new(const char *name, void *func, int type)
  29. {
  30. clish_sym_t *this;
  31. this = malloc(sizeof(*this));
  32. this->name = lub_string_dup(name);
  33. this->func = func;
  34. this->type = type;
  35. this->api = CLISH_SYM_API_SIMPLE;
  36. this->permanent = BOOL_FALSE;
  37. return this;
  38. }
  39. /*--------------------------------------------------------- */
  40. void clish_sym_free(clish_sym_t *this)
  41. {
  42. if (!this)
  43. return;
  44. lub_string_free(this->name);
  45. free(this);
  46. }
  47. /*--------------------------------------------------------- */
  48. void clish_sym__set_func(clish_sym_t *this, void *func)
  49. {
  50. this->func = func;
  51. }
  52. CLISH_GET(sym, const void *, func);
  53. /*--------------------------------------------------------- */
  54. void clish_sym__set_permanent(clish_sym_t *this, bool_t permanent)
  55. {
  56. this->permanent = permanent;
  57. }
  58. CLISH_GET(sym, bool_t, permanent);
  59. /*--------------------------------------------------------- */
  60. void clish_sym__set_name(clish_sym_t *this, const char *name)
  61. {
  62. lub_string_free(this->name);
  63. this->name = lub_string_dup(name);
  64. }
  65. /*--------------------------------------------------------- */
  66. char *clish_sym__get_name(clish_sym_t *this)
  67. {
  68. return this->name;
  69. }
  70. /*--------------------------------------------------------- */
  71. void clish_sym__set_plugin(clish_sym_t *this, clish_plugin_t *plugin)
  72. {
  73. this->plugin = plugin;
  74. }
  75. /*--------------------------------------------------------- */
  76. clish_plugin_t *clish_sym__get_plugin(clish_sym_t *this)
  77. {
  78. return this->plugin;
  79. }
  80. /*--------------------------------------------------------- */
  81. void clish_sym__set_type(clish_sym_t *this, int type)
  82. {
  83. this->type = type;
  84. }
  85. /*--------------------------------------------------------- */
  86. int clish_sym__get_type(const clish_sym_t *this)
  87. {
  88. return this->type;
  89. }
  90. /*--------------------------------------------------------- */
  91. void clish_sym__set_api(clish_sym_t *this, clish_sym_api_e api)
  92. {
  93. this->api = api;
  94. }
  95. /*--------------------------------------------------------- */
  96. clish_sym_api_e clish_sym__get_api(const clish_sym_t *this)
  97. {
  98. return this->api;
  99. }
  100. /*--------------------------------------------------------- */
  101. int clish_sym_clone(clish_sym_t *dst, clish_sym_t *src)
  102. {
  103. char *name;
  104. if (!dst || !src)
  105. return -1;
  106. name = dst->name;
  107. *dst = *src;
  108. dst->name = name;
  109. return 0;
  110. }
  111. /**********************************************************
  112. * PLUGIN functions *
  113. **********************************************************/
  114. /*--------------------------------------------------------- */
  115. clish_plugin_t *clish_plugin_new(const char *name)
  116. {
  117. clish_plugin_t *this;
  118. this = malloc(sizeof(*this));
  119. this->name = lub_string_dup(name);
  120. this->conf = NULL;
  121. this->alias = NULL;
  122. this->file = NULL;
  123. this->builtin_flag = BOOL_FALSE; /* The plugin is shared object by default */
  124. this->dlhan = NULL;
  125. /* Initialise the list of symbols */
  126. this->syms = lub_list_new(clish_sym_compare);
  127. /* Constructor and destructor */
  128. this->init = NULL;
  129. this->fini = NULL;
  130. /* Flags */
  131. this->rtld_global = BOOL_FALSE; /* The dlopen() use RTLD_LOCAL by default */
  132. return this;
  133. }
  134. /*--------------------------------------------------------- */
  135. void clish_plugin_free(clish_plugin_t *this, void *userdata)
  136. {
  137. lub_list_node_t *iter;
  138. if (!this)
  139. return;
  140. /* Execute destructor */
  141. if (this->fini)
  142. this->fini(userdata, this);
  143. lub_string_free(this->name);
  144. lub_string_free(this->alias);
  145. lub_string_free(this->file);
  146. lub_string_free(this->conf);
  147. /* Free symbol list */
  148. while ((iter = lub_list__get_head(this->syms))) {
  149. /* Remove the symbol from the list */
  150. lub_list_del(this->syms, iter);
  151. /* Free the instance */
  152. clish_sym_free((clish_sym_t *)lub_list_node__get_data(iter));
  153. lub_list_node_free(iter);
  154. }
  155. lub_list_free(this->syms);
  156. #ifdef HAVE_DLFCN_H
  157. if (this->dlhan)
  158. dlclose(this->dlhan);
  159. #endif
  160. free(this);
  161. }
  162. /*--------------------------------------------------------- */
  163. clish_sym_t *clish_plugin_add_generic(clish_plugin_t *this,
  164. void *func, const char *name, int type, bool_t permanent)
  165. {
  166. clish_sym_t *sym;
  167. if (!name || !func)
  168. return NULL;
  169. if (!(sym = clish_sym_new(name, func, type)))
  170. return NULL;
  171. clish_sym__set_plugin(sym, this);
  172. clish_sym__set_permanent(sym, permanent);
  173. lub_list_add(this->syms, sym);
  174. return sym;
  175. }
  176. /*--------------------------------------------------------- */
  177. clish_sym_t *clish_plugin_add_sym(clish_plugin_t *this,
  178. clish_hook_action_fn_t *func, const char *name)
  179. {
  180. return clish_plugin_add_generic(this, func,
  181. name, CLISH_SYM_TYPE_ACTION, BOOL_FALSE);
  182. }
  183. /*--------------------------------------------------------- */
  184. /* Add permanent symbol (can't be turned off by dry-run) */
  185. clish_sym_t *clish_plugin_add_psym(clish_plugin_t *this,
  186. clish_hook_action_fn_t *func, const char *name)
  187. {
  188. return clish_plugin_add_generic(this, func,
  189. name, CLISH_SYM_TYPE_ACTION, BOOL_TRUE);
  190. }
  191. /*--------------------------------------------------------- */
  192. clish_sym_t *clish_plugin_add_osym(clish_plugin_t *this,
  193. clish_hook_oaction_fn_t *func, const char *name)
  194. {
  195. clish_sym_t *s;
  196. if (!(s = clish_plugin_add_generic(this, func,
  197. name, CLISH_SYM_TYPE_ACTION, BOOL_FALSE)))
  198. return s;
  199. clish_sym__set_api(s, CLISH_SYM_API_STDOUT);
  200. return s;
  201. }
  202. /*--------------------------------------------------------- */
  203. /* Add permanent symbol (can't be turned off by dry-run) */
  204. clish_sym_t *clish_plugin_add_posym(clish_plugin_t *this,
  205. clish_hook_oaction_fn_t *func, const char *name)
  206. {
  207. clish_sym_t *s;
  208. if (!(s = clish_plugin_add_generic(this, func,
  209. name, CLISH_SYM_TYPE_ACTION, BOOL_TRUE)))
  210. return s;
  211. clish_sym__set_api(s, CLISH_SYM_API_STDOUT);
  212. return s;
  213. }
  214. /*--------------------------------------------------------- */
  215. clish_sym_t *clish_plugin_add_hook(clish_plugin_t *this,
  216. void *func, const char *name, int type)
  217. {
  218. return clish_plugin_add_generic(this, func,
  219. name, type, BOOL_FALSE);
  220. }
  221. /*--------------------------------------------------------- */
  222. clish_sym_t *clish_plugin_add_phook(clish_plugin_t *this,
  223. void *func, const char *name, int type)
  224. {
  225. return clish_plugin_add_generic(this, func,
  226. name, type, BOOL_TRUE);
  227. }
  228. /*--------------------------------------------------------- */
  229. void clish_plugin_add_fini(clish_plugin_t *this,
  230. clish_plugin_fini_t *fini)
  231. {
  232. this->fini = fini;
  233. }
  234. /*--------------------------------------------------------- */
  235. clish_plugin_fini_t * clish_plugin_get_fini(clish_plugin_t *this)
  236. {
  237. return this->fini;
  238. }
  239. /*--------------------------------------------------------- */
  240. void clish_plugin_add_init(clish_plugin_t *this,
  241. clish_plugin_init_t *init)
  242. {
  243. this->init = init;
  244. }
  245. /*--------------------------------------------------------- */
  246. clish_plugin_init_t * clish_plugin_get_init(clish_plugin_t *this)
  247. {
  248. return this->init;
  249. }
  250. /*--------------------------------------------------------- */
  251. clish_sym_t *clish_plugin_get_sym(clish_plugin_t *this, const char *name, int type)
  252. {
  253. lub_list_node_t *iter;
  254. clish_sym_t *sym;
  255. /* Iterate elements */
  256. for(iter = lub_list__get_head(this->syms);
  257. iter; iter = lub_list_node__get_next(iter)) {
  258. int res;
  259. sym = (clish_sym_t *)lub_list_node__get_data(iter);
  260. res = strcmp(clish_sym__get_name(sym), name);
  261. if (!res && ((CLISH_SYM_TYPE_NONE == type) || (clish_sym__get_type(sym) == type)))
  262. return sym;
  263. if (res > 0) /* No chances to find name */
  264. break;
  265. }
  266. return NULL;
  267. }
  268. /*--------------------------------------------------------- */
  269. static int clish_plugin_load_shared(clish_plugin_t *this)
  270. {
  271. #ifdef HAVE_DLFCN_H
  272. char *file = NULL; /* Plugin so file name */
  273. char *init_name = NULL; /* Init function name */
  274. int flag = RTLD_NOW;
  275. if (this->file) {
  276. file = lub_string_dup(this->file);
  277. } else {
  278. lub_string_cat(&file, "clish_plugin_");
  279. lub_string_cat(&file, this->name);
  280. lub_string_cat(&file, ".so");
  281. }
  282. /* Open dynamic library */
  283. if (clish_plugin__get_rtld_global(this))
  284. flag |= RTLD_GLOBAL;
  285. else
  286. flag |= RTLD_LOCAL;
  287. this->dlhan = dlopen(file, flag);
  288. lub_string_free(file);
  289. if (!this->dlhan) {
  290. fprintf(stderr, "Error: Can't open plugin \"%s\": %s\n",
  291. this->name, dlerror());
  292. return -1;
  293. }
  294. /* Get plugin init function */
  295. lub_string_cat(&init_name, CLISH_PLUGIN_INIT_NAME_PREFIX);
  296. lub_string_cat(&init_name, this->name);
  297. lub_string_cat(&init_name, CLISH_PLUGIN_INIT_NAME_SUFFIX);
  298. this->init = (clish_plugin_init_t *)dlsym(this->dlhan, init_name);
  299. lub_string_free(init_name);
  300. if (!this->init) {
  301. fprintf(stderr, "Error: Can't get plugin \"%s\" init function: %s\n",
  302. this->name, dlerror());
  303. return -1;
  304. }
  305. return 0;
  306. #else /* HAVE_DLFCN_H */
  307. /* We have no any dl functions. */
  308. fprintf(stderr, "Error: Can't get plugin \"%s\" init function.\n",
  309. this->name);
  310. return -1;
  311. #endif /* HAVE_DLFCN_H */
  312. }
  313. /*--------------------------------------------------------- */
  314. int clish_plugin_load(clish_plugin_t *this, void *userdata)
  315. {
  316. int res;
  317. if (!this)
  318. return -1;
  319. assert(this->name);
  320. /* Builtin plugins already have init function. */
  321. if (!this->builtin_flag) {
  322. if (clish_plugin_load_shared(this) < 0)
  323. return -1;
  324. }
  325. if (!this->init) {
  326. fprintf(stderr, "Error: PLUGIN %s has no init function\n",
  327. this->name);
  328. return -1;
  329. }
  330. /* Execute init function */
  331. if ((res = this->init(userdata, this)))
  332. fprintf(stderr, "Error: Plugin %s init retcode: %d\n",
  333. this->name, res);
  334. return res;
  335. }
  336. /*--------------------------------------------------------- */
  337. char *clish_plugin__get_name(const clish_plugin_t *this)
  338. {
  339. return this->name;
  340. }
  341. /*--------------------------------------------------------- */
  342. void clish_plugin__set_alias(clish_plugin_t *this, const char *alias)
  343. {
  344. lub_string_free(this->alias);
  345. this->alias = lub_string_dup(alias);
  346. }
  347. /*--------------------------------------------------------- */
  348. char *clish_plugin__get_alias(const clish_plugin_t *this)
  349. {
  350. return this->alias;
  351. }
  352. /*--------------------------------------------------------- */
  353. char *clish_plugin__get_pubname(const clish_plugin_t *this)
  354. {
  355. return (this->alias ? this->alias : this->name);
  356. }
  357. /*--------------------------------------------------------- */
  358. void clish_plugin__set_file(clish_plugin_t *this, const char *file)
  359. {
  360. lub_string_free(this->file);
  361. this->file = lub_string_dup(file);
  362. }
  363. /*--------------------------------------------------------- */
  364. char *clish_plugin__get_file(const clish_plugin_t *this)
  365. {
  366. return this->file;
  367. }
  368. /*--------------------------------------------------------- */
  369. void clish_plugin__set_builtin_flag(clish_plugin_t *this, bool_t builtin_flag)
  370. {
  371. this->builtin_flag = builtin_flag;
  372. }
  373. /*--------------------------------------------------------- */
  374. bool_t clish_plugin__get_builtin_flag(const clish_plugin_t *this)
  375. {
  376. return this->builtin_flag;
  377. }
  378. /*--------------------------------------------------------- */
  379. void clish_plugin__set_conf(clish_plugin_t *this, const char *conf)
  380. {
  381. lub_string_free(this->conf);
  382. this->conf = lub_string_dup(conf);
  383. }
  384. /*--------------------------------------------------------- */
  385. char *clish_plugin__get_conf(const clish_plugin_t *this)
  386. {
  387. return this->conf;
  388. }
  389. /*--------------------------------------------------------- */
  390. void clish_plugin__set_rtld_global(clish_plugin_t *this, bool_t rtld_global)
  391. {
  392. this->rtld_global = rtld_global;
  393. }
  394. /*--------------------------------------------------------- */
  395. bool_t clish_plugin__get_rtld_global(const clish_plugin_t *this)
  396. {
  397. return this->rtld_global;
  398. }
  399. /*--------------------------------------------------------- */