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