at v5.2 9.3 kB view raw
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 ".traceevent/plugins" 22 23static struct registered_plugin_options { 24 struct registered_plugin_options *next; 25 struct tep_plugin_option *options; 26} *registered_options; 27 28static struct trace_plugin_options { 29 struct trace_plugin_options *next; 30 char *plugin; 31 char *option; 32 char *value; 33} *trace_plugin_options; 34 35struct tep_plugin_list { 36 struct tep_plugin_list *next; 37 char *name; 38 void *handle; 39}; 40 41static void lower_case(char *str) 42{ 43 if (!str) 44 return; 45 for (; *str; str++) 46 *str = tolower(*str); 47} 48 49static 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 */ 99char **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 137void 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 153static int 154update_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 */ 212int 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 */ 235void 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 */ 261void 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 271static void 272load_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 326static void 327load_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 368static void 369load_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 421struct tep_plugin_list* 422tep_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 430void 431tep_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}