Merge tag 'printk-for-5.10-rc6-fixup' of git://git.kernel.org/pub/scm/linux/kernel...
[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                         goto out_free;
365                 memset(op, 0, sizeof(*op));
366                 op->plugin = plugin;
367                 op->option = option_str;
368                 if (val) {
369                         op->value = strdup(val);
370                         if (!op->value) {
371                                 free(op);
372                                 goto out_free;
373                         }
374                 }
375                 op->next = trace_plugin_options;
376                 trace_plugin_options = op;
377         }
378
379         return process_option(plugin, option_str, val);
380
381 out_free:
382         free(plugin);
383         free(option_str);
384         return -ENOMEM;
385 }
386
387 static void print_op_data(struct trace_seq *s, const char *name,
388                           const char *op)
389 {
390         if (op)
391                 trace_seq_printf(s, "%8s:\t%s\n", name, op);
392 }
393
394 /**
395  * tep_plugin_print_options - print out the registered plugin options
396  * @s: The trace_seq descriptor to write the plugin options into
397  *
398  * Writes a list of options into trace_seq @s.
399  */
400 void tep_plugin_print_options(struct trace_seq *s)
401 {
402         struct registered_plugin_options *reg;
403         struct tep_plugin_option *op;
404
405         for (reg = registered_options; reg; reg = reg->next) {
406                 if (reg != registered_options)
407                         trace_seq_printf(s, "============\n");
408                 for (op = reg->options; op->name; op++) {
409                         if (op != reg->options)
410                                 trace_seq_printf(s, "------------\n");
411                         print_op_data(s, "file", op->file);
412                         print_op_data(s, "plugin", op->plugin_alias);
413                         print_op_data(s, "option", op->name);
414                         print_op_data(s, "desc", op->description);
415                         print_op_data(s, "value", op->value);
416                         trace_seq_printf(s, "%8s:\t%d\n", "set", op->set);
417                 }
418         }
419 }
420
421 /**
422  * tep_print_plugins - print out the list of plugins loaded
423  * @s: the trace_seq descripter to write to
424  * @prefix: The prefix string to add before listing the option name
425  * @suffix: The suffix string ot append after the option name
426  * @list: The list of plugins (usually returned by tep_load_plugins()
427  *
428  * Writes to the trace_seq @s the list of plugins (files) that is
429  * returned by tep_load_plugins(). Use @prefix and @suffix for formating:
430  * @prefix = "  ", @suffix = "\n".
431  */
432 void tep_print_plugins(struct trace_seq *s,
433                        const char *prefix, const char *suffix,
434                        const struct tep_plugin_list *list)
435 {
436         while (list) {
437                 trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix);
438                 list = list->next;
439         }
440 }
441
442 static void
443 load_plugin(struct tep_handle *tep, const char *path,
444             const char *file, void *data)
445 {
446         struct tep_plugin_list **plugin_list = data;
447         struct tep_plugin_option *options;
448         tep_plugin_load_func func;
449         struct tep_plugin_list *list;
450         const char *alias;
451         char *plugin;
452         void *handle;
453         int ret;
454
455         ret = asprintf(&plugin, "%s/%s", path, file);
456         if (ret < 0) {
457                 warning("could not allocate plugin memory\n");
458                 return;
459         }
460
461         handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL);
462         if (!handle) {
463                 warning("could not load plugin '%s'\n%s\n",
464                         plugin, dlerror());
465                 goto out_free;
466         }
467
468         alias = dlsym(handle, TEP_PLUGIN_ALIAS_NAME);
469         if (!alias)
470                 alias = file;
471
472         options = dlsym(handle, TEP_PLUGIN_OPTIONS_NAME);
473         if (options) {
474                 while (options->name) {
475                         ret = update_option(alias, options);
476                         if (ret < 0)
477                                 goto out_free;
478                         options++;
479                 }
480         }
481
482         func = dlsym(handle, TEP_PLUGIN_LOADER_NAME);
483         if (!func) {
484                 warning("could not find func '%s' in plugin '%s'\n%s\n",
485                         TEP_PLUGIN_LOADER_NAME, plugin, dlerror());
486                 goto out_free;
487         }
488
489         list = malloc(sizeof(*list));
490         if (!list) {
491                 warning("could not allocate plugin memory\n");
492                 goto out_free;
493         }
494
495         list->next = *plugin_list;
496         list->handle = handle;
497         list->name = plugin;
498         *plugin_list = list;
499
500         pr_stat("registering plugin: %s", plugin);
501         func(tep);
502         return;
503
504  out_free:
505         free(plugin);
506 }
507
508 static void
509 load_plugins_dir(struct tep_handle *tep, const char *suffix,
510                  const char *path,
511                  void (*load_plugin)(struct tep_handle *tep,
512                                      const char *path,
513                                      const char *name,
514                                      void *data),
515                  void *data)
516 {
517         struct dirent *dent;
518         struct stat st;
519         DIR *dir;
520         int ret;
521
522         ret = stat(path, &st);
523         if (ret < 0)
524                 return;
525
526         if (!S_ISDIR(st.st_mode))
527                 return;
528
529         dir = opendir(path);
530         if (!dir)
531                 return;
532
533         while ((dent = readdir(dir))) {
534                 const char *name = dent->d_name;
535
536                 if (strcmp(name, ".") == 0 ||
537                     strcmp(name, "..") == 0)
538                         continue;
539
540                 /* Only load plugins that end in suffix */
541                 if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0)
542                         continue;
543
544                 load_plugin(tep, path, name, data);
545         }
546
547         closedir(dir);
548 }
549
550 /**
551  * tep_load_plugins_hook - call a user specified callback to load a plugin
552  * @tep: handler to traceevent context
553  * @suffix: filter only plugin files with given suffix
554  * @load_plugin: user specified callback, called for each plugin file
555  * @data: custom context, passed to @load_plugin
556  *
557  * Searches for traceevent plugin files and calls @load_plugin for each
558  * The order of plugins search is:
559  *  - Directories, specified in @tep->plugins_dir and priority TEP_PLUGIN_FIRST
560  *  - Directory, specified at compile time with PLUGIN_TRACEEVENT_DIR
561  *  - Directory, specified by environment variable TRACEEVENT_PLUGIN_DIR
562  *  - In user's home: ~/.local/lib/traceevent/plugins/
563  *  - Directories, specified in @tep->plugins_dir and priority TEP_PLUGIN_LAST
564  *
565  */
566 void tep_load_plugins_hook(struct tep_handle *tep, const char *suffix,
567                            void (*load_plugin)(struct tep_handle *tep,
568                                                const char *path,
569                                                const char *name,
570                                                void *data),
571                            void *data)
572 {
573         struct tep_plugins_dir *dir = NULL;
574         char *home;
575         char *path;
576         char *envdir;
577         int ret;
578
579         if (tep && tep->flags & TEP_DISABLE_PLUGINS)
580                 return;
581
582         if (tep)
583                 dir = tep->plugins_dir;
584         while (dir) {
585                 if (dir->prio == TEP_PLUGIN_FIRST)
586                         load_plugins_dir(tep, suffix, dir->path,
587                                          load_plugin, data);
588                 dir = dir->next;
589         }
590
591         /*
592          * If a system plugin directory was defined,
593          * check that first.
594          */
595 #ifdef PLUGIN_DIR
596         if (!tep || !(tep->flags & TEP_DISABLE_SYS_PLUGINS))
597                 load_plugins_dir(tep, suffix, PLUGIN_DIR,
598                                  load_plugin, data);
599 #endif
600
601         /*
602          * Next let the environment-set plugin directory
603          * override the system defaults.
604          */
605         envdir = getenv("TRACEEVENT_PLUGIN_DIR");
606         if (envdir)
607                 load_plugins_dir(tep, suffix, envdir, load_plugin, data);
608
609         /*
610          * Now let the home directory override the environment
611          * or system defaults.
612          */
613         home = getenv("HOME");
614         if (!home)
615                 return;
616
617         ret = asprintf(&path, "%s/%s", home, LOCAL_PLUGIN_DIR);
618         if (ret < 0) {
619                 warning("could not allocate plugin memory\n");
620                 return;
621         }
622
623         load_plugins_dir(tep, suffix, path, load_plugin, data);
624
625         if (tep)
626                 dir = tep->plugins_dir;
627         while (dir) {
628                 if (dir->prio == TEP_PLUGIN_LAST)
629                         load_plugins_dir(tep, suffix, dir->path,
630                                          load_plugin, data);
631                 dir = dir->next;
632         }
633
634         free(path);
635 }
636
637 struct tep_plugin_list*
638 tep_load_plugins(struct tep_handle *tep)
639 {
640         struct tep_plugin_list *list = NULL;
641
642         tep_load_plugins_hook(tep, ".so", load_plugin, &list);
643         return list;
644 }
645
646 /**
647  * tep_add_plugin_path - Add a new plugin directory.
648  * @tep: Trace event handler.
649  * @path: Path to a directory. All plugin files in that
650  *        directory will be loaded.
651  *@prio: Load priority of the plugins in that directory.
652  *
653  * Returns -1 in case of an error, 0 otherwise.
654  */
655 int tep_add_plugin_path(struct tep_handle *tep, char *path,
656                         enum tep_plugin_load_priority prio)
657 {
658         struct tep_plugins_dir *dir;
659
660         if (!tep || !path)
661                 return -1;
662
663         dir = calloc(1, sizeof(*dir));
664         if (!dir)
665                 return -1;
666
667         dir->path = strdup(path);
668         if (!dir->path) {
669                 free(dir);
670                 return -1;
671         }
672         dir->prio = prio;
673         dir->next = tep->plugins_dir;
674         tep->plugins_dir = dir;
675
676         return 0;
677 }
678
679 __hidden void free_tep_plugin_paths(struct tep_handle *tep)
680 {
681         struct tep_plugins_dir *dir;
682
683         if (!tep)
684                 return;
685
686         dir = tep->plugins_dir;
687         while (dir) {
688                 tep->plugins_dir = tep->plugins_dir->next;
689                 free(dir->path);
690                 free(dir);
691                 dir = tep->plugins_dir;
692         }
693 }
694
695 void
696 tep_unload_plugins(struct tep_plugin_list *plugin_list, struct tep_handle *tep)
697 {
698         tep_plugin_unload_func func;
699         struct tep_plugin_list *list;
700
701         while (plugin_list) {
702                 list = plugin_list;
703                 plugin_list = list->next;
704                 func = dlsym(list->handle, TEP_PLUGIN_UNLOADER_NAME);
705                 if (func)
706                         func(tep);
707                 dlclose(list->handle);
708                 free(list->name);
709                 free(list);
710         }
711 }