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

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

Version: ~ [ linux-4.17-rc6 ] ~ [ linux-4.16.10 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.42 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.101 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.132 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.51 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.109 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.56 ] ~ [ 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.101 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.27.62 ] ~ [ 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                         int ret;
124 
125                         ret = asprintf(&name, "%s:%s", alias, op->name);
126                         if (ret < 0)
127                                 goto err;
128 
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         int ret;
294 
295         ret = asprintf(&plugin, "%s/%s", path, file);
296         if (ret < 0) {
297                 warning("could not allocate plugin memory\n");
298                 return;
299         }
300 
301         handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL);
302         if (!handle) {
303                 warning("could not load plugin '%s'\n%s\n",
304                         plugin, dlerror());
305                 goto out_free;
306         }
307 
308         alias = dlsym(handle, PEVENT_PLUGIN_ALIAS_NAME);
309         if (!alias)
310                 alias = file;
311 
312         func = dlsym(handle, PEVENT_PLUGIN_LOADER_NAME);
313         if (!func) {
314                 warning("could not find func '%s' in plugin '%s'\n%s\n",
315                         PEVENT_PLUGIN_LOADER_NAME, plugin, dlerror());
316                 goto out_free;
317         }
318 
319         list = malloc(sizeof(*list));
320         if (!list) {
321                 warning("could not allocate plugin memory\n");
322                 goto out_free;
323         }
324 
325         list->next = *plugin_list;
326         list->handle = handle;
327         list->name = plugin;
328         *plugin_list = list;
329 
330         pr_stat("registering plugin: %s", plugin);
331         func(pevent);
332         return;
333 
334  out_free:
335         free(plugin);
336 }
337 
338 static void
339 load_plugins_dir(struct pevent *pevent, const char *suffix,
340                  const char *path,
341                  void (*load_plugin)(struct pevent *pevent,
342                                      const char *path,
343                                      const char *name,
344                                      void *data),
345                  void *data)
346 {
347         struct dirent *dent;
348         struct stat st;
349         DIR *dir;
350         int ret;
351 
352         ret = stat(path, &st);
353         if (ret < 0)
354                 return;
355 
356         if (!S_ISDIR(st.st_mode))
357                 return;
358 
359         dir = opendir(path);
360         if (!dir)
361                 return;
362 
363         while ((dent = readdir(dir))) {
364                 const char *name = dent->d_name;
365 
366                 if (strcmp(name, ".") == 0 ||
367                     strcmp(name, "..") == 0)
368                         continue;
369 
370                 /* Only load plugins that end in suffix */
371                 if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0)
372                         continue;
373 
374                 load_plugin(pevent, path, name, data);
375         }
376 
377         closedir(dir);
378 }
379 
380 static void
381 load_plugins(struct pevent *pevent, const char *suffix,
382              void (*load_plugin)(struct pevent *pevent,
383                                  const char *path,
384                                  const char *name,
385                                  void *data),
386              void *data)
387 {
388         char *home;
389         char *path;
390         char *envdir;
391         int ret;
392 
393         if (pevent->flags & PEVENT_DISABLE_PLUGINS)
394                 return;
395 
396         /*
397          * If a system plugin directory was defined,
398          * check that first.
399          */
400 #ifdef PLUGIN_DIR
401         if (!(pevent->flags & PEVENT_DISABLE_SYS_PLUGINS))
402                 load_plugins_dir(pevent, suffix, PLUGIN_DIR,
403                                  load_plugin, data);
404 #endif
405 
406         /*
407          * Next let the environment-set plugin directory
408          * override the system defaults.
409          */
410         envdir = getenv("TRACEEVENT_PLUGIN_DIR");
411         if (envdir)
412                 load_plugins_dir(pevent, suffix, envdir, load_plugin, data);
413 
414         /*
415          * Now let the home directory override the environment
416          * or system defaults.
417          */
418         home = getenv("HOME");
419         if (!home)
420                 return;
421 
422         ret = asprintf(&path, "%s/%s", home, LOCAL_PLUGIN_DIR);
423         if (ret < 0) {
424                 warning("could not allocate plugin memory\n");
425                 return;
426         }
427 
428         load_plugins_dir(pevent, suffix, path, load_plugin, data);
429 
430         free(path);
431 }
432 
433 struct plugin_list*
434 traceevent_load_plugins(struct pevent *pevent)
435 {
436         struct plugin_list *list = NULL;
437 
438         load_plugins(pevent, ".so", load_plugin, &list);
439         return list;
440 }
441 
442 void
443 traceevent_unload_plugins(struct plugin_list *plugin_list, struct pevent *pevent)
444 {
445         pevent_plugin_unload_func func;
446         struct plugin_list *list;
447 
448         while (plugin_list) {
449                 list = plugin_list;
450                 plugin_list = list->next;
451                 func = dlsym(list->handle, PEVENT_PLUGIN_UNLOADER_NAME);
452                 if (func)
453                         func(pevent);
454                 dlclose(list->handle);
455                 free(list->name);
456                 free(list);
457         }
458 }
459 

~ [ 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