diff options
Diffstat (limited to 'tools/lib/traceevent/event-plugin.c')
-rw-r--r-- | tools/lib/traceevent/event-plugin.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c new file mode 100644 index 000000000000..0c8bf6780e4d --- /dev/null +++ b/tools/lib/traceevent/event-plugin.c | |||
@@ -0,0 +1,215 @@ | |||
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 | |||
33 | struct plugin_list { | ||
34 | struct plugin_list *next; | ||
35 | char *name; | ||
36 | void *handle; | ||
37 | }; | ||
38 | |||
39 | static void | ||
40 | load_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 | |||
97 | static void | ||
98 | load_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 | |||
139 | static void | ||
140 | load_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 | |||
190 | struct plugin_list* | ||
191 | traceevent_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 | |||
199 | void | ||
200 | traceevent_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 | } | ||