Loading...
Note: File does not exist in v6.13.7.
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}