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.
37 #include <wsutil/filesystem.h>
38 #include <wsutil/privileges.h>
39 #include <wsutil/file_util.h>
40 #include <wsutil/report_message.h>
42 #include <wsutil/plugins.h>
43 #include <wsutil/ws_printf.h> /* ws_debug_printf */
45 /* linked list of all plugins */
46 typedef struct _plugin {
47 GModule *handle; /* handle returned by g_module_open */
48 gchar *name; /* plugin name */
49 gchar *version; /* plugin version */
50 guint32 types; /* bitmask of plugin types this plugin supports */
51 struct _plugin *next; /* forward link */
54 static plugin *plugin_list = NULL;
57 * Add a new plugin type.
58 * Takes a callback routine as an argument; it is called for each plugin
59 * we find, and handed a handle for the plugin, the name of the plugin,
60 * and the version string for the plugin. The plugin returns TRUE if
61 * it's a plugin for that type and FALSE if not.
65 plugin_check_type_callback callback;
69 static GSList *plugin_types = NULL;
72 add_plugin_type(const char *type, plugin_check_type_callback callback)
74 plugin_type *new_type;
75 static guint type_val;
79 * There's a bitmask of types that a plugin provides, and it's
80 * 32 bits, so we don't support types > 31.
82 report_failure("At most 32 plugin types can be supported, so the plugin type '%s' won't be supported.",
86 new_type = (plugin_type *)g_malloc(sizeof (plugin_type));
87 new_type->type = type;
88 new_type->callback = callback;
89 new_type->type_val = type_val;
90 plugin_types = g_slist_append(plugin_types, new_type);
95 * add a new plugin to the list
98 add_plugin(plugin *new_plug)
102 pt_plug = plugin_list;
103 if (!pt_plug) /* the list is empty */
105 plugin_list = new_plug;
111 /* we found the last plugin in the list */
112 if (pt_plug->next == NULL)
115 pt_plug = pt_plug->next;
117 pt_plug->next = new_plug;
122 check_if_plugin_exists(const char *name)
124 for (plugin *p = plugin_list; p != NULL; p = p->next) {
125 if (strcmp(p->name, name) == 0) {
133 call_plugin_callback(gpointer data, gpointer user_data)
135 plugin_type *type = (plugin_type *)data;
136 plugin *new_plug = (plugin *)user_data;
138 if ((*type->callback)(new_plug->handle)) {
139 /* The plugin supports this type */
140 new_plug->types |= 1 << type->type_val;
145 plugins_scan_dir(const char *dirname, plugin_load_failure_mode mode)
147 #define FILENAME_LEN 1024
148 WS_DIR *dir; /* scanned directory */
149 WS_DIRENT *file; /* current file */
151 gchar filename[FILENAME_LEN]; /* current file name */
152 GModule *handle; /* handle returned by g_module_open */
157 if (!g_file_test(dirname, G_FILE_TEST_EXISTS) || !g_file_test(dirname, G_FILE_TEST_IS_DIR)) {
161 if ((dir = ws_dir_open(dirname, 0, NULL)) != NULL)
163 while ((file = ws_dir_read_name(dir)) != NULL)
165 name = ws_dir_get_name(file);
168 * GLib 2.x defines G_MODULE_SUFFIX as the extension used on
169 * this platform for loadable modules.
171 /* skip anything but files with G_MODULE_SUFFIX */
172 dot = strrchr(name, '.');
173 if (dot == NULL || strcmp(dot+1, G_MODULE_SUFFIX) != 0)
176 if (strncmp(name, "nordic_ble.dll", 14) == 0)
178 * Skip the Nordic BLE Sniffer dll on WIN32 because
179 * the dissector has been added as internal.
183 g_snprintf(filename, FILENAME_LEN, "%s" G_DIR_SEPARATOR_S "%s",
187 * Check if the same name is already registered.
189 if (check_if_plugin_exists(name)) {
191 if (mode == REPORT_LOAD_FAILURE) {
192 report_warning("The plugin '%s' was found "
193 "in multiple directories.\n", name);
198 if ((handle = g_module_open(filename, G_MODULE_BIND_LOCAL)) == NULL)
201 * Only report load failures if we were asked to.
203 * XXX - we really should put different types of plugins
204 * (libwiretap, libwireshark) in different subdirectories,
205 * give libwiretap and libwireshark init routines that
206 * load the plugins, and have them scan the appropriate
207 * subdirectories so tha we don't even *try* to, for
208 * example, load libwireshark plugins in programs that
209 * only use libwiretap.
211 if (mode == REPORT_LOAD_FAILURE) {
212 report_failure("Couldn't load module %s: %s", filename,
218 if (!g_module_symbol(handle, "version", &gp))
220 report_failure("The plugin %s has no version symbol", name);
221 g_module_close(handle);
225 new_plug = (plugin *)g_malloc(sizeof(plugin));
226 new_plug->handle = handle;
227 new_plug->name = g_strdup(name);
228 new_plug->version = (char *)gp;
230 new_plug->next = NULL;
233 * Hand the plugin to each of the plugin type callbacks.
235 g_slist_foreach(plugin_types, call_plugin_callback, new_plug);
238 * Does this dissector do anything useful?
240 if (new_plug->types == 0)
245 * Only report this failure if we were asked to; it might
246 * just mean that it's a plugin type that this program
247 * doesn't support, such as a libwireshark plugin in
248 * a program that doesn't use libwireshark.
250 * XXX - we really should put different types of plugins
251 * (libwiretap, libwireshark) in different subdirectories,
252 * give libwiretap and libwireshark init routines that
253 * load the plugins, and have them scan the appropriate
254 * subdirectories so tha we don't even *try* to, for
255 * example, load libwireshark plugins in programs that
256 * only use libwiretap.
258 if (mode == REPORT_LOAD_FAILURE) {
259 report_failure("The plugin '%s' has no registration routines",
262 g_module_close(handle);
263 g_free(new_plug->name);
269 * OK, add it to the list of plugins.
271 add_plugin(new_plug);
282 scan_plugins(plugin_load_failure_mode mode)
284 const char *plugin_dir;
286 char *plugin_dir_path;
287 WS_DIR *dir; /* scanned directory */
288 WS_DIRENT *file; /* current file */
290 if (plugin_list == NULL) /* only scan for plugins once */
293 * Scan the global plugin directory.
294 * If we're running from a build directory, scan the "plugins"
295 * subdirectory, as that's where plugins are located in an
296 * out-of-tree build. If we find subdirectories scan those since
297 * they will contain plugins in the case of an in-tree build.
299 plugin_dir = get_plugins_dir();
300 if (plugin_dir == NULL)
302 /* We couldn't find the plugin directory. */
305 if (running_in_build_directory())
307 if ((dir = ws_dir_open(plugin_dir, 0, NULL)) != NULL)
309 plugins_scan_dir(plugin_dir, mode);
310 while ((file = ws_dir_read_name(dir)) != NULL)
312 name = ws_dir_get_name(file);
313 if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
314 continue; /* skip "." and ".." */
316 * Get the full path of a ".libs" subdirectory of that
319 plugin_dir_path = g_strdup_printf(
320 "%s" G_DIR_SEPARATOR_S "%s" G_DIR_SEPARATOR_S ".libs",
322 if (test_for_directory(plugin_dir_path) != EISDIR) {
324 * Either it doesn't refer to a directory or it
325 * refers to something that doesn't exist.
327 * Assume that means that the plugins are in
328 * the subdirectory of the plugin directory, not
329 * a ".libs" subdirectory of that subdirectory.
331 g_free(plugin_dir_path);
332 plugin_dir_path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
335 plugins_scan_dir(plugin_dir_path, mode);
336 g_free(plugin_dir_path);
343 plugins_scan_dir(get_plugins_dir_with_version(), mode);
347 * If the program wasn't started with special privileges,
348 * scan the users plugin directory. (Even if we relinquish
349 * them, plugins aren't safe unless we've *permanently*
350 * relinquished them, and we can't do that in Wireshark as,
351 * if we need privileges to start capturing, we'd need to
352 * reclaim them before each time we start capturing.)
354 if (!started_with_special_privs())
356 plugins_scan_dir(get_plugins_pers_dir_with_version(), mode);
362 * Iterate over all plugins, calling a callback with information about
369 } type_callback_info;
372 add_plugin_type_description(gpointer data, gpointer user_data)
374 plugin_type *type = (plugin_type *)data;
375 type_callback_info *info = (type_callback_info *)user_data;
378 * If the plugin handles this type, add the type to the list of types.
380 if (info->pt_plug->types & (1 << type->type_val)) {
381 g_string_append_printf(info->types, "%s%s", info->sep, type->type);
387 plugins_get_descriptions(plugin_description_callback callback, void *user_data)
389 type_callback_info info;
391 info.types = NULL; /* Certain compiler suites need a init state for this variable */
392 for (info.pt_plug = plugin_list; info.pt_plug != NULL;
393 info.pt_plug = info.pt_plug->next)
396 info.types = g_string_new("");
399 * Build a list of all the plugin types.
401 g_slist_foreach(plugin_types, add_plugin_type_description, &info);
404 * And hand the information to the callback.
406 callback(info.pt_plug->name, info.pt_plug->version, info.types->str,
407 g_module_name(info.pt_plug->handle), user_data);
409 g_string_free(info.types, TRUE);
414 print_plugin_description(const char *name, const char *version,
415 const char *description, const char *filename,
418 ws_debug_printf("%s\t%s\t%s\t%s\n", name, version, description, filename);
422 plugins_dump_all(void)
424 plugins_get_descriptions(print_plugin_description, NULL);
428 free_plugin_type(gpointer p, gpointer user_data _U_)
434 plugins_cleanup(void)
438 for (cur = plugin_list; cur != NULL; cur = next) {
444 g_slist_foreach(plugin_types, free_plugin_type, NULL);
445 g_slist_free(plugin_types);
448 #endif /* HAVE_PLUGINS */
456 * indent-tabs-mode: nil
459 * ex: set shiftwidth=4 tabstop=8 expandtab:
460 * :indentSize=4:tabSize=8:noTabs=true: