4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
49 #include <wsutil/filesystem.h>
50 #include <wsutil/privileges.h>
51 #include <wsutil/file_util.h>
52 #include <wsutil/report_err.h>
54 #include <wsutil/plugins.h>
56 /* linked list of all plugins */
57 typedef struct _plugin {
58 GModule *handle; /* handle returned by g_module_open */
59 gchar *name; /* plugin name */
60 gchar *version; /* plugin version */
61 guint32 types; /* bitmask of plugin types this plugin supports */
62 struct _plugin *next; /* forward link */
65 static plugin *plugin_list = NULL;
68 * Add a new plugin type.
69 * Takes a callback routine as an argument; it is called for each plugin
70 * we find, and handed a handle for the plugin, the name of the plugin,
71 * and the version string for the plugin. The plugin returns TRUE if
72 * it's a plugin for that type and FALSE if not.
76 plugin_callback callback;
80 static GSList *plugin_types = NULL;
83 add_plugin_type(const char *type, plugin_callback callback)
85 plugin_type *new_type;
86 static guint type_val;
90 * There's a bitmask of types that a plugin provides, and it's
91 * 32 bits, so we don't support types > 31.
93 report_failure("At most 32 plugin types can be supported, so the plugin type '%s' won't be supported.",
97 new_type = (plugin_type *)g_malloc(sizeof (plugin_type));
98 new_type->type = type;
99 new_type->callback = callback;
100 new_type->type_val = type_val;
101 plugin_types = g_slist_append(plugin_types, new_type);
106 * add a new plugin to the list
109 * - EEXIST : the same plugin (i.e. name/version) was already registered.
112 add_plugin(plugin *new_plug)
116 pt_plug = plugin_list;
117 if (!pt_plug) /* the list is empty */
119 plugin_list = new_plug;
125 /* check if the same name/version is already registered */
126 if (strcmp(pt_plug->name, new_plug->name) == 0 &&
127 strcmp(pt_plug->version, new_plug->version) == 0)
132 /* we found the last plugin in the list */
133 if (pt_plug->next == NULL)
136 pt_plug = pt_plug->next;
138 pt_plug->next = new_plug;
145 call_plugin_callback(gpointer data, gpointer user_data)
147 plugin_type *type = (plugin_type *)data;
148 plugin *new_plug = (plugin *)user_data;
150 if ((*type->callback)(new_plug->handle)) {
151 /* The plugin supports this type */
152 new_plug->types |= 1 << type->type_val;
157 plugins_scan_dir(const char *dirname)
159 #define FILENAME_LEN 1024
160 WS_DIR *dir; /* scanned directory */
161 WS_DIRENT *file; /* current file */
163 gchar filename[FILENAME_LEN]; /* current file name */
164 GModule *handle; /* handle returned by g_module_open */
170 if ((dir = ws_dir_open(dirname, 0, NULL)) != NULL)
172 while ((file = ws_dir_read_name(dir)) != NULL)
174 name = ws_dir_get_name(file);
177 * GLib 2.x defines G_MODULE_SUFFIX as the extension used on
178 * this platform for loadable modules.
180 /* skip anything but files with G_MODULE_SUFFIX */
181 dot = strrchr(name, '.');
182 if (dot == NULL || strcmp(dot+1, G_MODULE_SUFFIX) != 0)
185 g_snprintf(filename, FILENAME_LEN, "%s" G_DIR_SEPARATOR_S "%s",
187 if ((handle = g_module_open(filename, (GModuleFlags)0)) == NULL)
189 report_failure("Couldn't load module %s: %s", filename,
194 if (!g_module_symbol(handle, "version", &gp))
196 report_failure("The plugin %s has no version symbol", name);
197 g_module_close(handle);
201 new_plug = (plugin *)g_malloc(sizeof(plugin));
202 new_plug->handle = handle;
203 new_plug->name = g_strdup(name);
204 new_plug->version = (char *)gp;
206 new_plug->next = NULL;
209 * Hand the plugin to each of the plugin type callbacks.
211 g_slist_foreach(plugin_types, call_plugin_callback, new_plug);
214 * Does this dissector do anything useful?
216 if (new_plug->types == 0)
221 report_failure("The plugin '%s' has no registration routines",
223 g_module_close(handle);
224 g_free(new_plug->name);
230 * OK, attempt to add it to the list of plugins.
232 cr = add_plugin(new_plug);
235 g_assert(cr == EEXIST);
236 fprintf(stderr, "The plugin %s, version %s\n"
237 "was found in multiple directories\n",
238 new_plug->name, new_plug->version);
239 g_module_close(handle);
240 g_free(new_plug->name);
257 const char *plugin_dir;
259 char *plugin_dir_path;
260 char *plugins_pers_dir;
261 WS_DIR *dir; /* scanned directory */
262 WS_DIRENT *file; /* current file */
264 if (plugin_list == NULL) /* ensure scan_plugins is only run once */
267 * Scan the global plugin directory.
268 * If we're running from a build directory, scan the subdirectories
269 * of that directory, as the global plugin directory is the
270 * "plugins" directory of the source tree, and the subdirectories
271 * are the source directories for the plugins, with the plugins
272 * built in those subdirectories.
274 plugin_dir = get_plugin_dir();
275 if (running_in_build_directory())
277 if ((dir = ws_dir_open(plugin_dir, 0, NULL)) != NULL)
279 while ((file = ws_dir_read_name(dir)) != NULL)
281 name = ws_dir_get_name(file);
282 if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
283 continue; /* skip "." and ".." */
285 * Get the full path of a ".libs" subdirectory of that
288 plugin_dir_path = g_strdup_printf(
289 "%s" G_DIR_SEPARATOR_S "%s" G_DIR_SEPARATOR_S ".libs",
291 if (test_for_directory(plugin_dir_path) != EISDIR) {
293 * Either it doesn't refer to a directory or it
294 * refers to something that doesn't exist.
296 * Assume that means that the plugins are in
297 * the subdirectory of the plugin directory, not
298 * a ".libs" subdirectory of that subdirectory.
300 g_free(plugin_dir_path);
301 plugin_dir_path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
304 plugins_scan_dir(plugin_dir_path);
305 g_free(plugin_dir_path);
311 plugins_scan_dir(plugin_dir);
314 * If the program wasn't started with special privileges,
315 * scan the users plugin directory. (Even if we relinquish
316 * them, plugins aren't safe unless we've *permanently*
317 * relinquished them, and we can't do that in Wireshark as,
318 * if we need privileges to start capturing, we'd need to
319 * reclaim them before each time we start capturing.)
321 if (!started_with_special_privs())
323 plugins_pers_dir = get_plugins_pers_dir();
324 plugins_scan_dir(plugins_pers_dir);
325 g_free(plugins_pers_dir);
331 * Iterate over all plugins, calling a callback with information about
338 } type_callback_info;
341 add_plugin_type_description(gpointer data, gpointer user_data)
343 plugin_type *type = (plugin_type *)data;
344 type_callback_info *info = (type_callback_info *)user_data;
347 * If the plugin handles this type, add the type to the list of types.
349 if (info->pt_plug->types & (1 << type->type_val)) {
350 g_string_append_printf(info->types, "%s%s", info->sep, type->type);
356 plugins_get_descriptions(plugin_description_callback callback, void *user_data)
358 type_callback_info info;
360 info.types = NULL; /* FUCK LLVM UP THE ASS WITH A RED HOT POKER */
361 for (info.pt_plug = plugin_list; info.pt_plug != NULL;
362 info.pt_plug = info.pt_plug->next)
365 info.types = g_string_new("");
368 * Build a list of all the plugin types.
370 g_slist_foreach(plugin_types, add_plugin_type_description, &info);
373 * And hand the information to the callback.
375 callback(info.pt_plug->name, info.pt_plug->version, info.types->str,
376 g_module_name(info.pt_plug->handle), user_data);
378 g_string_free(info.types, TRUE);
383 print_plugin_description(const char *name, const char *version,
384 const char *description, const char *filename,
387 printf("%s\t%s\t%s\t%s\n", name, version, description, filename);
391 plugins_dump_all(void)
393 plugins_get_descriptions(print_plugin_description, NULL);
396 #endif /* HAVE_PLUGINS */
404 * indent-tabs-mode: nil
407 * ex: set shiftwidth=4 tabstop=8 expandtab:
408 * :indentSize=4:tabSize=8:noTabs=true: