2 * Code for reading and writing the filters file.
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.
36 #include <wsutil/file_util.h>
37 #include <wsutil/filesystem.h>
42 * Old filter file name.
44 #define FILTER_FILE_NAME "filters"
47 * Capture filter file name.
49 #define CFILTER_FILE_NAME "cfilters"
52 * Display filter file name.
54 #define DFILTER_FILE_NAME "dfilters"
57 * List of capture filters - saved.
59 static GList *capture_filters = NULL;
62 * List of display filters - saved.
64 static GList *display_filters = NULL;
67 * List of capture filters - currently edited.
69 static GList *capture_edited_filters = NULL;
72 * List of display filters - currently edited.
74 static GList *display_edited_filters = NULL;
77 * Read in a list of filters.
79 * On success, "*pref_path_return" is set to NULL.
80 * On error, "*pref_path_return" is set to point to the pathname of
81 * the file we tried to read - it should be freed by our caller -
82 * and "*errno_return" is set to the error.
85 #define INIT_BUF_SIZE 128
88 add_filter_entry(GList *fl, const char *filt_name, const char *filt_expr)
92 filt = (filter_def *) g_malloc(sizeof(filter_def));
93 filt->name = g_strdup(filt_name);
94 filt->strval = g_strdup(filt_expr);
95 return g_list_append(fl, filt);
99 remove_filter_entry(GList *fl, GList *fl_entry)
103 filt = (filter_def *) fl_entry->data;
105 g_free(filt->strval);
107 return g_list_remove_link(fl, fl_entry);
111 read_filter_list(filter_list_type_t list_type, char **pref_path_return,
119 char *filt_name, *filt_expr;
120 int filt_name_len, filt_expr_len;
121 int filt_name_index, filt_expr_index;
124 *pref_path_return = NULL; /* assume no error */
129 ff_name = CFILTER_FILE_NAME;
130 flpp = &capture_filters;
134 ff_name = DFILTER_FILE_NAME;
135 flpp = &display_filters;
139 g_assert_not_reached();
143 /* try to open personal "cfilters"/"dfilters" file */
144 ff_path = get_persconffile_path(ff_name, TRUE);
145 if ((ff = ws_fopen(ff_path, "r")) == NULL) {
147 * Did that fail because the file didn't exist?
149 if (errno != ENOENT) {
153 *pref_path_return = ff_path;
154 *errno_return = errno;
159 * Yes. See if there's an "old style" personal "filters" file; if so, read it.
160 * This means that a user will start out with their capture and
161 * display filter lists being identical; each list may contain
162 * filters that don't belong in that list. The user can edit
163 * the filter lists, and delete the ones that don't belong in
167 ff_path = get_persconffile_path(FILTER_FILE_NAME, FALSE);
168 if ((ff = ws_fopen(ff_path, "r")) == NULL) {
170 * Did that fail because the file didn't exist?
172 if (errno != ENOENT) {
176 *pref_path_return = ff_path;
177 *errno_return = errno;
182 * Try to open the global "cfilters/dfilters" file */
184 ff_path = get_datafile_path(ff_name);
185 if ((ff = ws_fopen(ff_path, "r")) == NULL) {
188 * Well, that didn't work, either. Just give up.
189 * Return an error if the file existed but we couldn't open it.
191 if (errno != ENOENT) {
192 *pref_path_return = ff_path;
193 *errno_return = errno;
202 /* If we already have a list of filters, discard it. */
203 /* this should never happen - this function is called only once for each list! */
205 *flpp = remove_filter_entry(*flpp, g_list_first(*flpp));
208 /* Allocate the filter name buffer. */
209 filt_name_len = INIT_BUF_SIZE;
210 filt_name = (char *)g_malloc(filt_name_len + 1);
211 filt_expr_len = INIT_BUF_SIZE;
212 filt_expr = (char *)g_malloc(filt_expr_len + 1);
214 for (line = 1; ; line++) {
215 /* Lines in a filter file are of the form
219 where "name" is a name, in quotes - backslashes in the name
220 escape the next character, so quotes and backslashes can appear
221 in the name - and "expression" is a filter expression, not in
222 quotes, running to the end of the line. */
224 /* Skip over leading white space, if any. */
225 while ((c = getc(ff)) != EOF && isspace(c)) {
233 break; /* Nothing more to read */
235 /* "c" is the first non-white-space character.
236 If it's not a quote, it's an error. */
238 g_warning("'%s' line %d doesn't have a quoted filter name.", ff_path,
241 c = getc(ff); /* skip to the end of the line */
245 /* Get the name of the filter. */
249 if (c == EOF || c == '\n')
250 break; /* End of line - or end of file */
253 if (filt_name_index >= filt_name_len) {
254 /* Filter name buffer isn't long enough; double its length. */
256 filt_name = (char *)g_realloc(filt_name, filt_name_len + 1);
258 filt_name[filt_name_index] = '\0';
262 /* Next character is escaped */
264 if (c == EOF || c == '\n')
265 break; /* End of line - or end of file */
267 /* Add this character to the filter name string. */
268 if (filt_name_index >= filt_name_len) {
269 /* Filter name buffer isn't long enough; double its length. */
271 filt_name = (char *)g_realloc(filt_name, filt_name_len + 1);
273 filt_name[filt_name_index] = c;
279 /* EOF, not error; no newline seen before EOF */
280 g_warning("'%s' line %d doesn't have a newline.", ff_path,
283 break; /* nothing more to read */
287 /* No newline seen before end-of-line */
288 g_warning("'%s' line %d doesn't have a closing quote.", ff_path,
293 /* Skip over separating white space, if any. */
294 while ((c = getc(ff)) != EOF && isspace(c)) {
301 /* EOF, not error; no newline seen before EOF */
302 g_warning("'%s' line %d doesn't have a newline.", ff_path,
305 break; /* nothing more to read */
309 /* No filter expression */
310 g_warning("'%s' line %d doesn't have a filter expression.", ff_path,
315 /* "c" is the first non-white-space character; it's the first
316 character of the filter expression. */
319 /* Add this character to the filter expression string. */
320 if (filt_expr_index >= filt_expr_len) {
321 /* Filter expressioin buffer isn't long enough; double its length. */
323 filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1);
325 filt_expr[filt_expr_index] = c;
328 /* Get the next character. */
330 if (c == EOF || c == '\n')
336 /* EOF, not error; no newline seen before EOF */
337 g_warning("'%s' line %d doesn't have a newline.", ff_path,
340 break; /* nothing more to read */
343 /* We saw the ending newline; terminate the filter expression string */
344 if (filt_expr_index >= filt_expr_len) {
345 /* Filter expressioin buffer isn't long enough; double its length. */
347 filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1);
349 filt_expr[filt_expr_index] = '\0';
351 /* Add the new filter to the list of filters */
352 *flpp = add_filter_entry(*flpp, filt_name, filt_expr);
355 *pref_path_return = ff_path;
356 *errno_return = errno;
363 /* init the corresponding edited list */
366 copy_filter_list(CFILTER_EDITED_LIST, CFILTER_LIST);
369 copy_filter_list(DFILTER_EDITED_LIST, DFILTER_LIST);
372 g_assert_not_reached();
378 * Get a pointer to a list of filters.
381 get_filter_list(filter_list_type_t list_type)
388 flpp = &capture_filters;
392 flpp = &display_filters;
395 case CFILTER_EDITED_LIST:
396 flpp = &capture_edited_filters;
399 case DFILTER_EDITED_LIST:
400 flpp = &display_edited_filters;
404 g_assert_not_reached();
411 * Get a pointer to the first entry in a filter list.
414 get_filter_list_first(filter_list_type_t list_type)
418 flpp = get_filter_list(list_type);
419 return g_list_first(*flpp);
423 * Add a new filter to the end of a list.
424 * Returns a pointer to the newly-added entry.
427 add_to_filter_list(filter_list_type_t list_type, const char *name,
428 const char *expression)
432 flpp = get_filter_list(list_type);
433 *flpp = add_filter_entry(*flpp, name, expression);
435 return g_list_last(*flpp);
439 * Remove a filter from a list.
442 remove_from_filter_list(filter_list_type_t list_type, GList *fl_entry)
446 flpp = get_filter_list(list_type);
447 *flpp = remove_filter_entry(*flpp, fl_entry);
451 * Write out a list of filters.
453 * On success, "*pref_path_return" is set to NULL.
454 * On error, "*pref_path_return" is set to point to the pathname of
455 * the file we tried to read - it should be freed by our caller -
456 * and "*errno_return" is set to the error.
459 save_filter_list(filter_list_type_t list_type, char **pref_path_return,
462 const gchar *ff_name;
463 gchar *ff_path, *ff_path_new;
470 *pref_path_return = NULL; /* assume no error */
475 ff_name = CFILTER_FILE_NAME;
476 fl = capture_filters;
480 ff_name = DFILTER_FILE_NAME;
481 fl = display_filters;
485 g_assert_not_reached();
489 ff_path = get_persconffile_path(ff_name, TRUE);
491 /* Write to "XXX.new", and rename if that succeeds.
492 That means we don't trash the file if we fail to write it out
494 ff_path_new = g_strdup_printf("%s.new", ff_path);
496 if ((ff = ws_fopen(ff_path_new, "w")) == NULL) {
497 *pref_path_return = ff_path;
498 *errno_return = errno;
502 flpp = g_list_first(fl);
504 filt = (filter_def *) flpp->data;
506 /* Write out the filter name as a quoted string; escape any quotes
509 for (p = (guchar *)filt->name; (c = *p) != '\0'; p++) {
510 if (c == '"' || c == '\\')
516 /* Separate the filter name and value with a space. */
519 /* Write out the filter expression and a newline. */
520 fprintf(ff, "%s\n", filt->strval);
522 *pref_path_return = ff_path;
523 *errno_return = errno;
525 ws_unlink(ff_path_new);
531 if (fclose(ff) == EOF) {
532 *pref_path_return = ff_path;
533 *errno_return = errno;
534 ws_unlink(ff_path_new);
540 /* ANSI C doesn't say whether "rename()" removes the target if it
541 exists; the Win32 call to rename files doesn't do so, which I
542 infer is the reason why the MSVC++ "rename()" doesn't do so.
543 We must therefore remove the target file first, on Windows.
545 XXX - ws_rename() should be ws_stdio_rename() on Windows,
546 and ws_stdio_rename() uses MoveFileEx() with MOVEFILE_REPLACE_EXISTING,
547 so it should remove the target if it exists, so this stuff
548 shouldn't be necessary. Perhaps it dates back to when we were
549 calling rename(), with that being a wrapper around Microsoft's
550 _rename(), which didn't remove the target. */
551 if (ws_remove(ff_path) < 0 && errno != ENOENT) {
552 /* It failed for some reason other than "it's not there"; if
553 it's not there, we don't need to remove it, so we just
555 *pref_path_return = ff_path;
556 *errno_return = errno;
557 ws_unlink(ff_path_new);
563 if (ws_rename(ff_path_new, ff_path) < 0) {
564 *pref_path_return = ff_path;
565 *errno_return = errno;
566 ws_unlink(ff_path_new);
575 * Copy a filter list into another.
577 void copy_filter_list(filter_list_type_t dest_type, filter_list_type_t src_type)
584 g_assert(dest_type != src_type);
586 flpp_dest = get_filter_list(dest_type);
587 flpp_src = get_filter_list(src_type);
588 /* throw away the "old" destination list - a NULL list is ok here */
590 *flpp_dest = remove_filter_entry(*flpp_dest, g_list_first(*flpp_dest));
592 g_assert(g_list_length(*flpp_dest) == 0);
594 /* copy the list entries */
595 for(flp_src = g_list_first(*flpp_src); flp_src; flp_src = g_list_next(flp_src)) {
596 filt = (filter_def *)(flp_src->data);
598 *flpp_dest = add_filter_entry(*flpp_dest, filt->name, filt->strval);