Merge tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb...
[platform/adaptation/renesas_rcar/renesas_kernel.git] / tools / lib / traceevent / event-plugin.c
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 }