event-plugin.c 9.2 KB

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