nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* filters.c
2 * Code for reading and writing the filters file.
3 *
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
7 *
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.
12 *
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.
17 *
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.
21 */
22  
23 #include <config.h>
24  
25 #include <stdio.h>
26 #include <string.h>
27 #include <errno.h>
28  
29 #include <glib.h>
30  
31 #include <wsutil/file_util.h>
32 #include <wsutil/filesystem.h>
33  
34 #include "filter_files.h"
35  
36 /*
37 * Old filter file name.
38 */
39 #define FILTER_FILE_NAME "filters"
40  
41 /*
42 * Capture filter file name.
43 */
44 #define CFILTER_FILE_NAME "cfilters"
45  
46 /*
47 * Display filter file name.
48 */
49 #define DFILTER_FILE_NAME "dfilters"
50  
51 /*
52 * List of capture filters - saved.
53 */
54 static GList *capture_filters = NULL;
55  
56 /*
57 * List of display filters - saved.
58 */
59 static GList *display_filters = NULL;
60  
61 /*
62 * List of capture filters - currently edited.
63 */
64 static GList *capture_edited_filters = NULL;
65  
66 /*
67 * List of display filters - currently edited.
68 */
69 static GList *display_edited_filters = NULL;
70  
71 /*
72 * Read in a list of filters.
73 *
74 * On success, "*pref_path_return" is set to NULL.
75 * On error, "*pref_path_return" is set to point to the pathname of
76 * the file we tried to read - it should be freed by our caller -
77 * and "*errno_return" is set to the error.
78 */
79  
80 #define INIT_BUF_SIZE 128
81  
82 static GList *
83 add_filter_entry(GList *fl, const char *filt_name, const char *filt_expr)
84 {
85 filter_def *filt;
86  
87 filt = (filter_def *) g_malloc(sizeof(filter_def));
88 filt->name = g_strdup(filt_name);
89 filt->strval = g_strdup(filt_expr);
90 return g_list_append(fl, filt);
91 }
92  
93 static GList *
94 remove_filter_entry(GList *fl, GList *fl_entry)
95 {
96 filter_def *filt;
97  
98 filt = (filter_def *) fl_entry->data;
99 g_free(filt->name);
100 g_free(filt->strval);
101 g_free(filt);
102 return g_list_remove_link(fl, fl_entry);
103 }
104  
105 static int
106 skip_whitespace(FILE *ff)
107 {
108 int c;
109  
110 while ((c = getc(ff)) != EOF && c != '\n' && g_ascii_isspace(c))
111 ;
112 return c;
113 }
114  
115 static int
116 getc_crlf(FILE *ff)
117 {
118 int c;
119  
120 c = getc(ff);
121 if (c == '\r') {
122 /* Treat CR-LF at the end of a line like LF, so that if we're reading
123 * a Windows-format file on UN*X, we handle it the same way we'd handle
124 * a UN*X-format file. */
125 c = getc(ff);
126 if (c != EOF && c != '\n') {
127 /* Put back the character after the CR, and process the CR normally. */
128 ungetc(c, ff);
129 c = '\r';
130 }
131 }
132 return c;
133 }
134  
135 void
136 read_filter_list(filter_list_type_t list_type, char **pref_path_return,
137 int *errno_return)
138 {
139 const char *ff_name;
140 char *ff_path;
141 FILE *ff;
142 GList **flpp;
143 int c;
144 char *filt_name, *filt_expr;
145 int filt_name_len, filt_expr_len;
146 int filt_name_index, filt_expr_index;
147 int line = 1;
148  
149 *pref_path_return = NULL; /* assume no error */
150  
151 switch (list_type) {
152  
153 case CFILTER_LIST:
154 ff_name = CFILTER_FILE_NAME;
155 flpp = &capture_filters;
156 break;
157  
158 case DFILTER_LIST:
159 ff_name = DFILTER_FILE_NAME;
160 flpp = &display_filters;
161 break;
162  
163 default:
164 g_assert_not_reached();
165 return;
166 }
167  
168 /* try to open personal "cfilters"/"dfilters" file */
169 ff_path = get_persconffile_path(ff_name, TRUE);
170 if ((ff = ws_fopen(ff_path, "r")) == NULL) {
171 /*
172 * Did that fail because the file didn't exist?
173 */
174 if (errno != ENOENT) {
175 /*
176 * No. Just give up.
177 */
178 *pref_path_return = ff_path;
179 *errno_return = errno;
180 return;
181 }
182  
183 /*
184 * Yes. See if there's an "old style" personal "filters" file; if so, read it.
185 * This means that a user will start out with their capture and
186 * display filter lists being identical; each list may contain
187 * filters that don't belong in that list. The user can edit
188 * the filter lists, and delete the ones that don't belong in
189 * a particular list.
190 */
191 g_free(ff_path);
192 ff_path = get_persconffile_path(FILTER_FILE_NAME, FALSE);
193 if ((ff = ws_fopen(ff_path, "r")) == NULL) {
194 /*
195 * Did that fail because the file didn't exist?
196 */
197 if (errno != ENOENT) {
198 /*
199 * No. Just give up.
200 */
201 *pref_path_return = ff_path;
202 *errno_return = errno;
203 return;
204 }
205  
206 /*
207 * Try to open the global "cfilters/dfilters" file */
208 g_free(ff_path);
209 ff_path = get_datafile_path(ff_name);
210 if ((ff = ws_fopen(ff_path, "r")) == NULL) {
211  
212 /*
213 * Well, that didn't work, either. Just give up.
214 * Return an error if the file existed but we couldn't open it.
215 */
216 if (errno != ENOENT) {
217 *pref_path_return = ff_path;
218 *errno_return = errno;
219 } else {
220 g_free(ff_path);
221 }
222 return;
223 }
224 }
225 }
226  
227 /* If we already have a list of filters, discard it. */
228 /* this should never happen - this function is called only once for each list! */
229 while(*flpp) {
230 *flpp = remove_filter_entry(*flpp, g_list_first(*flpp));
231 }
232  
233 /* Allocate the filter name buffer. */
234 filt_name_len = INIT_BUF_SIZE;
235 filt_name = (char *)g_malloc(filt_name_len + 1);
236 filt_expr_len = INIT_BUF_SIZE;
237 filt_expr = (char *)g_malloc(filt_expr_len + 1);
238  
239 for (line = 1; ; line++) {
240 /* Lines in a filter file are of the form
241  
242 "name" expression
243  
244 where "name" is a name, in quotes - backslashes in the name
245 escape the next character, so quotes and backslashes can appear
246 in the name - and "expression" is a filter expression, not in
247 quotes, running to the end of the line. */
248  
249 /* Skip over leading white space, if any. */
250 c = skip_whitespace(ff);
251  
252 if (c == EOF)
253 break; /* Nothing more to read */
254 if (c == '\n')
255 continue; /* Blank line. */
256  
257 /* "c" is the first non-white-space character.
258 If it's not a quote, it's an error. */
259 if (c != '"') {
260 g_warning("'%s' line %d doesn't have a quoted filter name.", ff_path,
261 line);
262 while (c != '\n')
263 c = getc(ff); /* skip to the end of the line */
264 continue;
265 }
266  
267 /* Get the name of the filter. */
268 filt_name_index = 0;
269 for (;;) {
270 c = getc_crlf(ff);
271 if (c == EOF || c == '\n')
272 break; /* End of line - or end of file */
273 if (c == '"') {
274 /* Closing quote. */
275 if (filt_name_index >= filt_name_len) {
276 /* Filter name buffer isn't long enough; double its length. */
277 filt_name_len *= 2;
278 filt_name = (char *)g_realloc(filt_name, filt_name_len + 1);
279 }
280 filt_name[filt_name_index] = '\0';
281 break;
282 }
283 if (c == '\\') {
284 /* Next character is escaped */
285 c = getc_crlf(ff);
286 if (c == EOF || c == '\n')
287 break; /* End of line - or end of file */
288 }
289 /* Add this character to the filter name string. */
290 if (filt_name_index >= filt_name_len) {
291 /* Filter name buffer isn't long enough; double its length. */
292 filt_name_len *= 2;
293 filt_name = (char *)g_realloc(filt_name, filt_name_len + 1);
294 }
295 filt_name[filt_name_index] = c;
296 filt_name_index++;
297 }
298  
299 if (c == EOF) {
300 if (!ferror(ff)) {
301 /* EOF, not error; no newline seen before EOF */
302 g_warning("'%s' line %d doesn't have a newline.", ff_path,
303 line);
304 }
305 break; /* nothing more to read */
306 }
307  
308 if (c != '"') {
309 /* No newline seen before end-of-line */
310 g_warning("'%s' line %d doesn't have a closing quote.", ff_path,
311 line);
312 continue;
313 }
314  
315 /* Skip over separating white space, if any. */
316 c = skip_whitespace(ff);
317  
318 if (c == EOF) {
319 if (!ferror(ff)) {
320 /* EOF, not error; no newline seen before EOF */
321 g_warning("'%s' line %d doesn't have a newline.", ff_path,
322 line);
323 }
324 break; /* nothing more to read */
325 }
326  
327 if (c == '\n') {
328 /* No filter expression */
329 g_warning("'%s' line %d doesn't have a filter expression.", ff_path,
330 line);
331 continue;
332 }
333  
334 /* "c" is the first non-white-space character; it's the first
335 character of the filter expression. */
336 filt_expr_index = 0;
337 for (;;) {
338 /* Add this character to the filter expression string. */
339 if (filt_expr_index >= filt_expr_len) {
340 /* Filter expressioin buffer isn't long enough; double its length. */
341 filt_expr_len *= 2;
342 filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1);
343 }
344 filt_expr[filt_expr_index] = c;
345 filt_expr_index++;
346  
347 /* Get the next character. */
348 c = getc_crlf(ff);
349 if (c == EOF || c == '\n')
350 break;
351 }
352  
353 if (c == EOF) {
354 if (!ferror(ff)) {
355 /* EOF, not error; no newline seen before EOF */
356 g_warning("'%s' line %d doesn't have a newline.", ff_path,
357 line);
358 }
359 break; /* nothing more to read */
360 }
361  
362 /* We saw the ending newline; terminate the filter expression string */
363 if (filt_expr_index >= filt_expr_len) {
364 /* Filter expressioin buffer isn't long enough; double its length. */
365 filt_expr_len *= 2;
366 filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1);
367 }
368 filt_expr[filt_expr_index] = '\0';
369  
370 /* Add the new filter to the list of filters */
371 *flpp = add_filter_entry(*flpp, filt_name, filt_expr);
372 }
373 if (ferror(ff)) {
374 *pref_path_return = ff_path;
375 *errno_return = errno;
376 } else
377 g_free(ff_path);
378 fclose(ff);
379 g_free(filt_name);
380 g_free(filt_expr);
381  
382 /* init the corresponding edited list */
383 switch (list_type) {
384 case CFILTER_LIST:
385 copy_filter_list(CFILTER_EDITED_LIST, CFILTER_LIST);
386 break;
387 case DFILTER_LIST:
388 copy_filter_list(DFILTER_EDITED_LIST, DFILTER_LIST);
389 break;
390 default:
391 g_assert_not_reached();
392 return;
393 }
394 }
395  
396 /*
397 * Get a pointer to a list of filters.
398 */
399 static GList **
400 get_filter_list(filter_list_type_t list_type)
401 {
402 GList **flpp;
403  
404 switch (list_type) {
405  
406 case CFILTER_LIST:
407 flpp = &capture_filters;
408 break;
409  
410 case DFILTER_LIST:
411 flpp = &display_filters;
412 break;
413  
414 case CFILTER_EDITED_LIST:
415 flpp = &capture_edited_filters;
416 break;
417  
418 case DFILTER_EDITED_LIST:
419 flpp = &display_edited_filters;
420 break;
421  
422 default:
423 g_assert_not_reached();
424 flpp = NULL;
425 }
426 return flpp;
427 }
428  
429 /*
430 * Get a pointer to the first entry in a filter list.
431 */
432 GList *
433 get_filter_list_first(filter_list_type_t list_type)
434 {
435 GList **flpp;
436  
437 flpp = get_filter_list(list_type);
438 return g_list_first(*flpp);
439 }
440  
441 /*
442 * Add a new filter to the end of a list.
443 * Returns a pointer to the newly-added entry.
444 */
445 GList *
446 add_to_filter_list(filter_list_type_t list_type, const char *name,
447 const char *expression)
448 {
449 GList **flpp;
450  
451 flpp = get_filter_list(list_type);
452 *flpp = add_filter_entry(*flpp, name, expression);
453  
454 return g_list_last(*flpp);
455 }
456  
457 /*
458 * Remove a filter from a list.
459 */
460 void
461 remove_from_filter_list(filter_list_type_t list_type, GList *fl_entry)
462 {
463 GList **flpp;
464  
465 flpp = get_filter_list(list_type);
466 *flpp = remove_filter_entry(*flpp, fl_entry);
467 }
468  
469 /*
470 * Write out a list of filters.
471 *
472 * On success, "*pref_path_return" is set to NULL.
473 * On error, "*pref_path_return" is set to point to the pathname of
474 * the file we tried to read - it should be freed by our caller -
475 * and "*errno_return" is set to the error.
476 */
477 void
478 save_filter_list(filter_list_type_t list_type, char **pref_path_return,
479 int *errno_return)
480 {
481 const gchar *ff_name;
482 gchar *ff_path, *ff_path_new;
483 GList *fl;
484 GList *flpp;
485 filter_def *filt;
486 FILE *ff;
487 guchar *p, c;
488  
489 *pref_path_return = NULL; /* assume no error */
490  
491 switch (list_type) {
492  
493 case CFILTER_LIST:
494 ff_name = CFILTER_FILE_NAME;
495 fl = capture_filters;
496 break;
497  
498 case DFILTER_LIST:
499 ff_name = DFILTER_FILE_NAME;
500 fl = display_filters;
501 break;
502  
503 default:
504 g_assert_not_reached();
505 return;
506 }
507  
508 ff_path = get_persconffile_path(ff_name, TRUE);
509  
510 /* Write to "XXX.new", and rename if that succeeds.
511 That means we don't trash the file if we fail to write it out
512 completely. */
513 ff_path_new = g_strdup_printf("%s.new", ff_path);
514  
515 if ((ff = ws_fopen(ff_path_new, "w")) == NULL) {
516 *pref_path_return = ff_path;
517 *errno_return = errno;
518 g_free(ff_path_new);
519 return;
520 }
521 flpp = g_list_first(fl);
522 while (flpp) {
523 filt = (filter_def *) flpp->data;
524  
525 /* Write out the filter name as a quoted string; escape any quotes
526 or backslashes. */
527 putc('"', ff);
528 for (p = (guchar *)filt->name; (c = *p) != '\0'; p++) {
529 if (c == '"' || c == '\\')
530 putc('\\', ff);
531 putc(c, ff);
532 }
533 putc('"', ff);
534  
535 /* Separate the filter name and value with a space. */
536 putc(' ', ff);
537  
538 /* Write out the filter expression and a newline. */
539 fprintf(ff, "%s\n", filt->strval);
540 if (ferror(ff)) {
541 *pref_path_return = ff_path;
542 *errno_return = errno;
543 fclose(ff);
544 ws_unlink(ff_path_new);
545 g_free(ff_path_new);
546 return;
547 }
548 flpp = flpp->next;
549 }
550 if (fclose(ff) == EOF) {
551 *pref_path_return = ff_path;
552 *errno_return = errno;
553 ws_unlink(ff_path_new);
554 g_free(ff_path_new);
555 return;
556 }
557  
558 #ifdef _WIN32
559 /* ANSI C doesn't say whether "rename()" removes the target if it
560 exists; the Win32 call to rename files doesn't do so, which I
561 infer is the reason why the MSVC++ "rename()" doesn't do so.
562 We must therefore remove the target file first, on Windows.
563  
564 XXX - ws_rename() should be ws_stdio_rename() on Windows,
565 and ws_stdio_rename() uses MoveFileEx() with MOVEFILE_REPLACE_EXISTING,
566 so it should remove the target if it exists, so this stuff
567 shouldn't be necessary. Perhaps it dates back to when we were
568 calling rename(), with that being a wrapper around Microsoft's
569 _rename(), which didn't remove the target. */
570 if (ws_remove(ff_path) < 0 && errno != ENOENT) {
571 /* It failed for some reason other than "it's not there"; if
572 it's not there, we don't need to remove it, so we just
573 drive on. */
574 *pref_path_return = ff_path;
575 *errno_return = errno;
576 ws_unlink(ff_path_new);
577 g_free(ff_path_new);
578 return;
579 }
580 #endif
581  
582 if (ws_rename(ff_path_new, ff_path) < 0) {
583 *pref_path_return = ff_path;
584 *errno_return = errno;
585 ws_unlink(ff_path_new);
586 g_free(ff_path_new);
587 return;
588 }
589 g_free(ff_path_new);
590 g_free(ff_path);
591 }
592  
593 /*
594 * Copy a filter list into another.
595 */
596 void copy_filter_list(filter_list_type_t dest_type, filter_list_type_t src_type)
597 {
598 GList **flpp_dest;
599 GList **flpp_src;
600 GList *flp_src;
601 filter_def *filt;
602  
603 g_assert(dest_type != src_type);
604  
605 flpp_dest = get_filter_list(dest_type);
606 flpp_src = get_filter_list(src_type);
607 /* throw away the "old" destination list - a NULL list is ok here */
608 while(*flpp_dest) {
609 *flpp_dest = remove_filter_entry(*flpp_dest, g_list_first(*flpp_dest));
610 }
611 g_assert(g_list_length(*flpp_dest) == 0);
612  
613 /* copy the list entries */
614 for(flp_src = g_list_first(*flpp_src); flp_src; flp_src = g_list_next(flp_src)) {
615 filt = (filter_def *)(flp_src->data);
616  
617 *flpp_dest = add_filter_entry(*flpp_dest, filt->name, filt->strval);
618 }
619 }
620  
621 /*
622 * Editor modelines - http://www.wireshark.org/tools/modelines.html
623 *
624 * Local Variables:
625 * c-basic-offset: 2
626 * tab-width: 8
627 * indent-tabs-mode: nil
628 * End:
629 *
630 * ex: set shiftwidth=2 tabstop=8 expandtab:
631 * :indentSize=2:tabSize=8:noTabs=true:
632 */