Add support for a global "ethereal.conf" preferences file, stored in the
[obnox/wireshark/wip.git] / tethereal.c
1 /* tethereal.c
2  *
3  * $Id: tethereal.c,v 1.34 2000/07/05 09:40:43 guy Exp $
4  *
5  * Ethereal - Network traffic analyzer
6  * By Gerald Combs <gerald@zing.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * Text-mode variant, by Gilbert Ramirez <gram@xiexie.org>.
10  *
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.
15  * 
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.
20  * 
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.
24  *
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <locale.h>
35
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39
40 #include <errno.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 #include <signal.h>
45
46 #ifdef NEED_SNPRINTF_H
47 # ifdef HAVE_STDARG_H
48 #  include <stdarg.h>
49 # else
50 #  include <varargs.h>
51 # endif
52 # include "snprintf.h"
53 #endif
54
55 #if defined(HAVE_UCD_SNMP_SNMP_H)
56 #ifdef HAVE_UCD_SNMP_VERSION_H
57 #include <ucd-snmp/version.h>
58 #endif /* HAVE_UCD_SNMP_VERSION_H */
59 #elif defined(HAVE_SNMP_SNMP_H)
60 #ifdef HAVE_SNMP_VERSION_H
61 #include <snmp/version.h>
62 #endif /* HAVE_SNMP_VERSION_H */
63 #endif /* SNMP */
64
65 #ifdef NEED_STRERROR_H
66 #include "strerror.h"
67 #endif
68
69 #ifdef NEED_GETOPT_H
70 #include "getopt.h"
71 #endif
72
73 #include "globals.h"
74 #include "timestamp.h"
75 #include "packet.h"
76 #include "file.h"
77 #include "prefs.h"
78 #include "column.h"
79 #include "print.h"
80 #include "resolv.h"
81 #include "follow.h"
82 #include "util.h"
83 #include "ui_util.h"
84 #include "conversation.h"
85 #include "plugins.h"
86
87 static guint32 firstsec, firstusec;
88 static guint32 prevsec, prevusec;
89 static gchar   comp_info_str[256];
90 static gboolean verbose;
91 static gboolean print_hex;
92
93 #ifdef HAVE_LIBPCAP
94 typedef struct _loop_data {
95   gint           linktype;
96   pcap_t        *pch;
97   wtap_dumper   *pdh;
98 } loop_data;
99
100 static loop_data ld;
101
102 static int capture(int, int);
103 static void capture_pcap_cb(u_char *, const struct pcap_pkthdr *,
104   const u_char *);
105 static void capture_cleanup(int);
106 #endif
107
108 typedef struct {
109   capture_file *cf;
110   wtap_dumper *pdh;
111 } cb_args_t;
112
113 static int load_cap_file(capture_file *, int);
114 static void wtap_dispatch_cb_write(u_char *, const struct wtap_pkthdr *, int,
115     union wtap_pseudo_header *, const u_char *);
116 static void wtap_dispatch_cb_print(u_char *, const struct wtap_pkthdr *, int,
117     union wtap_pseudo_header *, const u_char *);
118 static gchar *col_info(frame_data *, gint);
119
120 packet_info  pi;
121 capture_file cfile;
122 FILE        *data_out_file = NULL;
123 guint        main_ctx, file_ctx;
124 ts_type timestamp_type = RELATIVE;
125
126 static void 
127 print_usage(void)
128 {
129   int i;
130
131   fprintf(stderr, "This is GNU t%s %s, compiled with %s\n", PACKAGE,
132           VERSION, comp_info_str);
133 #ifdef HAVE_LIBPCAP
134   fprintf(stderr, "t%s [ -vVh ] [ -c count ] [ -D ] [ -f <capture filter> ]\n", PACKAGE);
135   fprintf(stderr, "\t[ -F <capture file type> ] [ -i interface ] [ -n ]\n");
136   fprintf(stderr, "\t[ -o <preference setting> ] ... [ -r infile ] [ -R <read filter> ]\n");
137   fprintf(stderr, "\t[ -s snaplen ] [ -t <time stamp format> ] [ -w savefile ] [ -x ]\n");
138 #else
139   fprintf(stderr, "t%s [ -vVh ] [ -D ] [ -F <capture file type> ] [ -n ]\n", PACKAGE);
140   fprintf(stderr, "\t[ -o <preference setting> ] ... [ -r infile ] [ -R <read filter> ]\n");
141   fprintf(stderr, "\t[ -t <time stamp format> ] [ -w savefile ] [ -x ]\n");
142 #endif
143   fprintf(stderr, "Valid file type arguments to the \"-F\" flag:\n");
144   for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
145     if (wtap_dump_can_open(i))
146       fprintf(stderr, "\t%s - %s\n",
147         wtap_file_type_short_string(i), wtap_file_type_string(i));
148   }
149   fprintf(stderr, "\tdefault is libpcap\n");
150 }
151
152 int
153 main(int argc, char *argv[])
154 {
155   int                  opt, i;
156   extern char         *optarg;
157   gboolean             arg_error = FALSE;
158 #ifdef HAVE_LIBPCAP
159 #ifdef WIN32
160   char pcap_version[] = "0.4a6";
161 #else
162   extern char          pcap_version[];
163 #endif
164 #endif
165   char                *gpf_path, *pf_path;
166   int                  gpf_open_errno, pf_open_errno;
167   int                  err;
168 #ifdef HAVE_LIBPCAP
169   gboolean             capture_filter_specified = FALSE;
170   int                  packet_count = 0;
171   GList               *if_list;
172   gchar                err_str[PCAP_ERRBUF_SIZE];
173 #else
174   gboolean             capture_option_specified = FALSE;
175 #endif
176   int                 out_file_type = WTAP_FILE_PCAP;
177   gchar               *cf_name = NULL, *rfilter = NULL;
178   dfilter             *rfcode = NULL;
179   e_prefs             *prefs;
180
181   /* Register all dissectors; we must do this before checking for the
182      "-G" flag, as the "-G" flag dumps a list of fields registered
183      by the dissectors, and we must do it before we read the preferences,
184      in case any dissectors register preferences. */
185   dissect_init();
186
187   /* Now register the preferences for any non-dissector modules.
188      We must do that before we read the preferences as well. */
189   prefs_register_modules();
190
191   /* If invoked with the "-G" flag, we dump out a glossary of
192      display filter symbols.
193
194      We do this here to mirror what happens in the GTK+ version, although
195      it's not necessary here. */
196   if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
197     proto_registrar_dump();
198     exit(0);
199   }
200
201   /* Set the C-language locale to the native environment. */
202   setlocale(LC_ALL, "");
203
204   prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
205   if (gpf_path != NULL) {
206     fprintf(stderr, "Can't open global preferences file \"%s\": %s.\n", pf_path,
207         strerror(gpf_open_errno));
208   }
209   if (pf_path != NULL) {
210     fprintf(stderr, "Can't open your preferences file \"%s\": %s.\n", pf_path,
211         strerror(pf_open_errno));
212   }
213     
214   /* Initialize the capture file struct */
215   cfile.plist           = NULL;
216   cfile.plist_end               = NULL;
217   cfile.wth             = NULL;
218   cfile.filename                = NULL;
219   cfile.user_saved              = FALSE;
220   cfile.is_tempfile     = FALSE;
221   cfile.rfcode          = NULL;
222   cfile.dfilter         = NULL;
223   cfile.dfcode          = NULL;
224 #ifdef HAVE_LIBPCAP
225   cfile.cfilter         = g_strdup("");
226 #endif
227   cfile.iface           = NULL;
228   cfile.save_file               = NULL;
229   cfile.save_file_fd    = -1;
230   cfile.snap            = WTAP_MAX_PACKET_SIZE;
231   cfile.count           = 0;
232   cfile.cinfo.num_cols  = prefs->num_cols;
233   cfile.cinfo.col_fmt      = (gint *) g_malloc(sizeof(gint) * cfile.cinfo.num_cols);
234   cfile.cinfo.fmt_matx  = (gboolean **) g_malloc(sizeof(gboolean *) * cfile.cinfo.num_cols);
235   cfile.cinfo.col_width = (gint *) g_malloc(sizeof(gint) * cfile.cinfo.num_cols);
236   cfile.cinfo.col_title    = (gchar **) g_malloc(sizeof(gchar *) * cfile.cinfo.num_cols);
237   cfile.cinfo.col_data  = (gchar **) g_malloc(sizeof(gchar *) * cfile.cinfo.num_cols);
238
239   /* Assemble the compile-time options */
240   snprintf(comp_info_str, 256,
241 #ifdef GTK_MAJOR_VERSION
242     "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
243     GTK_MICRO_VERSION,
244 #else
245     "GTK+ (version unknown), %s%s, %s%s, %s%s",
246 #endif
247
248 #ifdef HAVE_LIBPCAP
249    "with libpcap ", pcap_version,
250 #else
251    "without libpcap", "",
252 #endif
253
254 #ifdef HAVE_LIBZ
255 #ifdef ZLIB_VERSION
256    "with libz ", ZLIB_VERSION,
257 #else /* ZLIB_VERSION */
258    "with libz ", "(version unknown)",
259 #endif /* ZLIB_VERSION */
260 #else /* HAVE_LIBZ */
261    "without libz", "",
262 #endif /* HAVE_LIBZ */
263
264 /* Oh, this is pretty */
265 #if defined(HAVE_UCD_SNMP_SNMP_H)
266 #ifdef HAVE_UCD_SNMP_VERSION_H
267    "with UCD SNMP ", VersionInfo
268 #else /* HAVE_UCD_SNMP_VERSION_H */
269    "with UCD SNMP ", "(version unknown)"
270 #endif /* HAVE_UCD_SNMP_VERSION_H */
271 #elif defined(HAVE_SNMP_SNMP_H)
272 #ifdef HAVE_SNMP_VERSION_H
273    "with CMU SNMP ", snmp_Version()
274 #else /* HAVE_SNMP_VERSION_H */
275    "with CMU SNMP ", "(version unknown)"
276 #endif /* HAVE_SNMP_VERSION_H */
277 #else /* no SNMP */
278    "without SNMP", ""
279 #endif
280    );
281     
282   /* Now get our args */
283   while ((opt = getopt(argc, argv, "c:Df:F:hi:no:r:R:s:t:vw:Vx")) != EOF) {
284     switch (opt) {
285       case 'c':        /* Capture xxx packets */
286 #ifdef HAVE_LIBPCAP
287         packet_count = atoi(optarg);
288 #else
289         capture_option_specified = TRUE;
290         arg_error = TRUE;
291 #endif
292         break;
293       case 'D':        /* Turn off DSCP printing */
294         g_ip_dscp_actif = FALSE;
295         break;
296       case 'f':
297 #ifdef HAVE_LIBPCAP
298         capture_filter_specified = TRUE;
299         cfile.cfilter = g_strdup(optarg);
300 #else
301         capture_option_specified = TRUE;
302         arg_error = TRUE;
303 #endif
304         break;
305       case 'F':
306         out_file_type = wtap_short_string_to_file_type(optarg);
307         if (out_file_type < 0) {
308           fprintf(stderr, "tethereal: \"%s\" is not a valid capture file type\n",
309                         optarg);
310           exit(1);
311         }
312         break;
313       case 'h':        /* Print help and exit */
314         print_usage();
315         exit(0);
316         break;
317       case 'i':        /* Use interface xxx */
318 #ifdef HAVE_LIBPCAP
319         cfile.iface = g_strdup(optarg);
320 #else
321         capture_option_specified = TRUE;
322         arg_error = TRUE;
323 #endif
324         break;
325       case 'n':        /* No name resolution */
326         g_resolving_actif = 0;
327         break;
328       case 'o':        /* Override preference from command line */
329         switch (prefs_set_pref(optarg)) {
330
331         case PREFS_SET_SYNTAX_ERR:
332           fprintf(stderr, "tethereal: Invalid -o flag \"%s\"\n", optarg);
333           exit(1);
334           break;
335
336         case PREFS_SET_NO_SUCH_PREF:
337           fprintf(stderr, "tethereal: -o flag \"%s\" specifies unknown preference\n",
338                         optarg);
339           exit(1);
340           break;
341         }
342         break;
343       case 'r':        /* Read capture file xxx */
344         cf_name = g_strdup(optarg);
345         break;
346       case 'R':        /* Read file filter */
347         rfilter = optarg;
348         break;
349       case 's':        /* Set the snapshot (capture) length */
350 #ifdef HAVE_LIBPCAP
351         cfile.snap = atoi(optarg);
352 #else
353         capture_option_specified = TRUE;
354         arg_error = TRUE;
355 #endif
356         break;
357       case 't':        /* Time stamp type */
358         if (strcmp(optarg, "r") == 0)
359           timestamp_type = RELATIVE;
360         else if (strcmp(optarg, "a") == 0)
361           timestamp_type = ABSOLUTE;
362         else if (strcmp(optarg, "d") == 0)
363           timestamp_type = DELTA;
364         else {
365           fprintf(stderr, "tethereal: Invalid time stamp type \"%s\"\n",
366             optarg);
367           fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
368           fprintf(stderr, "or \"d\" for delta.\n");
369           exit(1);
370         }
371         break;
372       case 'v':        /* Show version and exit */
373         printf("t%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
374         exit(0);
375         break;
376       case 'w':        /* Write to capture file xxx */
377         cfile.save_file = g_strdup(optarg);
378         break;
379       case 'V':        /* Verbose */
380         verbose = TRUE;
381         break;
382       case 'x':        /* Print packet data in hex (and ASCII) */
383         print_hex = TRUE;
384         break;
385     }
386   }
387   
388   /* If no capture filter or read filter has been specified, and there are
389      still command-line arguments, treat them as the tokens of a capture
390      filter (if no "-r" flag was specified) or a read filter (if a "-r"
391      flag was specified. */
392   if (optind < argc) {
393     if (cf_name != NULL) {
394       if (rfilter != NULL) {
395         fprintf(stderr,
396 "tethereal: Read filters were specified both with \"-R\" and with additional command-line arguments\n");
397         exit(2);
398       }
399       rfilter = get_args_as_string(argc, argv, optind);
400     } else {
401 #ifdef HAVE_LIBPCAP
402       if (capture_filter_specified) {
403         fprintf(stderr,
404 "tethereal: Capture filters were specified both with \"-f\" and with additional command-line arguments\n");
405         exit(2);
406       }
407       cfile.cfilter = get_args_as_string(argc, argv, optind);
408 #else
409       capture_option_specified = TRUE;
410 #endif
411     }
412   }
413
414 #ifndef HAVE_LIBPCAP
415   if (capture_option_specified)
416     fprintf(stderr, "This version of Tethereal was not built with support for capturing packets.\n");
417 #endif
418   if (arg_error)
419     print_usage();
420
421   /* Build the column format array */  
422   for (i = 0; i < cfile.cinfo.num_cols; i++) {
423     cfile.cinfo.col_fmt[i] = get_column_format(i);
424     cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
425     cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
426       NUM_COL_FMTS);
427     get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
428     if (cfile.cinfo.col_fmt[i] == COL_INFO)
429       cfile.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
430     else
431       cfile.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
432   }
433
434   if (cfile.snap < 1)
435     cfile.snap = WTAP_MAX_PACKET_SIZE;
436   else if (cfile.snap < MIN_PACKET_SIZE)
437     cfile.snap = MIN_PACKET_SIZE;
438   
439   if (rfilter != NULL) {
440     if (dfilter_compile(rfilter, &rfcode) != 0) {
441       fprintf(stderr, "tethereal: %s\n", dfilter_error_msg);
442       dissect_cleanup();
443       exit(2);
444     }
445   }
446   cfile.rfcode = rfcode;
447   if (cf_name) {
448     err = open_cap_file(cf_name, FALSE, &cfile);
449     if (err != 0) {
450       dissect_cleanup();
451       exit(2);
452     }
453     err = load_cap_file(&cfile, out_file_type);
454     if (err != 0) {
455       dissect_cleanup();
456       exit(2);
457     }
458     cf_name[0] = '\0';
459   } else {
460     /* No capture file specified, so we're supposed to do a live capture;
461        do we have support for live captures? */
462 #ifdef HAVE_LIBPCAP
463     /* Yes; did the user specify an interface to use? */
464     if (cfile.iface == NULL) {
465         /* No - pick the first one from the list of interfaces. */
466         if_list = get_interface_list(&err, err_str);
467         if (if_list == NULL) {
468             switch (err) {
469
470             case CANT_GET_INTERFACE_LIST:
471                 fprintf(stderr, "tethereal: Can't get list of interfaces: %s\n",
472                         err_str);
473                 break;
474
475             case NO_INTERFACES_FOUND:
476                 fprintf(stderr, "tethereal: There are no interfaces on which a capture can be done\n");
477                 break;
478             }
479             exit(2);
480         }
481         cfile.iface = g_strdup(if_list->data);  /* first interface */
482         free_interface_list(if_list);
483     }
484     capture(packet_count, out_file_type);
485 #else
486     /* No - complain. */
487     fprintf(stderr, "This version of Tethereal was not built with support for capturing packets.\n");
488     exit(2);
489 #endif
490   }
491
492   dissect_cleanup();
493
494   exit(0);
495 }
496
497 #ifdef HAVE_LIBPCAP
498 /* Do the low-level work of a capture.
499    Returns TRUE if it succeeds, FALSE otherwise. */
500 static int
501 capture(int packet_count, int out_file_type)
502 {
503   gchar       err_str[PCAP_ERRBUF_SIZE];
504   bpf_u_int32 netnum, netmask;
505   void        (*oldhandler)(int);
506   int         err, inpkts;
507   char        errmsg[1024+1];
508
509   /* Initialize the table of conversations. */
510   conversation_init();
511
512   /* Initialize protocol-specific variables */
513   init_all_protocols();
514
515   ld.linktype       = WTAP_ENCAP_UNKNOWN;
516   ld.pdh            = NULL;
517
518   /* Open the network interface to capture from it. */
519   ld.pch = pcap_open_live(cfile.iface, cfile.snap, 1, 1000, err_str);
520
521   if (ld.pch == NULL) {
522     /* Well, we couldn't start the capture.
523        If this is a child process that does the capturing in sync
524        mode or fork mode, it shouldn't do any UI stuff until we pop up the
525        capture-progress window, and, since we couldn't start the
526        capture, we haven't popped it up. */
527     snprintf(errmsg, sizeof errmsg,
528       "The capture session could not be initiated (%s).\n"
529       "Please check to make sure you have sufficient permissions, and that\n"
530       "you have the proper interface specified.", err_str);
531     goto error;
532   }
533
534   if (cfile.cfilter) {
535     /* A capture filter was specified; set it up. */
536     if (pcap_lookupnet (cfile.iface, &netnum, &netmask, err_str) < 0) {
537       snprintf(errmsg, sizeof errmsg,
538         "Can't use filter:  Couldn't obtain netmask info (%s).", err_str);
539       goto error;
540     }
541     if (pcap_compile(ld.pch, &cfile.fcode, cfile.cfilter, 1, netmask) < 0) {
542       snprintf(errmsg, sizeof errmsg, "Unable to parse filter string (%s).",
543         pcap_geterr(ld.pch));
544       goto error;
545     }
546     if (pcap_setfilter(ld.pch, &cfile.fcode) < 0) {
547       snprintf(errmsg, sizeof errmsg, "Can't install filter (%s).",
548         pcap_geterr(ld.pch));
549       goto error;
550     }
551   }
552
553   ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_datalink(ld.pch));
554   if (cfile.save_file != NULL) {
555     /* Set up to write to the capture file. */
556     if (ld.linktype == WTAP_ENCAP_UNKNOWN) {
557       strcpy(errmsg, "The network you're capturing from is of a type"
558                " that Tethereal doesn't support.");
559       goto error;
560     }
561     ld.pdh = wtap_dump_open(cfile.save_file, out_file_type,
562                 ld.linktype, pcap_snapshot(ld.pch), &err);
563
564     if (ld.pdh == NULL) {
565       /* We couldn't set up to write to the capture file. */
566       switch (err) {
567
568       case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
569         strcpy(errmsg, "Tethereal does not support writing capture files in that format.");
570         break;
571
572       case WTAP_ERR_UNSUPPORTED_ENCAP:
573       case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
574         strcpy(errmsg, "Tethereal cannot save this capture in that format.");
575         break;
576
577       case WTAP_ERR_CANT_OPEN:
578         strcpy(errmsg, "The file to which the capture would be written"
579                  " couldn't be created for some unknown reason.");
580         break;
581
582       case WTAP_ERR_SHORT_WRITE:
583         strcpy(errmsg, "A full header couldn't be written to the file"
584                  " to which the capture would be written.");
585         break;
586
587       default:
588         if (err < 0) {
589           sprintf(errmsg, "The file to which the capture would be"
590                        " written (\"%s\") could not be opened: Error %d.",
591                         cfile.save_file, err);
592         } else {
593           sprintf(errmsg, "The file to which the capture would be"
594                        " written (\"%s\") could not be opened: %s.",
595                         cfile.save_file, strerror(err));
596         }
597         break;
598       }
599       goto error;
600     }
601   }
602
603   /* Catch SIGINT and SIGTERM and, if we get either of them, clean up
604      and exit.
605      XXX - deal with signal semantics on various platforms.  Or just
606      use "sigaction()" and be done with it? */
607   signal(SIGTERM, capture_cleanup);
608   signal(SIGINT, capture_cleanup);
609 #if !defined(WIN32)
610   if ((oldhandler = signal(SIGHUP, capture_cleanup)) != SIG_DFL)
611     signal(SIGHUP, oldhandler);
612 #endif
613
614   /* Let the user know what interface was chosen. */
615   printf("Capturing on %s\n", cfile.iface);
616
617   inpkts = pcap_loop(ld.pch, packet_count, capture_pcap_cb, (u_char *) &ld);
618   pcap_close(ld.pch);
619
620   return TRUE;
621
622 error:
623   g_free(cfile.save_file);
624   cfile.save_file = NULL;
625   fprintf(stderr, "tethereal: %s\n", errmsg);
626   if (ld.pch != NULL)
627     pcap_close(ld.pch);
628
629   return FALSE;
630 }
631
632 static void
633 capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
634   const u_char *pd)
635 {
636   struct wtap_pkthdr whdr;
637   loop_data *ld = (loop_data *) user;
638   cb_args_t args;
639
640   whdr.ts.tv_sec = phdr->ts.tv_sec;
641   whdr.ts.tv_usec = phdr->ts.tv_usec;
642   whdr.caplen = phdr->caplen;
643   whdr.len = phdr->len;
644   whdr.pkt_encap = ld->linktype;
645
646   args.cf = &cfile;
647   args.pdh = ld->pdh;
648   if (ld->pdh) {
649     wtap_dispatch_cb_write((u_char *)&args, &whdr, 0, NULL, pd);
650     cfile.count++;
651     printf("\r%u ", cfile.count);
652     fflush(stdout);
653   } else {
654     wtap_dispatch_cb_print((u_char *)&args, &whdr, 0, NULL, pd);
655   }
656 }
657
658 static void
659 capture_cleanup(int signum)
660 {
661   int err;
662
663   printf("\n");
664   pcap_close(ld.pch);
665   if (ld.pdh != NULL)
666     wtap_dump_close(ld.pdh, &err);
667   /* XXX - complain if this fails */
668   exit(0);
669 }
670 #endif /* HAVE_LIBPCAP */
671
672 static int
673 load_cap_file(capture_file *cf, int out_file_type)
674 {
675   gint         linktype;
676   wtap_dumper *pdh;
677   int          err;
678   int          success;
679   cb_args_t    args;
680
681   linktype = wtap_file_encap(cf->wth);
682   if (cf->save_file != NULL) {
683     /* Set up to write to the capture file. */
684     pdh = wtap_dump_open(cf->save_file, out_file_type,
685                 linktype, wtap_snapshot_length(cf->wth), &err);
686
687     if (pdh == NULL) {
688       /* We couldn't set up to write to the capture file. */
689       switch (err) {
690
691       case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
692         fprintf(stderr,
693                 "tethereal: Capture files can't be written in that format.\n");
694         break;
695
696       case WTAP_ERR_UNSUPPORTED_ENCAP:
697       case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
698         fprintf(stderr,
699 "tethereal: The capture file being read cannot be written in that format.\n");
700         break;
701
702       case WTAP_ERR_CANT_OPEN:
703         fprintf(stderr,
704 "tethereal: The file \"%s\" couldn't be created for some unknown reason.\n",
705                  cf->save_file);
706         break;
707
708       case WTAP_ERR_SHORT_WRITE:
709         fprintf(stderr,
710 "tethereal: A full header couldn't be written to the file \"%s\".\n",
711                 cf->save_file);
712         break;
713
714       default:
715         if (err < 0) {
716           fprintf(stderr,
717                 "tethereal: The file \"%s\" could not be opened: Error %d.\n",
718                 cf->save_file, err);
719         } else {
720           fprintf(stderr,
721                 "tethereal: The file \"%s\" could not be opened: %s\n.",
722                 cf->save_file, strerror(err));
723         }
724         break;
725       }
726       goto out;
727     }
728     args.cf = cf;
729     args.pdh = pdh;
730     success = wtap_loop(cf->wth, 0, wtap_dispatch_cb_write, (u_char *) &args,
731                         &err);
732   } else {
733     args.cf = cf;
734     args.pdh = NULL;
735     success = wtap_loop(cf->wth, 0, wtap_dispatch_cb_print, (u_char *) &args,
736                         &err);
737   }
738   if (!success) {
739     /* Print up a message box noting that the read failed somewhere along
740        the line. */
741     switch (err) {
742
743     case WTAP_ERR_UNSUPPORTED_ENCAP:
744       fprintf(stderr,
745 "tethereal: The capture file is for a network type that Tethereal doesn't support.\n");
746       break;
747
748     case WTAP_ERR_CANT_READ:
749       fprintf(stderr,
750 "tethereal: An attempt to read from the file failed for some unknown reason.\n");
751       break;
752
753     case WTAP_ERR_SHORT_READ:
754       fprintf(stderr,
755 "tethereal: The capture file appears to have been cut short in the middle of a packet.\n");
756       break;
757
758     case WTAP_ERR_BAD_RECORD:
759       fprintf(stderr,
760 "tethereal: The capture file appears to be damaged or corrupt.\n");
761       break;
762
763     default:
764       fprintf(stderr,
765 "tethereal: An error occurred while reading the capture file: %s.\n",
766         wtap_strerror(err));
767       break;
768     }
769   }
770
771 out:
772   wtap_close(cf->wth);
773   cf->wth = NULL;
774
775   return err;
776 }
777
778 static void
779 fill_in_fdata(frame_data *fdata, capture_file *cf,
780         const struct wtap_pkthdr *phdr,
781         const union wtap_pseudo_header *pseudo_header, int offset)
782 {
783   int i;
784
785   fdata->next = NULL;
786   fdata->prev = NULL;
787   fdata->pkt_len  = phdr->len;
788   fdata->cap_len  = phdr->caplen;
789   fdata->file_off = offset;
790   fdata->lnk_t = phdr->pkt_encap;
791   fdata->abs_secs  = phdr->ts.tv_sec;
792   fdata->abs_usecs = phdr->ts.tv_usec;
793   fdata->flags.encoding = CHAR_ASCII;
794   fdata->flags.visited = 0;
795   fdata->cinfo = NULL;
796
797   fdata->num = cf->count;
798
799   /* If we don't have the time stamp of the first packet in the
800      capture, it's because this is the first packet.  Save the time
801      stamp of this packet as the time stamp of the first packet. */
802   if (!firstsec && !firstusec) {
803     firstsec  = fdata->abs_secs;
804     firstusec = fdata->abs_usecs;
805   }
806
807   /* Get the time elapsed between the first packet and this packet. */
808   cf->esec = fdata->abs_secs - firstsec;
809   if (firstusec <= fdata->abs_usecs) {
810     cf->eusec = fdata->abs_usecs - firstusec;
811   } else {
812     cf->eusec = (fdata->abs_usecs + 1000000) - firstusec;
813     cf->esec--;
814   }
815   
816   /* If we don't have the time stamp of the previous displayed packet,
817      it's because this is the first displayed packet.  Save the time
818      stamp of this packet as the time stamp of the previous displayed
819      packet. */
820   if (!prevsec && !prevusec) {
821     prevsec  = fdata->abs_secs;
822     prevusec = fdata->abs_usecs;
823   }
824
825   /* Get the time elapsed between the first packet and this packet. */
826   fdata->rel_secs = cf->esec;
827   fdata->rel_usecs = cf->eusec;
828   
829   /* Get the time elapsed between the previous displayed packet and
830      this packet. */
831   fdata->del_secs = fdata->abs_secs - prevsec;
832   if (prevusec <= fdata->abs_usecs) {
833     fdata->del_usecs = fdata->abs_usecs - prevusec;
834   } else {
835     fdata->del_usecs = (fdata->abs_usecs + 1000000) - prevusec;
836     fdata->del_secs--;
837   }
838   prevsec = fdata->abs_secs;
839   prevusec = fdata->abs_usecs;
840
841   fdata->cinfo = &cf->cinfo;
842   for (i = 0; i < fdata->cinfo->num_cols; i++) {
843     fdata->cinfo->col_data[i][0] = '\0';
844   }
845 }
846
847 static void
848 wtap_dispatch_cb_write(u_char *user, const struct wtap_pkthdr *phdr, int offset,
849   union wtap_pseudo_header *pseudo_header, const u_char *buf)
850 {
851   cb_args_t    *args = (cb_args_t *) user;
852   capture_file *cf = args->cf;
853   wtap_dumper  *pdh = args->pdh;
854   frame_data    fdata;
855   proto_tree   *protocol_tree;
856   int           err;
857   gboolean      passed;
858
859   cf->count++;
860   if (cf->rfcode) {
861     fill_in_fdata(&fdata, cf, phdr, pseudo_header, offset);
862     protocol_tree = proto_tree_create_root();
863     dissect_packet(pseudo_header, buf, &fdata, protocol_tree);
864     passed = dfilter_apply(cf->rfcode, protocol_tree, buf, fdata.cap_len);
865   } else {
866     protocol_tree = NULL;
867     passed = TRUE;
868   }
869   if (passed) {
870     /* XXX - do something if this fails */
871     wtap_dump(pdh, phdr, pseudo_header, buf, &err);
872   }
873   if (protocol_tree != NULL)
874     proto_tree_free(protocol_tree);
875 }
876
877 static void
878 wtap_dispatch_cb_print(u_char *user, const struct wtap_pkthdr *phdr, int offset,
879   union wtap_pseudo_header *pseudo_header, const u_char *buf)
880 {
881   cb_args_t    *args = (cb_args_t *) user;
882   capture_file *cf = args->cf;
883   frame_data    fdata;
884   proto_tree   *protocol_tree;
885   gboolean      passed;
886   print_args_t print_args;
887
888   cf->count++;
889
890   /* The protocol tree will be "visible", i.e., printed, only if we're
891      not printing a summary. */
892   proto_tree_is_visible = verbose;
893
894   fill_in_fdata(&fdata, cf, phdr, pseudo_header, offset);
895
896   passed = TRUE;
897   if (cf->rfcode || verbose)
898     protocol_tree = proto_tree_create_root();
899   else
900     protocol_tree = NULL;
901   dissect_packet(pseudo_header, buf, &fdata, protocol_tree);
902   if (cf->rfcode)
903     passed = dfilter_apply(cf->rfcode, protocol_tree, buf, fdata.cap_len);
904   if (passed) {
905     /* The packet passed the read filter. */
906     if (verbose) {
907       /* Print the information in the protocol tree. */
908       print_args.to_file = TRUE;
909       print_args.format = PR_FMT_TEXT;
910       print_args.print_summary = FALSE;
911       print_args.print_hex = print_hex;
912       print_args.expand_all = TRUE;
913       proto_tree_print(FALSE, &print_args, (GNode *)protocol_tree,
914                         buf, &fdata, stdout);
915       if (!print_hex) {
916         /* "print_hex_data()" will put out a leading blank line, as well
917            as a trailing one; print one here, to separate the packets,
918            only if "print_hex_data()" won't be called. */
919         printf("\n");
920       }
921     } else {
922       /* Just fill in the columns. */
923       fill_in_columns(&fdata);
924       if (cf->iface == NULL) {
925          printf("%3s %10s %12s -> %-12s %s %s\n",
926                   col_info(&fdata, COL_NUMBER),
927                   col_info(&fdata, COL_CLS_TIME),
928                   col_info(&fdata, COL_DEF_SRC),
929                   col_info(&fdata, COL_DEF_DST),
930                   col_info(&fdata, COL_PROTOCOL),
931                   col_info(&fdata, COL_INFO));
932       } else {
933         printf("%12s -> %-12s %s %s\n",
934                   col_info(&fdata, COL_DEF_SRC),
935                   col_info(&fdata, COL_DEF_DST),
936                   col_info(&fdata, COL_PROTOCOL),
937                   col_info(&fdata, COL_INFO));
938       }
939     }
940     if (print_hex) {
941       print_hex_data(stdout, print_args.format, buf,
942                         fdata.cap_len, fdata.flags.encoding);
943       printf("\n");
944     }
945     fdata.cinfo = NULL;
946   }
947   if (protocol_tree != NULL)
948     proto_tree_free(protocol_tree);
949
950   proto_tree_is_visible = FALSE;
951 }
952
953 char *
954 file_open_error_message(int err, int for_writing)
955 {
956   char *errmsg;
957   static char errmsg_errno[1024+1];
958
959   switch (err) {
960
961   case WTAP_ERR_NOT_REGULAR_FILE:
962     errmsg = "The file \"%s\" is invalid.";
963     break;
964
965   case WTAP_ERR_FILE_UNKNOWN_FORMAT:
966   case WTAP_ERR_UNSUPPORTED:
967     /* Seen only when opening a capture file for reading. */
968     errmsg = "The file \"%s\" is not a capture file in a format Tethereal understands.";
969     break;
970
971   case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
972     /* Seen only when opening a capture file for writing. */
973     errmsg = "Tethereal does not support writing capture files in that format.";
974     break;
975
976   case WTAP_ERR_UNSUPPORTED_ENCAP:
977   case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
978     if (for_writing)
979       errmsg = "Tethereal cannot save this capture in that format.";
980     else
981       errmsg = "The file \"%s\" is a capture for a network type that Tethereal doesn't support.";
982     break;
983
984   case WTAP_ERR_BAD_RECORD:
985     errmsg = "The file \"%s\" appears to be damaged or corrupt.";
986     break;
987
988   case WTAP_ERR_CANT_OPEN:
989     if (for_writing)
990       errmsg = "The file \"%s\" could not be created for some unknown reason.";
991     else
992       errmsg = "The file \"%s\" could not be opened for some unknown reason.";
993     break;
994
995   case WTAP_ERR_SHORT_READ:
996     errmsg = "The file \"%s\" appears to have been cut short"
997              " in the middle of a packet.";
998     break;
999
1000   case WTAP_ERR_SHORT_WRITE:
1001     errmsg = "A full header couldn't be written to the file \"%s\".";
1002     break;
1003
1004   case ENOENT:
1005     if (for_writing)
1006       errmsg = "The path to the file \"%s\" does not exist.";
1007     else
1008       errmsg = "The file \"%s\" does not exist.";
1009     break;
1010
1011   case EACCES:
1012     if (for_writing)
1013       errmsg = "You do not have permission to create or write to the file \"%s\".";
1014     else
1015       errmsg = "You do not have permission to read the file \"%s\".";
1016     break;
1017
1018   default:
1019     sprintf(errmsg_errno, "The file \"%%s\" could not be opened: %s.",
1020                                 wtap_strerror(err));
1021     errmsg = errmsg_errno;
1022     break;
1023   }
1024   return errmsg;
1025 }
1026
1027 int
1028 open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
1029 {
1030   wtap       *wth;
1031   int         err;
1032   FILE_T      fh;
1033   int         fd;
1034   struct stat cf_stat;
1035   char        err_msg[2048+1];
1036
1037   wth = wtap_open_offline(fname, &err, FALSE);
1038   if (wth == NULL)
1039     goto fail;
1040
1041   /* Find the size of the file. */
1042   fh = wtap_file(wth);
1043   fd = wtap_fd(wth);
1044   if (fstat(fd, &cf_stat) < 0) {
1045     err = errno;
1046     wtap_close(wth);
1047     goto fail;
1048   }
1049
1050   /* The open succeeded.  Fill in the information for this file. */
1051
1052   /* Initialize the table of conversations. */
1053   conversation_init();
1054
1055   /* Initialize protocol-specific variables */
1056   init_all_protocols();
1057
1058   cf->wth = wth;
1059   cf->filed = fd;
1060   cf->f_len = cf_stat.st_size;
1061
1062   /* Set the file name because we need it to set the follow stream filter.
1063      XXX - is that still true?  We need it for other reasons, though,
1064      in any case. */
1065   cf->filename = g_strdup(fname);
1066
1067   /* Indicate whether it's a permanent or temporary file. */
1068   cf->is_tempfile = is_tempfile;
1069
1070   /* If it's a temporary capture buffer file, mark it as not saved. */
1071   cf->user_saved = !is_tempfile;
1072
1073   cf->cd_t      = wtap_file_type(cf->wth);
1074   cf->count     = 0;
1075   cf->drops     = 0;
1076   cf->esec      = 0;
1077   cf->eusec     = 0;
1078   cf->snap      = wtap_snapshot_length(cf->wth);
1079   cf->progbar_quantum = 0;
1080   cf->progbar_nextstep = 0;
1081   firstsec = 0, firstusec = 0;
1082   prevsec = 0, prevusec = 0;
1083  
1084   return (0);
1085
1086 fail:
1087   snprintf(err_msg, sizeof err_msg, file_open_error_message(err, FALSE), fname);
1088   fprintf(stderr, "tethereal: %s\n", err_msg);
1089   return (err);
1090 }
1091
1092 /* Get the text in a given column */
1093 static gchar *
1094 col_info(frame_data *fd, gint el) {
1095   int i;
1096   
1097   if (fd->cinfo) {
1098     for (i = 0; i < fd->cinfo->num_cols; i++) {
1099       if (fd->cinfo->fmt_matx[i][el])
1100         return fd->cinfo->col_data[i];
1101     }
1102   }
1103   return NULL;
1104 }