f8d253a619706fb3feed67afc97bfa18c34c3410
[linux-2.6-microblaze.git] / tools / lib / traceevent / event-plugin.c
1 // SPDX-License-Identifier: LGPL-2.1
2 /*
3  * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
4  *
5  */
6
7 #include <ctype.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <dlfcn.h>
11 #include <stdlib.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <unistd.h>
15 #include <dirent.h>
16 #include <errno.h>
17 #include "event-parse.h"
18 #include "event-parse-local.h"
19 #include "event-utils.h"
20 #include "trace-seq.h"
21
22 #define LOCAL_PLUGIN_DIR ".local/lib/traceevent/plugins/"
23
24 static struct registered_plugin_options {
25         struct registered_plugin_options        *next;
26         struct tep_plugin_option                *options;
27 } *registered_options;
28
29 static struct trace_plugin_options {
30         struct trace_plugin_options     *next;
31         char                            *plugin;
32         char                            *option;
33         char                            *value;
34 } *trace_plugin_options;
35
36 struct tep_plugin_list {
37         struct tep_plugin_list  *next;
38         char                    *name;
39         void                    *handle;
40 };
41
42 struct tep_plugins_dir {
43         struct tep_plugins_dir          *next;
44         char                            *path;
45         enum tep_plugin_load_priority   prio;
46 };
47
48 static void lower_case(char *str)
49 {
50         if (!str)
51                 return;
52         for (; *str; str++)
53                 *str = tolower(*str);
54 }
55
56 static int update_option_value(struct tep_plugin_option *op, const char *val)
57 {
58         char *op_val;
59
60         if (!val) {
61                 /* toggle, only if option is boolean */
62                 if (op->value)
63                         /* Warn? */
64                         return 0;
65                 op->set ^= 1;
66                 return 0;
67         }
68
69         /*
70          * If the option has a value then it takes a string
71          * otherwise the option is a boolean.
72          */
73         if (op->value) {
74                 op->value = val;
75                 return 0;
76         }
77
78         /* Option is boolean, must be either "1", "0", "true" or "false" */
79
80         op_val = strdup(val);
81         if (!op_val)
82                 return -1;
83         lower_case(op_val);
84
85         if (strcmp(val, "1") == 0 || strcmp(val, "true") == 0)
86                 op->set = 1;
87         else if (strcmp(val, "0") == 0 || strcmp(val, "false") == 0)
88                 op->set = 0;
89         free(op_val);
90
91         return 0;
92 }
93
94 /**
95  * tep_plugin_list_options - get list of plugin options
96  *
97  * Returns an array of char strings that list the currently registered
98  * plugin options in the format of <plugin>:<option>. This list can be
99  * used by toggling the option.
100  *
101  * Returns NULL if there's no options registered. On error it returns
102  * INVALID_PLUGIN_LIST_OPTION
103  *
104  * Must be freed with tep_plugin_free_options_list().
105  */
106 char **tep_plugin_list_options(void)
107 {
108         struct registered_plugin_options *reg;
109         struct tep_plugin_option *op;
110         char **list = NULL;
111         char *name;
112         int count = 0;
113
114         for (reg = registered_options; reg; reg = reg->next) {
115                 for (op = reg->options; op->name; op++) {
116                         char *alias = op->plugin_alias ? op->plugin_alias : op->file;
117                         char **temp = list;
118                         int ret;
119
120                         ret = asprintf(&name, "%s:%s", alias, op->name);
121                         if (ret < 0)
122                                 goto err;
123
124                         list = realloc(list, count + 2);
125                         if (!list) {
126                                 list = temp;
127                                 free(name);
128                                 goto err;
129                         }
130                         list[count++] = name;
131                         list[count] = NULL;
132                 }
133         }
134         return list;
135
136  err:
137         while (--count >= 0)
138                 free(list[count]);
139         free(list);
140
141         return INVALID_PLUGIN_LIST_OPTION;
142 }
143
144 void tep_plugin_free_options_list(char **list)
145 {
146         int i;
147
148         if (!list)
149                 return;
150
151         if (list == INVALID_PLUGIN_LIST_OPTION)
152                 return;
153
154         for (i = 0; list[i]; i++)
155                 free(list[i]);
156
157         free(list);
158 }
159
160 static int
161 update_option(const char *file, struct tep_plugin_option *option)
162 {
163         struct trace_plugin_options *op;
164         char *plugin;
165         int ret = 0;
166
167         if (option->plugin_alias) {
168                 plugin = strdup(option->plugin_alias);
169                 if (!plugin)
170                         return -1;
171         } else {
172                 char *p;
173                 plugin = strdup(file);
174                 if (!plugin)
175                         return -1;
176                 p = strstr(plugin, ".");
177                 if (p)
178                         *p = '\0';
179         }
180
181         /* first look for named options */
182         for (op = trace_plugin_options; op; op = op->next) {
183                 if (!op->plugin)
184                         continue;
185                 if (strcmp(op->plugin, plugin) != 0)
186                         continue;
187                 if (strcmp(op->option, option->name) != 0)
188                         continue;
189
190                 ret = update_option_value(option, op->value);
191                 if (ret)
192                         goto out;
193                 break;
194         }
195
196         /* first look for unnamed options */
197         for (op = trace_plugin_options; op; op = op->next) {
198                 if (op->plugin)
199                         continue;
200                 if (strcmp(op->option, option->name) != 0)
201                         continue;
202
203                 ret = update_option_value(option, op->value);
204                 break;
205         }
206
207  out:
208         free(plugin);
209         return ret;
210 }
211
212 /**
213  * tep_plugin_add_options - Add a set of options by a plugin
214  * @name: The name of the plugin adding the options
215  * @options: The set of options being loaded
216  *
217  * Sets the options with the values that have been added by user.
218  */
219 int tep_plugin_add_options(const char *name,
220                            struct tep_plugin_option *options)
221 {
222         struct registered_plugin_options *reg;
223
224         reg = malloc(sizeof(*reg));
225         if (!reg)
226                 return -1;
227         reg->next = registered_options;
228         reg->options = options;
229         registered_options = reg;
230
231         while (options->name) {
232                 update_option(name, options);
233                 options++;
234         }
235         return 0;
236 }
237
238 /**
239  * tep_plugin_remove_options - remove plugin options that were registered
240  * @options: Options to removed that were registered with tep_plugin_add_options
241  */
242 void tep_plugin_remove_options(struct tep_plugin_option *options)
243 {
244         struct registered_plugin_options **last;
245         struct registered_plugin_options *reg;
246
247         for (last = &registered_options; *last; last = &(*last)->next) {
248                 if ((*last)->options == options) {
249                         reg = *last;
250                         *last = reg->next;
251                         free(reg);
252                         return;
253                 }
254         }
255 }
256
257 static int parse_option_name(char **option, char **plugin)
258 {
259         char *p;
260
261         *plugin = NULL;
262
263         if ((p = strstr(*option, ":"))) {
264                 *plugin = *option;
265                 *p = '\0';
266                 *option = strdup(p + 1);
267                 if (!*option)
268                         return -1;
269         }
270         return 0;
271 }
272
273 static struct tep_plugin_option *
274 find_registered_option(const char *plugin, const char *option)
275 {
276         struct registered_plugin_options *reg;
277         struct tep_plugin_option *op;
278         const char *op_plugin;
279
280         for (reg = registered_options; reg; reg = reg->next) {
281                 for (op = reg->options; op->name; op++) {
282                         if (op->plugin_alias)
283                                 op_plugin = op->plugin_alias;
284                         else
285                                 op_plugin = op->file;
286
287                         if (plugin && strcmp(plugin, op_plugin) != 0)
288                                 continue;
289                         if (strcmp(option, op->name) != 0)
290                                 continue;
291
292                         return op;
293                 }
294         }
295
296         return NULL;
297 }
298
299 static int process_option(const char *plugin, const char *option, const char *val)
300 {
301         struct tep_plugin_option *op;
302
303         op = find_registered_option(plugin, option);
304         if (!op)
305                 return 0;
306
307         return update_option_value(op, val);
308 }
309
310 /**
311  * tep_plugin_add_option - add an option/val pair to set plugin options
312  * @name: The name of the option (format: <plugin>:<option> or just <option>)
313  * @val: (optional) the value for the option
314  *
315  * Modify a plugin option. If @val is given than the value of the option
316  * is set (note, some options just take a boolean, so @val must be either
317  * "1" or "0" or "true" or "false").
318  */
319 int tep_plugin_add_option(const char *name, const char *val)
320 {
321         struct trace_plugin_options *op;
322         char *option_str;
323         char *plugin;
324
325         option_str = strdup(name);
326         if (!option_str)
327                 return -ENOMEM;
328
329         if (parse_option_name(&option_str, &plugin) < 0)
330                 return -ENOMEM;
331
332         /* If the option exists, update the val */
333         for (op = trace_plugin_options; op; op = op->next) {
334                 /* Both must be NULL or not NULL */
335                 if ((!plugin || !op->plugin) && plugin != op->plugin)
336                         continue;
337                 if (plugin && strcmp(plugin, op->plugin) != 0)
338                         continue;
339                 if (strcmp(op->option, option_str) != 0)
340                         continue;
341
342                 /* update option */
343                 free(op->value);
344                 if (val) {
345                         op->value = strdup(val);
346                         if (!op->value)
347                                 goto out_free;
348                 } else
349                         op->value = NULL;
350
351                 /* plugin and option_str don't get freed at the end */
352                 free(plugin);
353                 free(option_str);
354
355                 plugin = op->plugin;
356                 option_str = op->option;
357                 break;
358         }
359
360         /* If not found, create */
361         if (!op) {
362                 op = malloc(sizeof(*op));
363                 if (!op)
364                         return -ENOMEM;
365                 memset(op, 0, sizeof(*op));
366                 op->next = trace_plugin_options;
367                 trace_plugin_options = op;
368
369                 op->plugin = plugin;
370                 op->option = option_str;
371
372                 if (val) {
373                         op->value = strdup(val);
374                         if (!op->value)
375                                 goto out_free;
376                 }
377         }
378
379         return process_option(plugin, option_str, val);
380  out_free:
381         free(option_str);
382         return -ENOMEM;
383 }
384
385 static void print_op_data(struct trace_seq *s, const char *name,
386                           const char *op)
387 {
388         if (op)
389                 trace_seq_printf(s, "%8s:\t%s\n", name, op);
390 }
391
392 /**
393  * tep_plugin_print_options - print out the registered plugin options
394  * @s: The trace_seq descriptor to write the plugin options into
395  *
396  * Writes a list of options into trace_seq @s.
397  */
398 void tep_plugin_print_options(struct trace_seq *s)
399 {
400         struct registered_plugin_options *reg;
401         struct tep_plugin_option *op;
402
403         for (reg = registered_options; reg; reg = reg->next) {
404                 if (reg != registered_options)
405                         trace_seq_printf(s, "============\n");
406                 for (op = reg->options; op->name; op++) {
407                         if (op != reg->options)
408                                 trace_seq_printf(s, "------------\n");
409                         print_op_data(s, "file", op->file);
410                         print_op_data(s, "plugin", op->plugin_alias);
411                         print_op_data(s, "option", op->name);
412                         print_op_data(s, "desc", op->description);
413                         print_op_data(s, "value", op->value);
414                         trace_seq_printf(s, "%8s:\t%d\n", "set", op->set);
415                 }
416         }
417 }
418
419 /**
420  * tep_print_plugins - print out the list of plugins loaded
421  * @s: the trace_seq descripter to write to
422  * @prefix: The prefix string to add before listing the option name
423  * @suffix: The suffix string ot append after the option name
424  * @list: The list of plugins (usually returned by tep_load_plugins()
425  *
426  * Writes to the trace_seq @s the list of plugins (files) that is
427  * returned by tep_load_plugins(). Use @prefix and @suffix for formating:
428  * @prefix = "  ", @suffix = "\n".
429  */
430 void tep_print_plugins(struct trace_seq *s,
431                        const char *prefix, const char *suffix,
432                        const struct tep_plugin_list *list)
433 {
434         while (list) {
435                 trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix);
436                 list = list->next;
437         }
438 }
439
440 static void
441 load_plugin(struct tep_handle *tep, const char *path,
442             const char *file, void *data)
443 {
444         struct tep_plugin_list **plugin_list = data;
445         struct tep_plugin_option *options;
446         tep_plugin_load_func func;
447         struct tep_plugin_list *list;
448         const char *alias;
449         char *plugin;
450         void *handle;
451         int ret;
452
453         ret = asprintf(&plugin, "%s/%s", path, file);
454         if (ret < 0) {
455                 warning("could not allocate plugin memory\n");
456                 return;
457         }
458
459         handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL);
460         if (!handle) {
461                 warning("could not load plugin '%s'\n%s\n",
462                         plugin, dlerror());
463                 goto out_free;
464         }
465
466         alias = dlsym(handle, TEP_PLUGIN_ALIAS_NAME);
467         if (!alias)
468                 alias = file;
469
470         options = dlsym(handle, TEP_PLUGIN_OPTIONS_NAME);
471         if (options) {
472                 while (options->name) {
473                         ret = update_option(alias, options);
474                         if (ret < 0)
475                                 goto out_free;
476                         options++;
477                 }
478         }
479
480         func = dlsym(handle, TEP_PLUGIN_LOADER_NAME);
481         if (!func) {
482                 warning("could not find func '%s' in plugin '%s'\n%s\n",
483                         TEP_PLUGIN_LOADER_NAME, plugin, dlerror());
484                 goto out_free;
485         }
486
487         list = malloc(sizeof(*list));
488         if (!list) {
489                 warning("could not allocate plugin memory\n");
490                 goto out_free;
491         }
492
493         list->next = *plugin_list;
494         list->handle = handle;
495         list->name = plugin;
496         *plugin_list = list;
497
498         pr_stat("registering plugin: %s", plugin);
499         func(tep);
500         return;
501
502  out_free:
503         free(plugin);
504 }
505
506 static void
507 load_plugins_dir(struct tep_handle *tep, const char *suffix,
508                  const char *path,
509                  void (*load_plugin)(struct tep_handle *tep,
510                                      const char *path,
511                                      const char *name,
512                                      void *data),
513                  void *data)
514 {
515         struct dirent *dent;
516         struct stat st;
517         DIR *dir;
518         int ret;
519
520         ret = stat(path, &st);
521         if (ret < 0)
522                 return;
523
524         if (!S_ISDIR(st.st_mode))
525                 return;
526
527         dir = opendir(path);
528         if (!dir)
529                 return;
530
531         while ((dent = readdir(dir))) {
532                 const char *name = dent->d_name;
533
534                 if (strcmp(name, ".") == 0 ||
535                     strcmp(name, "..") == 0)
536                         continue;
537
538                 /* Only load plugins that end in suffix */
539                 if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0)
540                         continue;
541
542                 load_plugin(tep, path, name, data);
543         }
544
545         closedir(dir);
546 }
547
548 /**
549  * tep_load_plugins_hook - call a user specified callback to load a plugin
550  * @tep: handler to traceevent context
551  * @suffix: filter only plugin files with given suffix
552  * @load_plugin: user specified callback, called for each plugin file
553  * @data: custom context, passed to @load_plugin
554  *
555  * Searches for traceevent plugin files and calls @load_plugin for each
556  * The order of plugins search is:
557  *  - Directories, specified in @tep->plugins_dir and priority TEP_PLUGIN_FIRST
558  *  - Directory, specified at compile time with PLUGIN_TRACEEVENT_DIR
559  *  - Directory, specified by environment variable TRACEEVENT_PLUGIN_DIR
560  *  - In user's home: ~/.local/lib/traceevent/plugins/
561  *  - Directories, specified in @tep->plugins_dir and priority TEP_PLUGIN_LAST
562  *
563  */
564 void tep_load_plugins_hook(struct tep_handle *tep, const char *suffix,
565                            void (*load_plugin)(struct tep_handle *tep,
566                                                const char *path,
567                                                const char *name,
568                                                void *data),
569                            void *data)
570 {
571         struct tep_plugins_dir *dir = NULL;
572         char *home;
573         char *path;
574         char *envdir;
575         int ret;
576
577         if (tep && tep->flags & TEP_DISABLE_PLUGINS)
578                 return;
579
580         if (tep)
581                 dir = tep->plugins_dir;
582         while (dir) {
583                 if (dir->prio == TEP_PLUGIN_FIRST)
584                         load_plugins_dir(tep, suffix, dir->path,
585                                          load_plugin, data);
586                 dir = dir->next;
587         }
588
589         /*
590          * If a system plugin directory was defined,
591          * check that first.
592          */
593 #ifdef PLUGIN_DIR
594         if (!tep || !(tep->flags & TEP_DISABLE_SYS_PLUGINS))
595                 load_plugins_dir(tep, suffix, PLUGIN_DIR,
596                                  load_plugin, data);
597 #endif
598
599         /*
600          * Next let the environment-set plugin directory
601          * override the system defaults.
602          */
603         envdir = getenv("TRACEEVENT_PLUGIN_DIR");
604         if (envdir)
605                 load_plugins_dir(tep, suffix, envdir, load_plugin, data);
606
607         /*
608          * Now let the home directory override the environment
609          * or system defaults.
610          */
611         home = getenv("HOME");
612         if (!home)
613                 return;
614
615         ret = asprintf(&path, "%s/%s", home, LOCAL_PLUGIN_DIR);
616         if (ret < 0) {
617                 warning("could not allocate plugin memory\n");
618                 return;
619         }
620
621         load_plugins_dir(tep, suffix, path, load_plugin, data);
622
623         if (tep)
624                 dir = tep->plugins_dir;
625         while (dir) {
626                 if (dir->prio == TEP_PLUGIN_LAST)
627                         load_plugins_dir(tep, suffix, dir->path,
628                                          load_plugin, data);
629                 dir = dir->next;
630         }
631
632         free(path);
633 }
634
635 struct tep_plugin_list*
636 tep_load_plugins(struct tep_handle *tep)
637 {
638         struct tep_plugin_list *list = NULL;
639
640         tep_load_plugins_hook(tep, ".so", load_plugin, &list);
641         return list;
642 }
643
644 /**
645  * tep_add_plugin_path - Add a new plugin directory.
646  * @tep: Trace event handler.
647  * @path: Path to a directory. All files with extension .so in that
648  *        directory will be loaded as plugins.
649  *@prio: Load priority of the plugins in that directory.
650  *
651  * Returns -1 in case of an error, 0 otherwise.
652  */
653 int tep_add_plugin_path(struct tep_handle *tep, char *path,
654                         enum tep_plugin_load_priority prio)
655 {
656         struct tep_plugins_dir *dir;
657
658         if (!tep || !path)
659                 return -1;
660
661         dir = calloc(1, sizeof(*dir));
662         if (!dir)
663                 return -1;
664
665         dir->path = strdup(path);
666         dir->prio = prio;
667         dir->next = tep->plugins_dir;
668         tep->plugins_dir = dir;
669
670         return 0;
671 }
672
673 void tep_free_plugin_paths(struct tep_handle *tep)
674 {
675         struct tep_plugins_dir *dir;
676
677         if (!tep)
678                 return;
679
680         dir = tep->plugins_dir;
681         while (dir) {
682                 tep->plugins_dir = tep->plugins_dir->next;
683                 free(dir->path);
684                 free(dir);
685                 dir = tep->plugins_dir;
686         }
687 }
688
689 void
690 tep_unload_plugins(struct tep_plugin_list *plugin_list, struct tep_handle *tep)
691 {
692         tep_plugin_unload_func func;
693         struct tep_plugin_list *list;
694
695         while (plugin_list) {
696                 list = plugin_list;
697                 plugin_list = list->next;
698                 func = dlsym(list->handle, TEP_PLUGIN_UNLOADER_NAME);
699                 if (func)
700                         func(tep);
701                 dlclose(list->handle);
702                 free(list->name);
703                 free(list);
704         }
705 }