root/tools/lib/traceevent/event-plugin.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lower_case
  2. update_option_value
  3. tep_plugin_list_options
  4. tep_plugin_free_options_list
  5. update_option
  6. tep_plugin_add_options
  7. tep_plugin_remove_options
  8. tep_print_plugins
  9. load_plugin
  10. load_plugins_dir
  11. load_plugins
  12. tep_load_plugins
  13. tep_unload_plugins

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

/* [<][>][^][v][top][bottom][index][help] */