diff options
Diffstat (limited to 'filters.c')
-rw-r--r-- | filters.c | 298 |
1 files changed, 261 insertions, 37 deletions
@@ -1,7 +1,7 @@ /* filters.c * Code for reading and writing the filters file. * - * $Id: filters.c,v 1.2 2001/01/28 04:52:28 guy Exp $ + * $Id: filters.c,v 1.3 2001/01/28 09:13:07 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@zing.org> @@ -30,6 +30,7 @@ #include <stdio.h> #include <string.h> #include <ctype.h> +#include <errno.h> #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> @@ -46,44 +47,125 @@ #include "filters.h" #include "util.h" +/* + * Old filter file name. + */ +#define FILTER_FILE_NAME "filters" + +/* + * Capture filter file name. + */ +#define CFILTER_FILE_NAME "cfilters" + +/* + * Display filter file name. + */ +#define DFILTER_FILE_NAME "dfilters" + #define FILTER_LINE_SIZE 2048 /* - * List of filters. + * List of capture filters. + */ +static GList *capture_filters = NULL; + +/* + * List of display filters. */ -GList *fl = NULL; +static GList *display_filters = NULL; +/* + * Read in a list of filters. + * + * On success, "*pref_path_return" is set to NULL. + * On error, "*pref_path_return" is set to point to the pathname of + * the file we tried to read - it should be freed by our caller - + * and "*errno_return" is set to the error. + */ void -get_filter_list(void) +read_filter_list(filter_list_type_t list, char **pref_path_return, + int *errno_return) { - GList *flp; - filter_def *filt; + char *ff_path, *ff_dir = PF_DIR, *ff_name; FILE *ff; - gchar *ff_path, *ff_name = PF_DIR "/filters", f_buf[FILTER_LINE_SIZE]; - gchar *name_begin, *name_end, *filt_begin; + GList **flp; + GList *fl_ent; + filter_def *filt; + char f_buf[FILTER_LINE_SIZE]; + char *name_begin, *name_end, *filt_begin; int len, line = 0; - /* If we already have a list of filters, discard it. */ - if (fl != NULL) { - flp = g_list_first(fl); - while (flp) { - filt = (filter_def *) flp->data; - g_free(filt->name); - g_free(filt->strval); - g_free(filt); - flp = flp->next; - } - g_list_free(fl); - fl = NULL; + *pref_path_return = NULL; /* assume no error */ + + switch (list) { + + case CFILTER_LIST: + ff_name = CFILTER_FILE_NAME; + flp = &capture_filters; + break; + + case DFILTER_LIST: + ff_name = DFILTER_FILE_NAME; + flp = &display_filters; + break; + + default: + g_assert_not_reached(); + return; } /* To do: generalize this */ - ff_path = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(ff_name) + 4); - sprintf(ff_path, "%s/%s", get_home_dir(), ff_name); + ff_path = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(ff_dir) + + strlen(ff_name) + 4); + sprintf(ff_path, "%s/%s/%s", get_home_dir(), ff_dir, ff_name); if ((ff = fopen(ff_path, "r")) == NULL) { - g_free(ff_path); - return; + /* + * Did that fail because we the file didn't exist? + */ + if (errno != ENOENT) { + /* + * No. Just give up. + */ + *pref_path_return = ff_path; + *errno_return = errno; + return; + } + + /* + * Yes. See if there's a "filters" file; if so, read it. + * This means that a user will start out with their capture and + * display filter lists being identical; each list may contain + * filters that don't belong in that list. The user can edit + * the filter lists, and delete the ones that don't belong in + * a particular list. + */ + sprintf(ff_path, "%s/%s/%s", get_home_dir(), ff_dir, FILTER_FILE_NAME); + if ((ff = fopen(ff_path, "r")) == NULL) { + /* + * Well, that didn't work, either. Just give up. + * Return an error if the file existed but we couldn't open it. + */ + if (errno != ENOENT) { + *pref_path_return = ff_path; + *errno_return = errno; + } + return; + } + } + + /* If we already have a list of filters, discard it. */ + if (*flp != NULL) { + fl_ent = g_list_first(*flp); + while (fl_ent != NULL) { + filt = (filter_def *) fl_ent->data; + g_free(filt->name); + g_free(filt->strval); + g_free(filt); + fl_ent = fl_ent->next; + } + g_list_free(*flp); + *flp = NULL; } while (fgets(f_buf, FILTER_LINE_SIZE, ff)) { @@ -115,23 +197,130 @@ get_filter_list(void) filt = (filter_def *) g_malloc(sizeof(filter_def)); filt->name = g_strdup(name_begin); filt->strval = g_strdup(filt_begin); - fl = g_list_append(fl, filt); + *flp = g_list_append(*flp, filt); } + if (ferror(ff)) { + *pref_path_return = ff_path; + *errno_return = errno; + } else + g_free(ff_path); fclose(ff); - g_free(ff_path); } +/* + * Get a pointer to a list of filters. + */ +static GList ** +get_filter_list(filter_list_type_t list) +{ + GList **flp; + + switch (list) { + + case CFILTER_LIST: + flp = &capture_filters; + break; + + case DFILTER_LIST: + flp = &display_filters; + break; + + default: + g_assert_not_reached(); + flp = NULL; + } + return flp; +} + +/* + * Get a pointer to the first entry in a filter list. + */ +GList * +get_filter_list_first(filter_list_type_t list) +{ + GList **flp; + + flp = get_filter_list(list); + return g_list_first(*flp); +} + +/* + * Add a new filter to the end of a list. + * Returns a pointer to the newly-added entry. + */ +GList * +add_to_filter_list(filter_list_type_t list, char *name, char *expression) +{ + GList **flp; + filter_def *filt; + + flp = get_filter_list(list); + filt = (filter_def *) g_malloc(sizeof(filter_def)); + filt->name = g_strdup(name); + filt->strval = g_strdup(expression); + *flp = g_list_append(*flp, filt); + return g_list_last(*flp); +} + +/* + * Remove a filter from a list. + */ +void +remove_from_filter_list(filter_list_type_t list, GList *fl_entry) +{ + GList **flp; + filter_def *filt; + + flp = get_filter_list(list); + filt = (filter_def *) fl_entry->data; + g_free(filt->name); + g_free(filt->strval); + g_free(filt); + *flp = g_list_remove_link(*flp, fl_entry); +} + +/* + * Write out a list of filters. + * + * On success, "*pref_path_return" is set to NULL. + * On error, "*pref_path_return" is set to point to the pathname of + * the file we tried to read - it should be freed by our caller - + * and "*errno_return" is set to the error. + */ void -save_filter_list(void) +save_filter_list(filter_list_type_t list, char **pref_path_return, + int *errno_return) { + gchar *ff_path, *ff_path_new, *ff_dir = PF_DIR, *ff_name; + int path_length; + GList *fl; GList *flp; filter_def *filt; - gchar *ff_path, *ff_dir = PF_DIR, *ff_name = "filters"; FILE *ff; struct stat s_buf; - ff_path = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(ff_dir) + - strlen(ff_name) + 4); + *pref_path_return = NULL; /* assume no error */ + + switch (list) { + + case CFILTER_LIST: + ff_name = CFILTER_FILE_NAME; + fl = capture_filters; + break; + + case DFILTER_LIST: + ff_name = DFILTER_FILE_NAME; + fl = display_filters; + break; + + default: + g_assert_not_reached(); + return; + } + + path_length = strlen(get_home_dir()) + strlen(ff_dir) + strlen(ff_name) + + 4 + 4; + ff_path = (gchar *) g_malloc(path_length); sprintf(ff_path, "%s/%s", get_home_dir(), ff_dir); if (stat(ff_path, &s_buf) != 0) @@ -143,15 +332,50 @@ save_filter_list(void) sprintf(ff_path, "%s/%s/%s", get_home_dir(), ff_dir, ff_name); - if ((ff = fopen(ff_path, "w")) != NULL) { - flp = g_list_first(fl); - while (flp) { - filt = (filter_def *) flp->data; - fprintf(ff, "\"%s\" %s\n", filt->name, filt->strval); - flp = flp->next; + /* Write to "XXX.new", and rename if that succeeds. + That means we don't trash the file if we fail to write it out + completely. */ + ff_path_new = (gchar *) g_malloc(path_length); + sprintf(ff_path_new, "%s/%s/%s.new", get_home_dir(), ff_dir, ff_name); + + if ((ff = fopen(ff_path_new, "w")) == NULL) { + *pref_path_return = ff_path; + *errno_return = errno; + g_free(ff_path_new); + return; + } + flp = g_list_first(fl); + while (flp) { + filt = (filter_def *) flp->data; + fprintf(ff, "\"%s\" %s\n", filt->name, filt->strval); + if (ferror(ff)) { + *pref_path_return = ff_path; + *errno_return = errno; + fclose(ff); + unlink(ff_path_new); + g_free(ff_path_new); + return; } - fclose(ff); + flp = flp->next; + } + if (fclose(ff) == EOF) { + *pref_path_return = ff_path; + *errno_return = errno; + unlink(ff_path_new); + g_free(ff_path_new); + return; } + /* XXX - does "rename()" exist on Win32? If so, does it remove the + target first? If so, does that mean it's not atomic? */ + if (rename(ff_path_new, ff_path) < 0) { + *pref_path_return = ff_path; + *errno_return = errno; + unlink(ff_path_new); + g_free(ff_path); + g_free(ff_path_new); + return; + } + g_free(ff_path_new); g_free(ff_path); } |