at v3.15-rc4 215 lines 4.8 kB view raw
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 <string.h> 22#include <dlfcn.h> 23#include <stdlib.h> 24#include <sys/types.h> 25#include <sys/stat.h> 26#include <unistd.h> 27#include <dirent.h> 28#include "event-parse.h" 29#include "event-utils.h" 30 31#define LOCAL_PLUGIN_DIR ".traceevent/plugins" 32 33struct plugin_list { 34 struct plugin_list *next; 35 char *name; 36 void *handle; 37}; 38 39static void 40load_plugin(struct pevent *pevent, const char *path, 41 const char *file, void *data) 42{ 43 struct plugin_list **plugin_list = data; 44 pevent_plugin_load_func func; 45 struct plugin_list *list; 46 const char *alias; 47 char *plugin; 48 void *handle; 49 50 plugin = malloc(strlen(path) + strlen(file) + 2); 51 if (!plugin) { 52 warning("could not allocate plugin memory\n"); 53 return; 54 } 55 56 strcpy(plugin, path); 57 strcat(plugin, "/"); 58 strcat(plugin, file); 59 60 handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL); 61 if (!handle) { 62 warning("could not load plugin '%s'\n%s\n", 63 plugin, dlerror()); 64 goto out_free; 65 } 66 67 alias = dlsym(handle, PEVENT_PLUGIN_ALIAS_NAME); 68 if (!alias) 69 alias = file; 70 71 func = dlsym(handle, PEVENT_PLUGIN_LOADER_NAME); 72 if (!func) { 73 warning("could not find func '%s' in plugin '%s'\n%s\n", 74 PEVENT_PLUGIN_LOADER_NAME, plugin, dlerror()); 75 goto out_free; 76 } 77 78 list = malloc(sizeof(*list)); 79 if (!list) { 80 warning("could not allocate plugin memory\n"); 81 goto out_free; 82 } 83 84 list->next = *plugin_list; 85 list->handle = handle; 86 list->name = plugin; 87 *plugin_list = list; 88 89 pr_stat("registering plugin: %s", plugin); 90 func(pevent); 91 return; 92 93 out_free: 94 free(plugin); 95} 96 97static void 98load_plugins_dir(struct pevent *pevent, const char *suffix, 99 const char *path, 100 void (*load_plugin)(struct pevent *pevent, 101 const char *path, 102 const char *name, 103 void *data), 104 void *data) 105{ 106 struct dirent *dent; 107 struct stat st; 108 DIR *dir; 109 int ret; 110 111 ret = stat(path, &st); 112 if (ret < 0) 113 return; 114 115 if (!S_ISDIR(st.st_mode)) 116 return; 117 118 dir = opendir(path); 119 if (!dir) 120 return; 121 122 while ((dent = readdir(dir))) { 123 const char *name = dent->d_name; 124 125 if (strcmp(name, ".") == 0 || 126 strcmp(name, "..") == 0) 127 continue; 128 129 /* Only load plugins that end in suffix */ 130 if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0) 131 continue; 132 133 load_plugin(pevent, path, name, data); 134 } 135 136 closedir(dir); 137} 138 139static void 140load_plugins(struct pevent *pevent, const char *suffix, 141 void (*load_plugin)(struct pevent *pevent, 142 const char *path, 143 const char *name, 144 void *data), 145 void *data) 146{ 147 char *home; 148 char *path; 149 char *envdir; 150 151 /* 152 * If a system plugin directory was defined, 153 * check that first. 154 */ 155#ifdef PLUGIN_DIR 156 load_plugins_dir(pevent, suffix, PLUGIN_DIR, load_plugin, data); 157#endif 158 159 /* 160 * Next let the environment-set plugin directory 161 * override the system defaults. 162 */ 163 envdir = getenv("TRACEEVENT_PLUGIN_DIR"); 164 if (envdir) 165 load_plugins_dir(pevent, suffix, envdir, load_plugin, data); 166 167 /* 168 * Now let the home directory override the environment 169 * or system defaults. 170 */ 171 home = getenv("HOME"); 172 if (!home) 173 return; 174 175 path = malloc(strlen(home) + strlen(LOCAL_PLUGIN_DIR) + 2); 176 if (!path) { 177 warning("could not allocate plugin memory\n"); 178 return; 179 } 180 181 strcpy(path, home); 182 strcat(path, "/"); 183 strcat(path, LOCAL_PLUGIN_DIR); 184 185 load_plugins_dir(pevent, suffix, path, load_plugin, data); 186 187 free(path); 188} 189 190struct plugin_list* 191traceevent_load_plugins(struct pevent *pevent) 192{ 193 struct plugin_list *list = NULL; 194 195 load_plugins(pevent, ".so", load_plugin, &list); 196 return list; 197} 198 199void 200traceevent_unload_plugins(struct plugin_list *plugin_list, struct pevent *pevent) 201{ 202 pevent_plugin_unload_func func; 203 struct plugin_list *list; 204 205 while (plugin_list) { 206 list = plugin_list; 207 plugin_list = list->next; 208 func = dlsym(list->handle, PEVENT_PLUGIN_UNLOADER_NAME); 209 if (func) 210 func(pevent); 211 dlclose(list->handle); 212 free(list->name); 213 free(list); 214 } 215}