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