event-plugin.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. // SPDX-License-Identifier: LGPL-2.1
  2. /*
  3. * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
  4. *
  5. */
  6. #include <ctype.h>
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <dlfcn.h>
  10. #include <stdlib.h>
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #include <unistd.h>
  14. #include <dirent.h>
  15. #include "event-parse.h"
  16. #include "event-parse-local.h"
  17. #include "event-utils.h"
  18. #include "trace-seq.h"
  19. #define LOCAL_PLUGIN_DIR ".traceevent/plugins"
  20. static struct registered_plugin_options {
  21. struct registered_plugin_options *next;
  22. struct tep_plugin_option *options;
  23. } *registered_options;
  24. static struct trace_plugin_options {
  25. struct trace_plugin_options *next;
  26. char *plugin;
  27. char *option;
  28. char *value;
  29. } *trace_plugin_options;
  30. struct tep_plugin_list {
  31. struct tep_plugin_list *next;
  32. char *name;
  33. void *handle;
  34. };
  35. static void lower_case(char *str)
  36. {
  37. if (!str)
  38. return;
  39. for (; *str; str++)
  40. *str = tolower(*str);
  41. }
  42. static int update_option_value(struct tep_plugin_option *op, const char *val)
  43. {
  44. char *op_val;
  45. if (!val) {
  46. /* toggle, only if option is boolean */
  47. if (op->value)
  48. /* Warn? */
  49. return 0;
  50. op->set ^= 1;
  51. return 0;
  52. }
  53. /*
  54. * If the option has a value then it takes a string
  55. * otherwise the option is a boolean.
  56. */
  57. if (op->value) {
  58. op->value = val;
  59. return 0;
  60. }
  61. /* Option is boolean, must be either "1", "0", "true" or "false" */
  62. op_val = strdup(val);
  63. if (!op_val)
  64. return -1;
  65. lower_case(op_val);
  66. if (strcmp(val, "1") == 0 || strcmp(val, "true") == 0)
  67. op->set = 1;
  68. else if (strcmp(val, "0") == 0 || strcmp(val, "false") == 0)
  69. op->set = 0;
  70. free(op_val);
  71. return 0;
  72. }
  73. /**
  74. * tep_plugin_list_options - get list of plugin options
  75. *
  76. * Returns an array of char strings that list the currently registered
  77. * plugin options in the format of <plugin>:<option>. This list can be
  78. * used by toggling the option.
  79. *
  80. * Returns NULL if there's no options registered. On error it returns
  81. * INVALID_PLUGIN_LIST_OPTION
  82. *
  83. * Must be freed with tep_plugin_free_options_list().
  84. */
  85. char **tep_plugin_list_options(void)
  86. {
  87. struct registered_plugin_options *reg;
  88. struct tep_plugin_option *op;
  89. char **list = NULL;
  90. char *name;
  91. int count = 0;
  92. for (reg = registered_options; reg; reg = reg->next) {
  93. for (op = reg->options; op->name; op++) {
  94. char *alias = op->plugin_alias ? op->plugin_alias : op->file;
  95. char **temp = list;
  96. int ret;
  97. ret = asprintf(&name, "%s:%s", alias, op->name);
  98. if (ret < 0)
  99. goto err;
  100. list = realloc(list, count + 2);
  101. if (!list) {
  102. list = temp;
  103. free(name);
  104. goto err;
  105. }
  106. list[count++] = name;
  107. list[count] = NULL;
  108. }
  109. }
  110. return list;
  111. err:
  112. while (--count >= 0)
  113. free(list[count]);
  114. free(list);
  115. return INVALID_PLUGIN_LIST_OPTION;
  116. }
  117. void tep_plugin_free_options_list(char **list)
  118. {
  119. int i;
  120. if (!list)
  121. return;
  122. if (list == INVALID_PLUGIN_LIST_OPTION)
  123. return;
  124. for (i = 0; list[i]; i++)
  125. free(list[i]);
  126. free(list);
  127. }
  128. static int
  129. update_option(const char *file, struct tep_plugin_option *option)
  130. {
  131. struct trace_plugin_options *op;
  132. char *plugin;
  133. int ret = 0;
  134. if (option->plugin_alias) {
  135. plugin = strdup(option->plugin_alias);
  136. if (!plugin)
  137. return -1;
  138. } else {
  139. char *p;
  140. plugin = strdup(file);
  141. if (!plugin)
  142. return -1;
  143. p = strstr(plugin, ".");
  144. if (p)
  145. *p = '\0';
  146. }
  147. /* first look for named options */
  148. for (op = trace_plugin_options; op; op = op->next) {
  149. if (!op->plugin)
  150. continue;
  151. if (strcmp(op->plugin, plugin) != 0)
  152. continue;
  153. if (strcmp(op->option, option->name) != 0)
  154. continue;
  155. ret = update_option_value(option, op->value);
  156. if (ret)
  157. goto out;
  158. break;
  159. }
  160. /* first look for unnamed options */
  161. for (op = trace_plugin_options; op; op = op->next) {
  162. if (op->plugin)
  163. continue;
  164. if (strcmp(op->option, option->name) != 0)
  165. continue;
  166. ret = update_option_value(option, op->value);
  167. break;
  168. }
  169. out:
  170. free(plugin);
  171. return ret;
  172. }
  173. /**
  174. * tep_plugin_add_options - Add a set of options by a plugin
  175. * @name: The name of the plugin adding the options
  176. * @options: The set of options being loaded
  177. *
  178. * Sets the options with the values that have been added by user.
  179. */
  180. int tep_plugin_add_options(const char *name,
  181. struct tep_plugin_option *options)
  182. {
  183. struct registered_plugin_options *reg;
  184. reg = malloc(sizeof(*reg));
  185. if (!reg)
  186. return -1;
  187. reg->next = registered_options;
  188. reg->options = options;
  189. registered_options = reg;
  190. while (options->name) {
  191. update_option(name, options);
  192. options++;
  193. }
  194. return 0;
  195. }
  196. /**
  197. * tep_plugin_remove_options - remove plugin options that were registered
  198. * @options: Options to removed that were registered with tep_plugin_add_options
  199. */
  200. void tep_plugin_remove_options(struct tep_plugin_option *options)
  201. {
  202. struct registered_plugin_options **last;
  203. struct registered_plugin_options *reg;
  204. for (last = &registered_options; *last; last = &(*last)->next) {
  205. if ((*last)->options == options) {
  206. reg = *last;
  207. *last = reg->next;
  208. free(reg);
  209. return;
  210. }
  211. }
  212. }
  213. /**
  214. * tep_print_plugins - print out the list of plugins loaded
  215. * @s: the trace_seq descripter to write to
  216. * @prefix: The prefix string to add before listing the option name
  217. * @suffix: The suffix string ot append after the option name
  218. * @list: The list of plugins (usually returned by tep_load_plugins()
  219. *
  220. * Writes to the trace_seq @s the list of plugins (files) that is
  221. * returned by tep_load_plugins(). Use @prefix and @suffix for formating:
  222. * @prefix = " ", @suffix = "\n".
  223. */
  224. void tep_print_plugins(struct trace_seq *s,
  225. const char *prefix, const char *suffix,
  226. const struct tep_plugin_list *list)
  227. {
  228. while (list) {
  229. trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix);
  230. list = list->next;
  231. }
  232. }
  233. static void
  234. load_plugin(struct tep_handle *pevent, const char *path,
  235. const char *file, void *data)
  236. {
  237. struct tep_plugin_list **plugin_list = data;
  238. tep_plugin_load_func func;
  239. struct tep_plugin_list *list;
  240. const char *alias;
  241. char *plugin;
  242. void *handle;
  243. int ret;
  244. ret = asprintf(&plugin, "%s/%s", path, file);
  245. if (ret < 0) {
  246. warning("could not allocate plugin memory\n");
  247. return;
  248. }
  249. handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL);
  250. if (!handle) {
  251. warning("could not load plugin '%s'\n%s\n",
  252. plugin, dlerror());
  253. goto out_free;
  254. }
  255. alias = dlsym(handle, TEP_PLUGIN_ALIAS_NAME);
  256. if (!alias)
  257. alias = file;
  258. func = dlsym(handle, TEP_PLUGIN_LOADER_NAME);
  259. if (!func) {
  260. warning("could not find func '%s' in plugin '%s'\n%s\n",
  261. TEP_PLUGIN_LOADER_NAME, plugin, dlerror());
  262. goto out_free;
  263. }
  264. list = malloc(sizeof(*list));
  265. if (!list) {
  266. warning("could not allocate plugin memory\n");
  267. goto out_free;
  268. }
  269. list->next = *plugin_list;
  270. list->handle = handle;
  271. list->name = plugin;
  272. *plugin_list = list;
  273. pr_stat("registering plugin: %s", plugin);
  274. func(pevent);
  275. return;
  276. out_free:
  277. free(plugin);
  278. }
  279. static void
  280. load_plugins_dir(struct tep_handle *pevent, const char *suffix,
  281. const char *path,
  282. void (*load_plugin)(struct tep_handle *pevent,
  283. const char *path,
  284. const char *name,
  285. void *data),
  286. void *data)
  287. {
  288. struct dirent *dent;
  289. struct stat st;
  290. DIR *dir;
  291. int ret;
  292. ret = stat(path, &st);
  293. if (ret < 0)
  294. return;
  295. if (!S_ISDIR(st.st_mode))
  296. return;
  297. dir = opendir(path);
  298. if (!dir)
  299. return;
  300. while ((dent = readdir(dir))) {
  301. const char *name = dent->d_name;
  302. if (strcmp(name, ".") == 0 ||
  303. strcmp(name, "..") == 0)
  304. continue;
  305. /* Only load plugins that end in suffix */
  306. if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0)
  307. continue;
  308. load_plugin(pevent, path, name, data);
  309. }
  310. closedir(dir);
  311. }
  312. static void
  313. load_plugins(struct tep_handle *pevent, const char *suffix,
  314. void (*load_plugin)(struct tep_handle *pevent,
  315. const char *path,
  316. const char *name,
  317. void *data),
  318. void *data)
  319. {
  320. char *home;
  321. char *path;
  322. char *envdir;
  323. int ret;
  324. if (pevent->flags & TEP_DISABLE_PLUGINS)
  325. return;
  326. /*
  327. * If a system plugin directory was defined,
  328. * check that first.
  329. */
  330. #ifdef PLUGIN_DIR
  331. if (!(pevent->flags & TEP_DISABLE_SYS_PLUGINS))
  332. load_plugins_dir(pevent, suffix, PLUGIN_DIR,
  333. load_plugin, data);
  334. #endif
  335. /*
  336. * Next let the environment-set plugin directory
  337. * override the system defaults.
  338. */
  339. envdir = getenv("TRACEEVENT_PLUGIN_DIR");
  340. if (envdir)
  341. load_plugins_dir(pevent, suffix, envdir, load_plugin, data);
  342. /*
  343. * Now let the home directory override the environment
  344. * or system defaults.
  345. */
  346. home = getenv("HOME");
  347. if (!home)
  348. return;
  349. ret = asprintf(&path, "%s/%s", home, LOCAL_PLUGIN_DIR);
  350. if (ret < 0) {
  351. warning("could not allocate plugin memory\n");
  352. return;
  353. }
  354. load_plugins_dir(pevent, suffix, path, load_plugin, data);
  355. free(path);
  356. }
  357. struct tep_plugin_list*
  358. tep_load_plugins(struct tep_handle *pevent)
  359. {
  360. struct tep_plugin_list *list = NULL;
  361. load_plugins(pevent, ".so", load_plugin, &list);
  362. return list;
  363. }
  364. void
  365. tep_unload_plugins(struct tep_plugin_list *plugin_list, struct tep_handle *pevent)
  366. {
  367. tep_plugin_unload_func func;
  368. struct tep_plugin_list *list;
  369. while (plugin_list) {
  370. list = plugin_list;
  371. plugin_list = list->next;
  372. func = dlsym(list->handle, TEP_PLUGIN_UNLOADER_NAME);
  373. if (func)
  374. func(pevent);
  375. dlclose(list->handle);
  376. free(list->name);
  377. free(list);
  378. }
  379. }