4 * $Id: plugins.c,v 1.5 2000/01/15 00:22:34 gram Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@zing.org>
8 * Copyright 1999 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
47 #include <sys/types.h>
60 /* linked list of all plugins */
63 static gchar std_plug_dir[] = "/usr/lib/ethereal/plugins/0.8";
64 static gchar local_plug_dir[] = "/usr/local/lib/ethereal/plugins/0.8";
65 static gchar *user_plug_dir = NULL;
66 static gchar *plugin_status_file = NULL;
69 * add a new plugin to the list
72 * - ENOMEM : memory allocation problem
73 * - EEXIST : the same plugin (i.e. name/version) was already registered.
76 add_plugin(void *handle, gchar *name, gchar *version, gchar *protocol,
77 gchar *filter_string, dfilter *filter,
78 void (*dissector) (const u_char *,
83 plugin *new_plug, *pt_plug;
85 pt_plug = plugin_list;
86 if (!pt_plug) /* the list is empty */
88 new_plug = (plugin *)g_malloc(sizeof(plugin));
89 if (new_plug == NULL) return ENOMEM;
90 plugin_list = new_plug;
96 /* check if the same name/version is already registered */
97 if (!strcmp(pt_plug->name, name) &&
98 !strcmp(pt_plug->version, version))
103 /* we found the last plugin in the list */
104 if (pt_plug->next == NULL) break;
106 pt_plug = pt_plug->next;
108 new_plug = (plugin *)g_malloc(sizeof(plugin));
109 if (new_plug == NULL) return ENOMEM;
110 pt_plug->next = new_plug;
113 new_plug->handle = handle;
114 new_plug->name = name;
115 new_plug->version = version;
116 new_plug->enabled = FALSE;
117 new_plug->protocol = protocol;
118 new_plug->filter_string = g_strdup(filter_string);
119 new_plug->filter = filter;
120 new_plug->dissector = dissector;
121 new_plug->next = NULL;
127 * returns a pointer to the enabled plugin, or NULL if the plugin wasn't found
131 enable_plugin(const gchar *name, const gchar *version)
135 pt_plug = plugin_list;
138 if (!strcmp(pt_plug->name, name) && !strcmp(pt_plug->version, version))
140 pt_plug->enabled = TRUE;
143 pt_plug = pt_plug->next;
150 * returns a pointer to the disabled plugin, or NULL if the plugin wasn't found
154 disable_plugin(const gchar *name, const gchar *version)
158 pt_plug = plugin_list;
161 if (!strcmp(pt_plug->name, name) && !strcmp(pt_plug->version, version))
163 pt_plug->enabled = FALSE;
166 pt_plug = pt_plug->next;
172 * find a plugin using its name/version
175 find_plugin(const gchar *name, const gchar *version)
179 pt_plug = plugin_list;
182 if (!strcmp(pt_plug->name, name) && !strcmp(pt_plug->version, version))
186 pt_plug = pt_plug->next;
192 * check if a plugin is enabled
195 is_enabled(const gchar *name, const gchar *version)
199 pt_plug = plugin_list;
202 if (!strcmp(pt_plug->name, name) && !strcmp(pt_plug->version, version))
203 return pt_plug->enabled;
204 pt_plug = pt_plug->next;
210 * replace the filter used by a plugin (filter string and dfilter)
213 plugin_replace_filter(const gchar *name, const gchar *version,
214 const gchar *filter_string, dfilter *filter)
218 pt_plug = plugin_list;
221 if (!strcmp(pt_plug->name, name) && !strcmp(pt_plug->version, version))
223 g_free(pt_plug->filter_string);
224 pt_plug->filter_string = g_strdup(filter_string);
225 dfilter_destroy(pt_plug->filter);
226 pt_plug->filter = filter;
229 pt_plug = pt_plug->next;
234 * save plugin status, returns 0 on success, -1 on failure:
236 * for each plugin, two lines are saved :
237 * plugin_name plugin_version [0|1] (0: disabled, 1: enabled)
251 if (!plugin_status_file) {
252 plugin_status_file = (gchar *)g_malloc(strlen(getenv("HOME")) + 26);
253 sprintf(plugin_status_file, "%s/%s/plugins.status", getenv("HOME"), PF_DIR);
255 statusfile=fopen(plugin_status_file, "w");
257 pf_path = g_malloc(strlen(getenv("HOME")) + strlen(PF_DIR) + 2);
258 sprintf(pf_path, "%s/%s", getenv("HOME"), PF_DIR);
262 mkdir(pf_path, 0755);
265 statusfile=fopen(plugin_status_file, "w");
266 if (!statusfile) return -1;
269 pt_plug = plugin_list;
272 fprintf(statusfile,"%s %s %s\n%s\n", pt_plug->name, pt_plug->version,
273 (pt_plug->enabled ? "1" : "0"), pt_plug->filter_string);
274 pt_plug = pt_plug->next;
281 * Check if the status of this plugin has been saved.
282 * If necessary, enable the plugin, and change the filter.
285 check_plugin_status(gchar *name, gchar *version, GModule *handle,
286 gchar *filter_string, FILE *statusfile)
289 guint16 ref_string_len;
291 void (*proto_init)();
294 if (!statusfile) return;
296 ref_string = (gchar *)g_malloc(strlen(name) + strlen(version) + 2);
297 ref_string_len = sprintf(ref_string, "%s %s", name, version);
299 while (!feof(statusfile))
301 if (fgets(line, 512, statusfile) == NULL) return;
302 if (strncmp(line, ref_string, ref_string_len) != 0) { /* not the right plugin */
303 if (fgets(line, 512, statusfile) == NULL) return;
305 else { /* found the plugin */
306 if (line[ref_string_len+1] == '1') {
307 enable_plugin(name, version);
308 if (g_module_symbol(handle, "proto_init", (gpointer*)&proto_init) == TRUE) {
313 if (fgets(line, 512, statusfile) == NULL) return;
314 if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0';
315 /* only compile the new filter if it is different from the default */
316 if (strcmp(line, filter_string) && dfilter_compile(line, &filter) == 0)
317 plugin_replace_filter(name, version, line, filter);
325 plugins_scan_dir(const char *dirname)
327 DIR *dir; /* scanned directory */
328 struct dirent *file; /* current file */
329 gchar filename[512]; /* current file name */
330 GModule *handle; /* handle returned by dlopen */
334 gchar *filter_string;
336 dfilter *filter = NULL;
337 void (*dissector) (const u_char *, int, frame_data *, proto_tree *);
342 #define LT_LIB_EXT ".dll"
344 #define LT_LIB_EXT ".la"
347 if (!plugin_status_file)
349 plugin_status_file = (gchar *)g_malloc(strlen(getenv("HOME")) + 26);
350 sprintf(plugin_status_file, "%s/%s/plugins.status", getenv("HOME"), PF_DIR);
352 statusfile = fopen(plugin_status_file, "r");
354 if ((dir = opendir(dirname)) != NULL)
356 while ((file = readdir(dir)) != NULL)
358 /* don't try to open "." and ".." */
359 if (!(strcmp(file->d_name, "..") &&
360 strcmp(file->d_name, "."))) continue;
362 /* skip anything but .la */
363 dot = strrchr(file->d_name, '.');
364 if (dot == NULL || ! strcmp(dot, LT_LIB_EXT)) continue;
366 sprintf(filename, "%s/%s", dirname, file->d_name);
368 if ((handle = g_module_open(filename, 0)) == NULL) continue;
369 name = (gchar *)file->d_name;
370 if (g_module_symbol(handle, "version", (gpointer*)&version) == FALSE)
372 g_module_close(handle);
375 if (g_module_symbol(handle, "protocol", (gpointer*)&protocol) == FALSE)
377 g_module_close(handle);
380 if (g_module_symbol(handle, "filter_string", (gpointer*)&filter_string) == FALSE)
382 g_module_close(handle);
385 if (dfilter_compile(filter_string, &filter) != 0) {
386 g_module_close(handle);
389 if (g_module_symbol(handle, "dissector", (gpointer*)&dissector) == FALSE) {
391 dfilter_destroy(filter);
392 g_module_close(handle);
396 if ((cr = add_plugin(handle, g_strdup(file->d_name), version,
397 protocol, filter_string, filter, dissector)))
400 fprintf(stderr, "The plugin : %s, version %s\n"
401 "was found in multiple directories\n", name, version);
403 fprintf(stderr, "Memory allocation problem\n"
404 "when processing plugin %s, version %sn",
407 dfilter_destroy(filter);
408 g_module_close(handle);
412 check_plugin_status(file->d_name, version, handle,
413 filter_string, statusfile);
419 if (statusfile) fclose(statusfile);
428 if (plugin_list == NULL) /* ensure init_plugins is only run once */
430 plugins_scan_dir(std_plug_dir);
431 plugins_scan_dir(local_plug_dir);
432 if ((strcmp(std_plug_dir, PLUGIN_DIR) != 0) &&
433 (strcmp(local_plug_dir, PLUGIN_DIR) != 0))
435 plugins_scan_dir(PLUGIN_DIR);
439 user_plug_dir = (gchar *)g_malloc(strlen(getenv("HOME")) + 19);
440 sprintf(user_plug_dir, "%s/%s/plugins", getenv("HOME"), PF_DIR);
442 plugins_scan_dir(user_plug_dir);