0001
0002
0003
0004
0005
0006
0007 #include <ctype.h>
0008 #include <stdio.h>
0009 #include <string.h>
0010 #include <dlfcn.h>
0011 #include <stdlib.h>
0012 #include <sys/types.h>
0013 #include <sys/stat.h>
0014 #include <unistd.h>
0015 #include <dirent.h>
0016 #include <errno.h>
0017 #include "event-parse.h"
0018 #include "event-parse-local.h"
0019 #include "event-utils.h"
0020 #include "trace-seq.h"
0021
0022 #define LOCAL_PLUGIN_DIR ".local/lib/traceevent/plugins/"
0023
0024 static struct registered_plugin_options {
0025 struct registered_plugin_options *next;
0026 struct tep_plugin_option *options;
0027 } *registered_options;
0028
0029 static struct trace_plugin_options {
0030 struct trace_plugin_options *next;
0031 char *plugin;
0032 char *option;
0033 char *value;
0034 } *trace_plugin_options;
0035
0036 struct tep_plugin_list {
0037 struct tep_plugin_list *next;
0038 char *name;
0039 void *handle;
0040 };
0041
0042 struct tep_plugins_dir {
0043 struct tep_plugins_dir *next;
0044 char *path;
0045 enum tep_plugin_load_priority prio;
0046 };
0047
0048 static void lower_case(char *str)
0049 {
0050 if (!str)
0051 return;
0052 for (; *str; str++)
0053 *str = tolower(*str);
0054 }
0055
0056 static int update_option_value(struct tep_plugin_option *op, const char *val)
0057 {
0058 char *op_val;
0059
0060 if (!val) {
0061
0062 if (op->value)
0063
0064 return 0;
0065 op->set ^= 1;
0066 return 0;
0067 }
0068
0069
0070
0071
0072
0073 if (op->value) {
0074 op->value = val;
0075 return 0;
0076 }
0077
0078
0079
0080 op_val = strdup(val);
0081 if (!op_val)
0082 return -1;
0083 lower_case(op_val);
0084
0085 if (strcmp(val, "1") == 0 || strcmp(val, "true") == 0)
0086 op->set = 1;
0087 else if (strcmp(val, "0") == 0 || strcmp(val, "false") == 0)
0088 op->set = 0;
0089 free(op_val);
0090
0091 return 0;
0092 }
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106 char **tep_plugin_list_options(void)
0107 {
0108 struct registered_plugin_options *reg;
0109 struct tep_plugin_option *op;
0110 char **list = NULL;
0111 char *name;
0112 int count = 0;
0113
0114 for (reg = registered_options; reg; reg = reg->next) {
0115 for (op = reg->options; op->name; op++) {
0116 char *alias = op->plugin_alias ? op->plugin_alias : op->file;
0117 char **temp = list;
0118 int ret;
0119
0120 ret = asprintf(&name, "%s:%s", alias, op->name);
0121 if (ret < 0)
0122 goto err;
0123
0124 list = realloc(list, count + 2);
0125 if (!list) {
0126 list = temp;
0127 free(name);
0128 goto err;
0129 }
0130 list[count++] = name;
0131 list[count] = NULL;
0132 }
0133 }
0134 return list;
0135
0136 err:
0137 while (--count >= 0)
0138 free(list[count]);
0139 free(list);
0140
0141 return INVALID_PLUGIN_LIST_OPTION;
0142 }
0143
0144 void tep_plugin_free_options_list(char **list)
0145 {
0146 int i;
0147
0148 if (!list)
0149 return;
0150
0151 if (list == INVALID_PLUGIN_LIST_OPTION)
0152 return;
0153
0154 for (i = 0; list[i]; i++)
0155 free(list[i]);
0156
0157 free(list);
0158 }
0159
0160 static int
0161 update_option(const char *file, struct tep_plugin_option *option)
0162 {
0163 struct trace_plugin_options *op;
0164 char *plugin;
0165 int ret = 0;
0166
0167 if (option->plugin_alias) {
0168 plugin = strdup(option->plugin_alias);
0169 if (!plugin)
0170 return -1;
0171 } else {
0172 char *p;
0173 plugin = strdup(file);
0174 if (!plugin)
0175 return -1;
0176 p = strstr(plugin, ".");
0177 if (p)
0178 *p = '\0';
0179 }
0180
0181
0182 for (op = trace_plugin_options; op; op = op->next) {
0183 if (!op->plugin)
0184 continue;
0185 if (strcmp(op->plugin, plugin) != 0)
0186 continue;
0187 if (strcmp(op->option, option->name) != 0)
0188 continue;
0189
0190 ret = update_option_value(option, op->value);
0191 if (ret)
0192 goto out;
0193 break;
0194 }
0195
0196
0197 for (op = trace_plugin_options; op; op = op->next) {
0198 if (op->plugin)
0199 continue;
0200 if (strcmp(op->option, option->name) != 0)
0201 continue;
0202
0203 ret = update_option_value(option, op->value);
0204 break;
0205 }
0206
0207 out:
0208 free(plugin);
0209 return ret;
0210 }
0211
0212
0213
0214
0215
0216
0217
0218
0219 int tep_plugin_add_options(const char *name,
0220 struct tep_plugin_option *options)
0221 {
0222 struct registered_plugin_options *reg;
0223
0224 reg = malloc(sizeof(*reg));
0225 if (!reg)
0226 return -1;
0227 reg->next = registered_options;
0228 reg->options = options;
0229 registered_options = reg;
0230
0231 while (options->name) {
0232 update_option(name, options);
0233 options++;
0234 }
0235 return 0;
0236 }
0237
0238
0239
0240
0241
0242 void tep_plugin_remove_options(struct tep_plugin_option *options)
0243 {
0244 struct registered_plugin_options **last;
0245 struct registered_plugin_options *reg;
0246
0247 for (last = ®istered_options; *last; last = &(*last)->next) {
0248 if ((*last)->options == options) {
0249 reg = *last;
0250 *last = reg->next;
0251 free(reg);
0252 return;
0253 }
0254 }
0255 }
0256
0257 static int parse_option_name(char **option, char **plugin)
0258 {
0259 char *p;
0260
0261 *plugin = NULL;
0262
0263 if ((p = strstr(*option, ":"))) {
0264 *plugin = *option;
0265 *p = '\0';
0266 *option = strdup(p + 1);
0267 if (!*option)
0268 return -1;
0269 }
0270 return 0;
0271 }
0272
0273 static struct tep_plugin_option *
0274 find_registered_option(const char *plugin, const char *option)
0275 {
0276 struct registered_plugin_options *reg;
0277 struct tep_plugin_option *op;
0278 const char *op_plugin;
0279
0280 for (reg = registered_options; reg; reg = reg->next) {
0281 for (op = reg->options; op->name; op++) {
0282 if (op->plugin_alias)
0283 op_plugin = op->plugin_alias;
0284 else
0285 op_plugin = op->file;
0286
0287 if (plugin && strcmp(plugin, op_plugin) != 0)
0288 continue;
0289 if (strcmp(option, op->name) != 0)
0290 continue;
0291
0292 return op;
0293 }
0294 }
0295
0296 return NULL;
0297 }
0298
0299 static int process_option(const char *plugin, const char *option, const char *val)
0300 {
0301 struct tep_plugin_option *op;
0302
0303 op = find_registered_option(plugin, option);
0304 if (!op)
0305 return 0;
0306
0307 return update_option_value(op, val);
0308 }
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319 int tep_plugin_add_option(const char *name, const char *val)
0320 {
0321 struct trace_plugin_options *op;
0322 char *option_str;
0323 char *plugin;
0324
0325 option_str = strdup(name);
0326 if (!option_str)
0327 return -ENOMEM;
0328
0329 if (parse_option_name(&option_str, &plugin) < 0)
0330 return -ENOMEM;
0331
0332
0333 for (op = trace_plugin_options; op; op = op->next) {
0334
0335 if ((!plugin || !op->plugin) && plugin != op->plugin)
0336 continue;
0337 if (plugin && strcmp(plugin, op->plugin) != 0)
0338 continue;
0339 if (strcmp(op->option, option_str) != 0)
0340 continue;
0341
0342
0343 free(op->value);
0344 if (val) {
0345 op->value = strdup(val);
0346 if (!op->value)
0347 goto out_free;
0348 } else
0349 op->value = NULL;
0350
0351
0352 free(plugin);
0353 free(option_str);
0354
0355 plugin = op->plugin;
0356 option_str = op->option;
0357 break;
0358 }
0359
0360
0361 if (!op) {
0362 op = malloc(sizeof(*op));
0363 if (!op)
0364 goto out_free;
0365 memset(op, 0, sizeof(*op));
0366 op->plugin = plugin;
0367 op->option = option_str;
0368 if (val) {
0369 op->value = strdup(val);
0370 if (!op->value) {
0371 free(op);
0372 goto out_free;
0373 }
0374 }
0375 op->next = trace_plugin_options;
0376 trace_plugin_options = op;
0377 }
0378
0379 return process_option(plugin, option_str, val);
0380
0381 out_free:
0382 free(plugin);
0383 free(option_str);
0384 return -ENOMEM;
0385 }
0386
0387 static void print_op_data(struct trace_seq *s, const char *name,
0388 const char *op)
0389 {
0390 if (op)
0391 trace_seq_printf(s, "%8s:\t%s\n", name, op);
0392 }
0393
0394
0395
0396
0397
0398
0399
0400 void tep_plugin_print_options(struct trace_seq *s)
0401 {
0402 struct registered_plugin_options *reg;
0403 struct tep_plugin_option *op;
0404
0405 for (reg = registered_options; reg; reg = reg->next) {
0406 if (reg != registered_options)
0407 trace_seq_printf(s, "============\n");
0408 for (op = reg->options; op->name; op++) {
0409 if (op != reg->options)
0410 trace_seq_printf(s, "------------\n");
0411 print_op_data(s, "file", op->file);
0412 print_op_data(s, "plugin", op->plugin_alias);
0413 print_op_data(s, "option", op->name);
0414 print_op_data(s, "desc", op->description);
0415 print_op_data(s, "value", op->value);
0416 trace_seq_printf(s, "%8s:\t%d\n", "set", op->set);
0417 }
0418 }
0419 }
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432 void tep_print_plugins(struct trace_seq *s,
0433 const char *prefix, const char *suffix,
0434 const struct tep_plugin_list *list)
0435 {
0436 while (list) {
0437 trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix);
0438 list = list->next;
0439 }
0440 }
0441
0442 static void
0443 load_plugin(struct tep_handle *tep, const char *path,
0444 const char *file, void *data)
0445 {
0446 struct tep_plugin_list **plugin_list = data;
0447 struct tep_plugin_option *options;
0448 tep_plugin_load_func func;
0449 struct tep_plugin_list *list;
0450 const char *alias;
0451 char *plugin;
0452 void *handle;
0453 int ret;
0454
0455 ret = asprintf(&plugin, "%s/%s", path, file);
0456 if (ret < 0) {
0457 warning("could not allocate plugin memory\n");
0458 return;
0459 }
0460
0461 handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL);
0462 if (!handle) {
0463 warning("could not load plugin '%s'\n%s\n",
0464 plugin, dlerror());
0465 goto out_free;
0466 }
0467
0468 alias = dlsym(handle, TEP_PLUGIN_ALIAS_NAME);
0469 if (!alias)
0470 alias = file;
0471
0472 options = dlsym(handle, TEP_PLUGIN_OPTIONS_NAME);
0473 if (options) {
0474 while (options->name) {
0475 ret = update_option(alias, options);
0476 if (ret < 0)
0477 goto out_free;
0478 options++;
0479 }
0480 }
0481
0482 func = dlsym(handle, TEP_PLUGIN_LOADER_NAME);
0483 if (!func) {
0484 warning("could not find func '%s' in plugin '%s'\n%s\n",
0485 TEP_PLUGIN_LOADER_NAME, plugin, dlerror());
0486 goto out_free;
0487 }
0488
0489 list = malloc(sizeof(*list));
0490 if (!list) {
0491 warning("could not allocate plugin memory\n");
0492 goto out_free;
0493 }
0494
0495 list->next = *plugin_list;
0496 list->handle = handle;
0497 list->name = plugin;
0498 *plugin_list = list;
0499
0500 pr_stat("registering plugin: %s", plugin);
0501 func(tep);
0502 return;
0503
0504 out_free:
0505 free(plugin);
0506 }
0507
0508 static void
0509 load_plugins_dir(struct tep_handle *tep, const char *suffix,
0510 const char *path,
0511 void (*load_plugin)(struct tep_handle *tep,
0512 const char *path,
0513 const char *name,
0514 void *data),
0515 void *data)
0516 {
0517 struct dirent *dent;
0518 struct stat st;
0519 DIR *dir;
0520 int ret;
0521
0522 ret = stat(path, &st);
0523 if (ret < 0)
0524 return;
0525
0526 if (!S_ISDIR(st.st_mode))
0527 return;
0528
0529 dir = opendir(path);
0530 if (!dir)
0531 return;
0532
0533 while ((dent = readdir(dir))) {
0534 const char *name = dent->d_name;
0535
0536 if (strcmp(name, ".") == 0 ||
0537 strcmp(name, "..") == 0)
0538 continue;
0539
0540
0541 if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0)
0542 continue;
0543
0544 load_plugin(tep, path, name, data);
0545 }
0546
0547 closedir(dir);
0548 }
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566 void tep_load_plugins_hook(struct tep_handle *tep, const char *suffix,
0567 void (*load_plugin)(struct tep_handle *tep,
0568 const char *path,
0569 const char *name,
0570 void *data),
0571 void *data)
0572 {
0573 struct tep_plugins_dir *dir = NULL;
0574 char *home;
0575 char *path;
0576 char *envdir;
0577 int ret;
0578
0579 if (tep && tep->flags & TEP_DISABLE_PLUGINS)
0580 return;
0581
0582 if (tep)
0583 dir = tep->plugins_dir;
0584 while (dir) {
0585 if (dir->prio == TEP_PLUGIN_FIRST)
0586 load_plugins_dir(tep, suffix, dir->path,
0587 load_plugin, data);
0588 dir = dir->next;
0589 }
0590
0591
0592
0593
0594
0595 #ifdef PLUGIN_DIR
0596 if (!tep || !(tep->flags & TEP_DISABLE_SYS_PLUGINS))
0597 load_plugins_dir(tep, suffix, PLUGIN_DIR,
0598 load_plugin, data);
0599 #endif
0600
0601
0602
0603
0604
0605 envdir = getenv("TRACEEVENT_PLUGIN_DIR");
0606 if (envdir)
0607 load_plugins_dir(tep, suffix, envdir, load_plugin, data);
0608
0609
0610
0611
0612
0613 home = getenv("HOME");
0614 if (!home)
0615 return;
0616
0617 ret = asprintf(&path, "%s/%s", home, LOCAL_PLUGIN_DIR);
0618 if (ret < 0) {
0619 warning("could not allocate plugin memory\n");
0620 return;
0621 }
0622
0623 load_plugins_dir(tep, suffix, path, load_plugin, data);
0624
0625 if (tep)
0626 dir = tep->plugins_dir;
0627 while (dir) {
0628 if (dir->prio == TEP_PLUGIN_LAST)
0629 load_plugins_dir(tep, suffix, dir->path,
0630 load_plugin, data);
0631 dir = dir->next;
0632 }
0633
0634 free(path);
0635 }
0636
0637 struct tep_plugin_list*
0638 tep_load_plugins(struct tep_handle *tep)
0639 {
0640 struct tep_plugin_list *list = NULL;
0641
0642 tep_load_plugins_hook(tep, ".so", load_plugin, &list);
0643 return list;
0644 }
0645
0646
0647
0648
0649
0650
0651
0652
0653
0654
0655 int tep_add_plugin_path(struct tep_handle *tep, char *path,
0656 enum tep_plugin_load_priority prio)
0657 {
0658 struct tep_plugins_dir *dir;
0659
0660 if (!tep || !path)
0661 return -1;
0662
0663 dir = calloc(1, sizeof(*dir));
0664 if (!dir)
0665 return -1;
0666
0667 dir->path = strdup(path);
0668 if (!dir->path) {
0669 free(dir);
0670 return -1;
0671 }
0672 dir->prio = prio;
0673 dir->next = tep->plugins_dir;
0674 tep->plugins_dir = dir;
0675
0676 return 0;
0677 }
0678
0679 __hidden void free_tep_plugin_paths(struct tep_handle *tep)
0680 {
0681 struct tep_plugins_dir *dir;
0682
0683 if (!tep)
0684 return;
0685
0686 dir = tep->plugins_dir;
0687 while (dir) {
0688 tep->plugins_dir = tep->plugins_dir->next;
0689 free(dir->path);
0690 free(dir);
0691 dir = tep->plugins_dir;
0692 }
0693 }
0694
0695 void
0696 tep_unload_plugins(struct tep_plugin_list *plugin_list, struct tep_handle *tep)
0697 {
0698 tep_plugin_unload_func func;
0699 struct tep_plugin_list *list;
0700
0701 while (plugin_list) {
0702 list = plugin_list;
0703 plugin_list = list->next;
0704 func = dlsym(list->handle, TEP_PLUGIN_UNLOADER_NAME);
0705 if (func)
0706 func(tep);
0707 dlclose(list->handle);
0708 free(list->name);
0709 free(list);
0710 }
0711 }