6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
51 #include <wsutil/filesystem.h>
52 #include <wsutil/privileges.h>
53 #include <wsutil/file_util.h>
54 #include <wsutil/report_err.h>
56 #include <wsutil/plugins.h>
58 /* linked list of all plugins */
59 typedef struct _plugin {
60 GModule *handle; /* handle returned by g_module_open */
61 gchar *name; /* plugin name */
62 gchar *version; /* plugin version */
63 guint32 types; /* bitmask of plugin types this plugin supports */
64 struct _plugin *next; /* forward link */
67 static plugin *plugin_list = NULL;
70 * Add a new plugin type.
71 * Takes a callback routine as an argument; it is called for each plugin
72 * we find, and handed a handle for the plugin, the name of the plugin,
73 * and the version string for the plugin. The plugin returns TRUE if
74 * it's a plugin for that type and FALSE if not.
78 plugin_callback callback;
82 static GSList *plugin_types = NULL;
85 add_plugin_type(const char *type, plugin_callback callback)
87 plugin_type *new_type;
88 static guint type_val;
92 * There's a bitmask of types that a plugin provides, and it's
93 * 32 bits, so we don't support types > 31.
95 report_failure("At most 32 plugin types can be supported, so the plugin type '%s' won't be supported.",
99 new_type = (plugin_type *)g_malloc(sizeof (plugin_type));
100 new_type->type = type;
101 new_type->callback = callback;
102 new_type->type_val = type_val;
103 plugin_types = g_slist_append(plugin_types, new_type);
108 * add a new plugin to the list
111 * - ENOMEM : memory allocation problem
112 * - EEXIST : the same plugin (i.e. name/version) was already registered.
115 add_plugin(plugin *new_plug)
119 pt_plug = plugin_list;
120 if (!pt_plug) /* the list is empty */
122 plugin_list = new_plug;
128 /* check if the same name/version is already registered */
129 if (strcmp(pt_plug->name, new_plug->name) == 0 &&
130 strcmp(pt_plug->version, new_plug->version) == 0)
135 /* we found the last plugin in the list */
136 if (pt_plug->next == NULL)
139 pt_plug = pt_plug->next;
141 pt_plug->next = new_plug;
148 call_plugin_callback(gpointer data, gpointer user_data)
150 plugin_type *type = (plugin_type *)data;
151 plugin *new_plug = (plugin *)user_data;
153 if ((*type->callback)(new_plug->handle)) {
154 /* The plugin supports this type */
155 new_plug->types |= 1 << type->type_val;
160 plugins_scan_dir(const char *dirname)
162 #define FILENAME_LEN 1024
163 WS_DIR *dir; /* scanned directory */
164 WS_DIRENT *file; /* current file */
166 gchar filename[FILENAME_LEN]; /* current file name */
167 GModule *handle; /* handle returned by g_module_open */
173 if ((dir = ws_dir_open(dirname, 0, NULL)) != NULL)
175 while ((file = ws_dir_read_name(dir)) != NULL)
177 name = ws_dir_get_name(file);
180 * GLib 2.x defines G_MODULE_SUFFIX as the extension used on
181 * this platform for loadable modules.
183 /* skip anything but files with G_MODULE_SUFFIX */
184 dot = strrchr(name, '.');
185 if (dot == NULL || strcmp(dot+1, G_MODULE_SUFFIX) != 0)
188 g_snprintf(filename, FILENAME_LEN, "%s" G_DIR_SEPARATOR_S "%s",
190 if ((handle = g_module_open(filename, (GModuleFlags)0)) == NULL)
192 report_failure("Couldn't load module %s: %s", filename,
197 if (!g_module_symbol(handle, "version", &gp))
199 report_failure("The plugin %s has no version symbol", name);
200 g_module_close(handle);
204 new_plug = (plugin *)g_malloc(sizeof(plugin));
205 new_plug->handle = handle;
206 new_plug->name = g_strdup(name);
207 new_plug->version = (char *)gp;
209 new_plug->next = NULL;
212 * Hand the plugin to each of the plugin type callbacks.
214 g_slist_foreach(plugin_types, call_plugin_callback, new_plug);
217 * Does this dissector do anything useful?
219 if (new_plug->types == 0)
224 report_failure("The plugin '%s' has no registration routines",
226 g_module_close(handle);
227 g_free(new_plug->name);
233 * OK, attempt to add it to the list of plugins.
235 if ((cr = add_plugin(new_plug)))
238 fprintf(stderr, "The plugin %s, version %s\n"
239 "was found in multiple directories\n",
240 new_plug->name, new_plug->version);
242 fprintf(stderr, "Memory allocation problem\n"
243 "when processing plugin %s, version %s\n",
244 new_plug->name, new_plug->version);
245 g_module_close(handle);
246 g_free(new_plug->name);
263 const char *plugin_dir;
265 char *plugin_dir_path;
266 char *plugins_pers_dir;
267 WS_DIR *dir; /* scanned directory */
268 WS_DIRENT *file; /* current file */
270 if (plugin_list == NULL) /* ensure scan_plugins is only run once */
273 * Scan the global plugin directory.
274 * If we're running from a build directory, scan the subdirectories
275 * of that directory, as the global plugin directory is the
276 * "plugins" directory of the source tree, and the subdirectories
277 * are the source directories for the plugins, with the plugins
278 * built in those subdirectories.
280 plugin_dir = get_plugin_dir();
281 if (running_in_build_directory())
283 if ((dir = ws_dir_open(plugin_dir, 0, NULL)) != NULL)
285 while ((file = ws_dir_read_name(dir)) != NULL)
287 name = ws_dir_get_name(file);
288 if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
289 continue; /* skip "." and ".." */
291 * Get the full path of a ".libs" subdirectory of that
294 plugin_dir_path = g_strdup_printf(
295 "%s" G_DIR_SEPARATOR_S "%s" G_DIR_SEPARATOR_S ".libs",
297 if (test_for_directory(plugin_dir_path) != EISDIR) {
299 * Either it doesn't refer to a directory or it
300 * refers to something that doesn't exist.
302 * Assume that means that the plugins are in
303 * the subdirectory of the plugin directory, not
304 * a ".libs" subdirectory of that subdirectory.
306 g_free(plugin_dir_path);
307 plugin_dir_path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
310 plugins_scan_dir(plugin_dir_path);
311 g_free(plugin_dir_path);
317 plugins_scan_dir(plugin_dir);
320 * If the program wasn't started with special privileges,
321 * scan the users plugin directory. (Even if we relinquish
322 * them, plugins aren't safe unless we've *permanently*
323 * relinquished them, and we can't do that in Wireshark as,
324 * if we need privileges to start capturing, we'd need to
325 * reclaim them before each time we start capturing.)
327 if (!started_with_special_privs())
329 plugins_pers_dir = get_plugins_pers_dir();
330 plugins_scan_dir(plugins_pers_dir);
331 g_free(plugins_pers_dir);
337 * Iterate over all plugins, calling a callback with information about
344 } type_callback_info;
347 add_plugin_type_description(gpointer data, gpointer user_data)
349 plugin_type *type = (plugin_type *)data;
350 type_callback_info *info = (type_callback_info *)user_data;
353 * If the plugin handles this type, add the type to the list of types.
355 if (info->pt_plug->types & (1 << type->type_val)) {
356 g_string_append_printf(info->types, "%s%s", info->sep, type->type);
362 plugins_get_descriptions(plugin_description_callback callback, void *user_data)
364 type_callback_info info;
366 info.types = NULL; /* FUCK LLVM UP THE ASS WITH A RED HOT POKER */
367 for (info.pt_plug = plugin_list; info.pt_plug != NULL;
368 info.pt_plug = info.pt_plug->next)
371 info.types = g_string_new("");
374 * Build a list of all the plugin types.
376 g_slist_foreach(plugin_types, add_plugin_type_description, &info);
379 * And hand the information to the callback.
381 callback(info.pt_plug->name, info.pt_plug->version, info.types->str,
382 g_module_name(info.pt_plug->handle), user_data);
384 g_string_free(info.types, TRUE);
389 print_plugin_description(const char *name, const char *version,
390 const char *description, const char *filename,
393 printf("%s\t%s\t%s\t%s\n", name, version, description, filename);
397 plugins_dump_all(void)
399 plugins_get_descriptions(print_plugin_description, NULL);
402 #endif /* HAVE_PLUGINS */
410 * indent-tabs-mode: nil
413 * ex: set shiftwidth=4 tabstop=8 expandtab:
414 * :indentSize=4:tabSize=8:noTabs=true: