~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/lib/traceevent/event-plugin.c

Version: ~ [ linux-5.4-rc3 ] ~ [ linux-5.3.6 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.79 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.149 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.196 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.196 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.75 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 21 #include <ctype.h>
 22 #include <stdio.h>
 23 #include <string.h>
 24 #include <dlfcn.h>
 25 #include <stdlib.h>
 26 #include <sys/types.h>
 27 #include <sys/stat.h>
 28 #include <unistd.h>
 29 #include <dirent.h>
 30 #include "event-parse.h"
 31 #include "event-utils.h"
 32 
 33 #define LOCAL_PLUGIN_DIR ".traceevent/plugins"
 34 
 35 static struct registered_plugin_options {
 36         struct registered_plugin_options        *next;
 37         struct pevent_plugin_option             *options;
 38 } *registered_options;
 39 
 40 static struct trace_plugin_options {
 41         struct trace_plugin_options     *next;
 42         char                            *plugin;
 43         char                            *option;
 44         char                            *value;
 45 } *trace_plugin_options;
 46 
 47 struct plugin_list {
 48         struct plugin_list      *next;
 49         char                    *name;
 50         void                    *handle;
 51 };
 52 
 53 static void lower_case(char *str)
 54 {
 55         if (!str)
 56                 return;
 57         for (; *str; str++)
 58                 *str = tolower(*str);
 59 }
 60 
 61 static int update_option_value(struct pevent_plugin_option *op, const char *val)
 62 {
 63         char *op_val;
 64 
 65         if (!val) {
 66                 /* toggle, only if option is boolean */
 67                 if (op->value)
 68                         /* Warn? */
 69                         return 0;
 70                 op->set ^= 1;
 71                 return 0;
 72         }
 73 
 74         /*
 75          * If the option has a value then it takes a string
 76          * otherwise the option is a boolean.
 77          */
 78         if (op->value) {
 79                 op->value = val;
 80                 return 0;
 81         }
 82 
 83         /* Option is boolean, must be either "1", "", "true" or "false" */
 84 
 85         op_val = strdup(val);
 86         if (!op_val)
 87                 return -1;
 88         lower_case(op_val);
 89 
 90         if (strcmp(val, "1") == 0 || strcmp(val, "true") == 0)
 91                 op->set = 1;
 92         else if (strcmp(val, "") == 0 || strcmp(val, "false") == 0)
 93                 op->set = 0;
 94         free(op_val);
 95 
 96         return 0;
 97 }
 98 
 99 /**
100  * traceevent_plugin_list_options - get list of plugin options
101  *
102  * Returns an array of char strings that list the currently registered
103  * plugin options in the format of <plugin>:<option>. This list can be
104  * used by toggling the option.
105  *
106  * Returns NULL if there's no options registered. On error it returns
107  * INVALID_PLUGIN_LIST_OPTION
108  *
109  * Must be freed with traceevent_plugin_free_options_list().
110  */
111 char **traceevent_plugin_list_options(void)
112 {
113         struct registered_plugin_options *reg;
114         struct pevent_plugin_option *op;
115         char **list = NULL;
116         char *name;
117         int count = 0;
118 
119         for (reg = registered_options; reg; reg = reg->next) {
120                 for (op = reg->options; op->name; op++) {
121                         char *alias = op->plugin_alias ? op->plugin_alias : op->file;
122                         char **temp = list;
123 
124                         name = malloc(strlen(op->name) + strlen(alias) + 2);
125                         if (!name)
126                                 goto err;
127 
128                         sprintf(name, "%s:%s", alias, op->name);
129                         list = realloc(list, count + 2);
130                         if (!list) {
131                                 list = temp;
132                                 free(name);
133                                 goto err;
134                         }
135                         list[count++] = name;
136                         list[count] = NULL;
137                 }
138         }
139         return list;
140 
141  err:
142         while (--count >= 0)
143                 free(list[count]);
144         free(list);
145 
146         return INVALID_PLUGIN_LIST_OPTION;
147 }
148 
149 void traceevent_plugin_free_options_list(char **list)
150 {
151         int i;
152 
153         if (!list)
154                 return;
155 
156         if (list == INVALID_PLUGIN_LIST_OPTION)
157                 return;
158 
159         for (i = 0; list[i]; i++)
160                 free(list[i]);
161 
162         free(list);
163 }
164 
165 static int
166 update_option(const char *file, struct pevent_plugin_option *option)
167 {
168         struct trace_plugin_options *op;
169         char *plugin;
170         int ret = 0;
171 
172         if (option->plugin_alias) {
173                 plugin = strdup(option->plugin_alias);
174                 if (!plugin)
175                         return -1;
176         } else {
177                 char *p;
178                 plugin = strdup(file);
179                 if (!plugin)
180                         return -1;
181                 p = strstr(plugin, ".");
182                 if (p)
183                         *p = '\0';
184         }
185 
186         /* first look for named options */
187         for (op = trace_plugin_options; op; op = op->next) {
188                 if (!op->plugin)
189                         continue;
190                 if (strcmp(op->plugin, plugin) != 0)
191                         continue;
192                 if (strcmp(op->option, option->name) != 0)
193                         continue;
194 
195                 ret = update_option_value(option, op->value);
196                 if (ret)
197                         goto out;
198                 break;
199         }
200 
201         /* first look for unnamed options */
202         for (op = trace_plugin_options; op; op = op->next) {
203                 if (op->plugin)
204                         continue;
205                 if (strcmp(op->option, option->name) != 0)
206                         continue;
207 
208                 ret = update_option_value(option, op->value);
209                 break;
210         }
211 
212  out:
213         free(plugin);
214         return ret;
215 }
216 
217 /**
218  * traceevent_plugin_add_options - Add a set of options by a plugin
219  * @name: The name of the plugin adding the options
220  * @options: The set of options being loaded
221  *
222  * Sets the options with the values that have been added by user.
223  */
224 int traceevent_plugin_add_options(const char *name,
225                                   struct pevent_plugin_option *options)
226 {
227         struct registered_plugin_options *reg;
228 
229         reg = malloc(sizeof(*reg));
230         if (!reg)
231                 return -1;
232         reg->next = registered_options;
233         reg->options = options;
234         registered_options = reg;
235 
236         while (options->name) {
237                 update_option(name, options);
238                 options++;
239         }
240         return 0;
241 }
242 
243 /**
244  * traceevent_plugin_remove_options - remove plugin options that were registered
245  * @options: Options to removed that were registered with traceevent_plugin_add_options
246  */
247 void traceevent_plugin_remove_options(struct pevent_plugin_option *options)
248 {
249         struct registered_plugin_options **last;
250         struct registered_plugin_options *reg;
251 
252         for (last = &registered_options; *last; last = &(*last)->next) {
253                 if ((*last)->options == options) {
254                         reg = *last;
255                         *last = reg->next;
256                         free(reg);
257                         return;
258                 }
259         }
260 }
261 
262 /**
263  * traceevent_print_plugins - print out the list of plugins loaded
264  * @s: the trace_seq descripter to write to
265  * @prefix: The prefix string to add before listing the option name
266  * @suffix: The suffix string ot append after the option name
267  * @list: The list of plugins (usually returned by traceevent_load_plugins()
268  *
269  * Writes to the trace_seq @s the list of plugins (files) that is
270  * returned by traceevent_load_plugins(). Use @prefix and @suffix for formating:
271  * @prefix = "  ", @suffix = "\n".
272  */
273 void traceevent_print_plugins(struct trace_seq *s,
274                               const char *prefix, const char *suffix,
275                               const struct plugin_list *list)
276 {
277         while (list) {
278                 trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix);
279                 list = list->next;
280         }
281 }
282 
283 static void
284 load_plugin(struct pevent *pevent, const char *path,
285             const char *file, void *data)
286 {
287         struct plugin_list **plugin_list = data;
288         pevent_plugin_load_func func;
289         struct plugin_list *list;
290         const char *alias;
291         char *plugin;
292         void *handle;
293 
294         plugin = malloc(strlen(path) + strlen(file) + 2);
295         if (!plugin) {
296                 warning("could not allocate plugin memory\n");
297                 return;
298         }
299 
300         strcpy(plugin, path);
301         strcat(plugin, "/");
302         strcat(plugin, file);
303 
304         handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL);
305         if (!handle) {
306                 warning("could not load plugin '%s'\n%s\n",
307                         plugin, dlerror());
308                 goto out_free;
309         }
310 
311         alias = dlsym(handle, PEVENT_PLUGIN_ALIAS_NAME);
312         if (!alias)
313                 alias = file;
314 
315         func = dlsym(handle, PEVENT_PLUGIN_LOADER_NAME);
316         if (!func) {
317                 warning("could not find func '%s' in plugin '%s'\n%s\n",
318                         PEVENT_PLUGIN_LOADER_NAME, plugin, dlerror());
319                 goto out_free;
320         }
321 
322         list = malloc(sizeof(*list));
323         if (!list) {
324                 warning("could not allocate plugin memory\n");
325                 goto out_free;
326         }
327 
328         list->next = *plugin_list;
329         list->handle = handle;
330         list->name = plugin;
331         *plugin_list = list;
332 
333         pr_stat("registering plugin: %s", plugin);
334         func(pevent);
335         return;
336 
337  out_free:
338         free(plugin);
339 }
340 
341 static void
342 load_plugins_dir(struct pevent *pevent, const char *suffix,
343                  const char *path,
344                  void (*load_plugin)(struct pevent *pevent,
345                                      const char *path,
346                                      const char *name,
347                                      void *data),
348                  void *data)
349 {
350         struct dirent *dent;
351         struct stat st;
352         DIR *dir;
353         int ret;
354 
355         ret = stat(path, &st);
356         if (ret < 0)
357                 return;
358 
359         if (!S_ISDIR(st.st_mode))
360                 return;
361 
362         dir = opendir(path);
363         if (!dir)
364                 return;
365 
366         while ((dent = readdir(dir))) {
367                 const char *name = dent->d_name;
368 
369                 if (strcmp(name, ".") == 0 ||
370                     strcmp(name, "..") == 0)
371                         continue;
372 
373                 /* Only load plugins that end in suffix */
374                 if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0)
375                         continue;
376 
377                 load_plugin(pevent, path, name, data);
378         }
379 
380         closedir(dir);
381 }
382 
383 static void
384 load_plugins(struct pevent *pevent, const char *suffix,
385              void (*load_plugin)(struct pevent *pevent,
386                                  const char *path,
387                                  const char *name,
388                                  void *data),
389              void *data)
390 {
391         char *home;
392         char *path;
393         char *envdir;
394 
395         if (pevent->flags & PEVENT_DISABLE_PLUGINS)
396                 return;
397 
398         /*
399          * If a system plugin directory was defined,
400          * check that first.
401          */
402 #ifdef PLUGIN_DIR
403         if (!(pevent->flags & PEVENT_DISABLE_SYS_PLUGINS))
404                 load_plugins_dir(pevent, suffix, PLUGIN_DIR,
405                                  load_plugin, data);
406 #endif
407 
408         /*
409          * Next let the environment-set plugin directory
410          * override the system defaults.
411          */
412         envdir = getenv("TRACEEVENT_PLUGIN_DIR");
413         if (envdir)
414                 load_plugins_dir(pevent, suffix, envdir, load_plugin, data);
415 
416         /*
417          * Now let the home directory override the environment
418          * or system defaults.
419          */
420         home = getenv("HOME");
421         if (!home)
422                 return;
423 
424         path = malloc(strlen(home) + strlen(LOCAL_PLUGIN_DIR) + 2);
425         if (!path) {
426                 warning("could not allocate plugin memory\n");
427                 return;
428         }
429 
430         strcpy(path, home);
431         strcat(path, "/");
432         strcat(path, LOCAL_PLUGIN_DIR);
433 
434         load_plugins_dir(pevent, suffix, path, load_plugin, data);
435 
436         free(path);
437 }
438 
439 struct plugin_list*
440 traceevent_load_plugins(struct pevent *pevent)
441 {
442         struct plugin_list *list = NULL;
443 
444         load_plugins(pevent, ".so", load_plugin, &list);
445         return list;
446 }
447 
448 void
449 traceevent_unload_plugins(struct plugin_list *plugin_list, struct pevent *pevent)
450 {
451         pevent_plugin_unload_func func;
452         struct plugin_list *list;
453 
454         while (plugin_list) {
455                 list = plugin_list;
456                 plugin_list = list->next;
457                 func = dlsym(list->handle, PEVENT_PLUGIN_UNLOADER_NAME);
458                 if (func)
459                         func(pevent);
460                 dlclose(list->handle);
461                 free(list->name);
462                 free(list);
463         }
464 }
465 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp