From Anders:
[metze/wireshark/wip.git] / disabled_protos.c
1 /* disabled_protos.c
2  * Code for reading and writing the disabled protocols file.
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
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.
14  *
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.
19  *
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.
23  */
24
25 #include "config.h"
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <errno.h>
31
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35
36 #include <glib.h>
37
38 #include <epan/filesystem.h>
39 #include <epan/proto.h>
40
41 #include "disabled_protos.h"
42 #include <wsutil/file_util.h>
43
44 #define GLOBAL_PROTOCOLS_FILE_NAME      "disabled_protos"
45 #define PROTOCOLS_FILE_NAME             "disabled_protos"
46
47 /*
48  * List of disabled protocols
49  */
50 static GList *global_disabled_protos = NULL;
51 static GList *disabled_protos = NULL;
52
53 #define INIT_BUF_SIZE   128
54
55 static void
56 discard_existing_list (GList **flp)
57 {
58   GList      *fl_ent;
59   protocol_def *prot;
60
61   if (*flp != NULL) {
62     fl_ent = g_list_first(*flp);
63     while (fl_ent != NULL) {
64       prot = (protocol_def *) fl_ent->data;
65       g_free(prot->name);
66       g_free(prot);
67       fl_ent = fl_ent->next;
68     }
69     g_list_free(*flp);
70     *flp = NULL;
71   }
72 }
73
74 /*
75  * Read in a list of disabled protocols.
76  *
77  * On success, "*pref_path_return" is set to NULL.
78  * On error, "*pref_path_return" is set to point to the pathname of
79  * the file we tried to read - it should be freed by our caller -
80  * and "*open_errno_return" is set to the error if an open failed
81  * or "*read_errno_return" is set to the error if a read failed.
82  */
83
84 static int read_disabled_protos_list_file(const char *ff_path, FILE *ff,
85                                           GList **flp);
86
87 void
88 read_disabled_protos_list(char **gpath_return, int *gopen_errno_return,
89                           int *gread_errno_return,
90                           char **path_return, int *open_errno_return,
91                           int *read_errno_return)
92 {
93   int         err;
94   char       *gff_path, *ff_path;
95   FILE       *ff;
96
97   /* Construct the pathname of the global disabled protocols file. */
98   gff_path = get_datafile_path(GLOBAL_PROTOCOLS_FILE_NAME);
99
100   /* If we already have a list of protocols, discard it. */
101   discard_existing_list (&global_disabled_protos);
102
103   /* Read the global disabled protocols file, if it exists. */
104   *gpath_return = NULL;
105   if ((ff = ws_fopen(gff_path, "r")) != NULL) {
106     /* We succeeded in opening it; read it. */
107     err = read_disabled_protos_list_file(gff_path, ff,
108                                          &global_disabled_protos);
109     if (err != 0) {
110       /* We had an error reading the file; return the errno and the
111          pathname, so our caller can report the error. */
112       *gopen_errno_return = 0;
113       *gread_errno_return = err;
114       *gpath_return = gff_path;
115     } else
116       g_free(gff_path);
117     fclose(ff);
118   } else {
119     /* We failed to open it.  If we failed for some reason other than
120        "it doesn't exist", return the errno and the pathname, so our
121        caller can report the error. */
122     if (errno != ENOENT) {
123       *gopen_errno_return = errno;
124       *gread_errno_return = 0;
125       *gpath_return = gff_path;
126     } else
127       g_free(gff_path);
128   }
129
130   /* Construct the pathname of the user's disabled protocols file. */
131   ff_path = get_persconffile_path(PROTOCOLS_FILE_NAME, TRUE);
132
133   /* If we already have a list of protocols, discard it. */
134   discard_existing_list (&disabled_protos);
135
136   /* Read the user's disabled protocols file, if it exists. */
137   *path_return = NULL;
138   if ((ff = ws_fopen(ff_path, "r")) != NULL) {
139     /* We succeeded in opening it; read it. */
140     err = read_disabled_protos_list_file(ff_path, ff, &disabled_protos);
141     if (err != 0) {
142       /* We had an error reading the file; return the errno and the
143          pathname, so our caller can report the error. */
144       *open_errno_return = 0;
145       *read_errno_return = err;
146       *path_return = ff_path;
147     } else
148       g_free(ff_path);
149     fclose(ff);
150   } else {
151     /* We failed to open it.  If we failed for some reason other than
152        "it doesn't exist", return the errno and the pathname, so our
153        caller can report the error. */
154     if (errno != ENOENT) {
155       *open_errno_return = errno;
156       *read_errno_return = 0;
157       *path_return = ff_path;
158     } else
159       g_free(ff_path);
160   }
161 }
162
163 static int
164 read_disabled_protos_list_file(const char *ff_path, FILE *ff,
165                                GList **flp)
166 {
167   protocol_def *prot;
168   int         c;
169   char       *prot_name;
170   int         prot_name_len;
171   int         prot_name_index;
172   int         line = 1;
173
174
175   /* Allocate the protocol name buffer. */
176   prot_name_len = INIT_BUF_SIZE;
177   prot_name = (char *)g_malloc(prot_name_len + 1);
178
179   for (line = 1; ; line++) {
180     /* Lines in a disabled protocol file contain the "filter name" of
181        a protocol to be disabled. */
182
183     /* Skip over leading white space, if any. */
184     while ((c = getc(ff)) != EOF && isspace(c)) {
185       if (c == '\n') {
186         /* Blank line. */
187         continue;
188       }
189     }
190
191     if (c == EOF) {
192       if (ferror(ff))
193         goto error;     /* I/O error */
194       else
195         break;  /* Nothing more to read */
196     }
197     ungetc(c, ff);      /* Unread the non-white-space character. */
198
199     /* Get the name of the protocol. */
200     prot_name_index = 0;
201     for (;;) {
202       c = getc(ff);
203       if (c == EOF)
204         break;  /* End of file, or I/O error */
205       if (isspace(c))
206         break;  /* Trailing white space, or end of line. */
207       if (c == '#')
208         break;  /* Start of comment, running to end of line. */
209       /* Add this character to the protocol name string. */
210       if (prot_name_index >= prot_name_len) {
211         /* protocol name buffer isn't long enough; double its length. */
212         prot_name_len *= 2;
213         prot_name = (char *)g_realloc(prot_name, prot_name_len + 1);
214       }
215       prot_name[prot_name_index] = c;
216       prot_name_index++;
217     }
218
219     if (isspace(c) && c != '\n') {
220       /* Skip over trailing white space. */
221       while ((c = getc(ff)) != EOF && c != '\n' && isspace(c))
222         ;
223       if (c != EOF && c != '\n' && c != '#') {
224         /* Non-white-space after the protocol name; warn about it,
225            in case we come up with a reason to use it. */
226         g_warning("'%s' line %d has extra stuff after the protocol name.",
227                   ff_path, line);
228       }
229     }
230     if (c != EOF && c != '\n') {
231       /* Skip to end of line. */
232       while ((c = getc(ff)) != EOF && c != '\n')
233         ;
234     }
235
236     if (c == EOF) {
237       if (ferror(ff))
238         goto error;     /* I/O error */
239       else {
240         /* EOF, not error; no newline seen before EOF */
241         g_warning("'%s' line %d doesn't have a newline.", ff_path,
242                   line);
243       }
244       break;    /* nothing more to read */
245     }
246
247     /* Null-terminate the protocol name. */
248     if (prot_name_index >= prot_name_len) {
249       /* protocol name buffer isn't long enough; double its length. */
250       prot_name_len *= 2;
251       prot_name = (char *)g_realloc(prot_name, prot_name_len + 1);
252     }
253     prot_name[prot_name_index] = '\0';
254
255     /* Add the new protocol to the list of disabled protocols */
256     prot         = (protocol_def *) g_malloc(sizeof(protocol_def));
257     prot->name   = g_strdup(prot_name);
258     *flp = g_list_append(*flp, prot);
259   }
260   g_free(prot_name);
261   return 0;
262
263 error:
264   return errno;
265 }
266
267 /*
268  * Disable protocols as per the stored configuration
269  */
270 void
271 set_disabled_protos_list(void)
272 {
273   gint i;
274   GList *fl_ent;
275   protocol_def *prot;
276
277   /*
278    * assume all protocols are enabled by default
279    */
280   if (disabled_protos == NULL)
281     goto skip;
282
283   fl_ent = g_list_first(disabled_protos);
284
285   while (fl_ent != NULL) {
286     prot = (protocol_def *) fl_ent->data;
287     i = proto_get_id_by_filter_name(prot->name);
288     if (i == -1) {
289       /* XXX - complain here? */
290     } else {
291       if (proto_can_toggle_protocol(i))
292         proto_set_decoding(i, FALSE);
293     }
294
295     fl_ent = fl_ent->next;
296   }
297
298 skip:
299   if (global_disabled_protos == NULL)
300     return;
301
302   fl_ent = g_list_first(global_disabled_protos);
303
304   while (fl_ent != NULL) {
305     prot = (protocol_def *) fl_ent->data;
306     i = proto_get_id_by_filter_name(prot->name);
307     if (i == -1) {
308       /* XXX - complain here? */
309     } else {
310       if (proto_can_toggle_protocol(i)) {
311         proto_set_decoding(i, FALSE);
312         proto_set_cant_toggle(i);
313       }
314     }
315
316     fl_ent = fl_ent->next;
317   }
318 }
319
320 /*
321  * Write out a list of disabled protocols.
322  *
323  * On success, "*pref_path_return" is set to NULL.
324  * On error, "*pref_path_return" is set to point to the pathname of
325  * the file we tried to read - it should be freed by our caller -
326  * and "*errno_return" is set to the error.
327  */
328 void
329 save_disabled_protos_list(char **pref_path_return, int *errno_return)
330 {
331   gchar       *ff_path, *ff_path_new;
332   FILE        *ff;
333   gint         i;
334   protocol_t  *protocol;
335   void        *cookie;
336
337   *pref_path_return = NULL;     /* assume no error */
338
339   ff_path = get_persconffile_path(PROTOCOLS_FILE_NAME, TRUE);
340
341   /* Write to "XXX.new", and rename if that succeeds.
342      That means we don't trash the file if we fail to write it out
343      completely. */
344   ff_path_new = g_strdup_printf("%s.new", ff_path);
345
346   if ((ff = ws_fopen(ff_path_new, "w")) == NULL) {
347     *pref_path_return = ff_path;
348     *errno_return = errno;
349     g_free(ff_path_new);
350     return;
351   }
352
353   /* Iterate over all the protocols */
354
355   for (i = proto_get_first_protocol(&cookie); i != -1;
356        i = proto_get_next_protocol(&cookie)) {
357
358     if (!proto_can_toggle_protocol(i)) {
359       continue;
360     }
361
362     protocol = find_protocol_by_id(i);
363     if (proto_is_protocol_enabled(protocol)) {
364       continue;
365     }
366
367     /* Write out the protocol name. */
368     fprintf(ff, "%s\n", proto_get_protocol_filter_name(i));
369   }
370
371   if (fclose(ff) == EOF) {
372     *pref_path_return = ff_path;
373     *errno_return = errno;
374     ws_unlink(ff_path_new);
375     g_free(ff_path_new);
376     return;
377   }
378
379 #ifdef _WIN32
380   /* ANSI C doesn't say whether "rename()" removes the target if it
381      exists; the Win32 call to rename files doesn't do so, which I
382      infer is the reason why the MSVC++ "rename()" doesn't do so.
383      We must therefore remove the target file first, on Windows.
384
385      XXX - ws_rename() should be ws_stdio_rename() on Windows,
386      and ws_stdio_rename() uses MoveFileEx() with MOVEFILE_REPLACE_EXISTING,
387      so it should remove the target if it exists, so this stuff
388      shouldn't be necessary.  Perhaps it dates back to when we were
389      calling rename(), with that being a wrapper around Microsoft's
390      _rename(), which didn't remove the target. */
391   if (ws_remove(ff_path) < 0 && errno != ENOENT) {
392     /* It failed for some reason other than "it's not there"; if
393        it's not there, we don't need to remove it, so we just
394        drive on. */
395     *pref_path_return = ff_path;
396     *errno_return = errno;
397     ws_unlink(ff_path_new);
398     g_free(ff_path_new);
399     return;
400   }
401 #endif
402
403   if (ws_rename(ff_path_new, ff_path) < 0) {
404     *pref_path_return = ff_path;
405     *errno_return = errno;
406     ws_unlink(ff_path_new);
407     g_free(ff_path_new);
408     return;
409   }
410   g_free(ff_path_new);
411   g_free(ff_path);
412 }