1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include <stdio.h>
22#include <string.h>
23#include <dlfcn.h>
24#include <stdlib.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <unistd.h>
28#include <dirent.h>
29#include "event-parse.h"
30#include "event-utils.h"
31
32#define LOCAL_PLUGIN_DIR ".traceevent/plugins"
33
34static struct registered_plugin_options {
35 struct registered_plugin_options *next;
36 struct pevent_plugin_option *options;
37} *registered_options;
38
39static struct trace_plugin_options {
40 struct trace_plugin_options *next;
41 char *plugin;
42 char *option;
43 char *value;
44} *trace_plugin_options;
45
46struct plugin_list {
47 struct plugin_list *next;
48 char *name;
49 void *handle;
50};
51
52
53
54
55
56
57
58
59
60
61
62
63
64char **traceevent_plugin_list_options(void)
65{
66 struct registered_plugin_options *reg;
67 struct pevent_plugin_option *op;
68 char **list = NULL;
69 char *name;
70 int count = 0;
71
72 for (reg = registered_options; reg; reg = reg->next) {
73 for (op = reg->options; op->name; op++) {
74 char *alias = op->plugin_alias ? op->plugin_alias : op->file;
75 char **temp = list;
76
77 name = malloc(strlen(op->name) + strlen(alias) + 2);
78 if (!name)
79 goto err;
80
81 sprintf(name, "%s:%s", alias, op->name);
82 list = realloc(list, count + 2);
83 if (!list) {
84 list = temp;
85 free(name);
86 goto err;
87 }
88 list[count++] = name;
89 list[count] = NULL;
90 }
91 }
92 return list;
93
94 err:
95 while (--count >= 0)
96 free(list[count]);
97 free(list);
98
99 return INVALID_PLUGIN_LIST_OPTION;
100}
101
102void traceevent_plugin_free_options_list(char **list)
103{
104 int i;
105
106 if (!list)
107 return;
108
109 if (list == INVALID_PLUGIN_LIST_OPTION)
110 return;
111
112 for (i = 0; list[i]; i++)
113 free(list[i]);
114
115 free(list);
116}
117
118static int
119update_option(const char *file, struct pevent_plugin_option *option)
120{
121 struct trace_plugin_options *op;
122 char *plugin;
123
124 if (option->plugin_alias) {
125 plugin = strdup(option->plugin_alias);
126 if (!plugin)
127 return -1;
128 } else {
129 char *p;
130 plugin = strdup(file);
131 if (!plugin)
132 return -1;
133 p = strstr(plugin, ".");
134 if (p)
135 *p = '\0';
136 }
137
138
139 for (op = trace_plugin_options; op; op = op->next) {
140 if (!op->plugin)
141 continue;
142 if (strcmp(op->plugin, plugin) != 0)
143 continue;
144 if (strcmp(op->option, option->name) != 0)
145 continue;
146
147 option->value = op->value;
148 option->set ^= 1;
149 goto out;
150 }
151
152
153 for (op = trace_plugin_options; op; op = op->next) {
154 if (op->plugin)
155 continue;
156 if (strcmp(op->option, option->name) != 0)
157 continue;
158
159 option->value = op->value;
160 option->set ^= 1;
161 break;
162 }
163
164 out:
165 free(plugin);
166 return 0;
167}
168
169
170
171
172
173
174
175
176int traceevent_plugin_add_options(const char *name,
177 struct pevent_plugin_option *options)
178{
179 struct registered_plugin_options *reg;
180
181 reg = malloc(sizeof(*reg));
182 if (!reg)
183 return -1;
184 reg->next = registered_options;
185 reg->options = options;
186 registered_options = reg;
187
188 while (options->name) {
189 update_option(name, options);
190 options++;
191 }
192 return 0;
193}
194
195
196
197
198
199void traceevent_plugin_remove_options(struct pevent_plugin_option *options)
200{
201 struct registered_plugin_options **last;
202 struct registered_plugin_options *reg;
203
204 for (last = ®istered_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
215
216
217
218
219
220
221
222
223
224
225void traceevent_print_plugins(struct trace_seq *s,
226 const char *prefix, const char *suffix,
227 const struct plugin_list *list)
228{
229 while (list) {
230 trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix);
231 list = list->next;
232 }
233}
234
235static void
236load_plugin(struct pevent *pevent, const char *path,
237 const char *file, void *data)
238{
239 struct plugin_list **plugin_list = data;
240 pevent_plugin_load_func func;
241 struct plugin_list *list;
242 const char *alias;
243 char *plugin;
244 void *handle;
245
246 plugin = malloc(strlen(path) + strlen(file) + 2);
247 if (!plugin) {
248 warning("could not allocate plugin memory\n");
249 return;
250 }
251
252 strcpy(plugin, path);
253 strcat(plugin, "/");
254 strcat(plugin, file);
255
256 handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL);
257 if (!handle) {
258 warning("could not load plugin '%s'\n%s\n",
259 plugin, dlerror());
260 goto out_free;
261 }
262
263 alias = dlsym(handle, PEVENT_PLUGIN_ALIAS_NAME);
264 if (!alias)
265 alias = file;
266
267 func = dlsym(handle, PEVENT_PLUGIN_LOADER_NAME);
268 if (!func) {
269 warning("could not find func '%s' in plugin '%s'\n%s\n",
270 PEVENT_PLUGIN_LOADER_NAME, plugin, dlerror());
271 goto out_free;
272 }
273
274 list = malloc(sizeof(*list));
275 if (!list) {
276 warning("could not allocate plugin memory\n");
277 goto out_free;
278 }
279
280 list->next = *plugin_list;
281 list->handle = handle;
282 list->name = plugin;
283 *plugin_list = list;
284
285 pr_stat("registering plugin: %s", plugin);
286 func(pevent);
287 return;
288
289 out_free:
290 free(plugin);
291}
292
293static void
294load_plugins_dir(struct pevent *pevent, const char *suffix,
295 const char *path,
296 void (*load_plugin)(struct pevent *pevent,
297 const char *path,
298 const char *name,
299 void *data),
300 void *data)
301{
302 struct dirent *dent;
303 struct stat st;
304 DIR *dir;
305 int ret;
306
307 ret = stat(path, &st);
308 if (ret < 0)
309 return;
310
311 if (!S_ISDIR(st.st_mode))
312 return;
313
314 dir = opendir(path);
315 if (!dir)
316 return;
317
318 while ((dent = readdir(dir))) {
319 const char *name = dent->d_name;
320
321 if (strcmp(name, ".") == 0 ||
322 strcmp(name, "..") == 0)
323 continue;
324
325
326 if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0)
327 continue;
328
329 load_plugin(pevent, path, name, data);
330 }
331
332 closedir(dir);
333}
334
335static void
336load_plugins(struct pevent *pevent, const char *suffix,
337 void (*load_plugin)(struct pevent *pevent,
338 const char *path,
339 const char *name,
340 void *data),
341 void *data)
342{
343 char *home;
344 char *path;
345 char *envdir;
346
347 if (pevent->flags & PEVENT_DISABLE_PLUGINS)
348 return;
349
350
351
352
353
354#ifdef PLUGIN_DIR
355 if (!(pevent->flags & PEVENT_DISABLE_SYS_PLUGINS))
356 load_plugins_dir(pevent, suffix, PLUGIN_DIR,
357 load_plugin, data);
358#endif
359
360
361
362
363
364 envdir = getenv("TRACEEVENT_PLUGIN_DIR");
365 if (envdir)
366 load_plugins_dir(pevent, suffix, envdir, load_plugin, data);
367
368
369
370
371
372 home = getenv("HOME");
373 if (!home)
374 return;
375
376 path = malloc(strlen(home) + strlen(LOCAL_PLUGIN_DIR) + 2);
377 if (!path) {
378 warning("could not allocate plugin memory\n");
379 return;
380 }
381
382 strcpy(path, home);
383 strcat(path, "/");
384 strcat(path, LOCAL_PLUGIN_DIR);
385
386 load_plugins_dir(pevent, suffix, path, load_plugin, data);
387
388 free(path);
389}
390
391struct plugin_list*
392traceevent_load_plugins(struct pevent *pevent)
393{
394 struct plugin_list *list = NULL;
395
396 load_plugins(pevent, ".so", load_plugin, &list);
397 return list;
398}
399
400void
401traceevent_unload_plugins(struct plugin_list *plugin_list, struct pevent *pevent)
402{
403 pevent_plugin_unload_func func;
404 struct plugin_list *list;
405
406 while (plugin_list) {
407 list = plugin_list;
408 plugin_list = list->next;
409 func = dlsym(list->handle, PEVENT_PLUGIN_UNLOADER_NAME);
410 if (func)
411 func(pevent);
412 dlclose(list->handle);
413 free(list->name);
414 free(list);
415 }
416}
417