Make the Tethereal usage message reflect whether libpcap support was
[obnox/wireshark/wip.git] / tethereal.c
1 /* tethereal.c
2  *
3  * $Id: tethereal.c,v 1.15 2000/01/24 05:13:45 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   ld.linktype       = WTAP_ENCAP_UNKNOWN;
462   ld.pdh            = NULL;
463
464   /* Open the network interface to capture from it. */
465   ld.pch = pcap_open_live(cf.iface, cf.snap, 1, 1000, err_str);
466
467   if (ld.pch == NULL) {
468     /* Well, we couldn't start the capture.
469        If this is a child process that does the capturing in sync
470        mode or fork mode, it shouldn't do any UI stuff until we pop up the
471        capture-progress window, and, since we couldn't start the
472        capture, we haven't popped it up. */
473     snprintf(errmsg, sizeof errmsg,
474       "The capture session could not be initiated (%s).\n"
475       "Please check to make sure you have sufficient permissions, and that\n"
476       "you have the proper interface specified.", err_str);
477     goto error;
478   }
479
480   if (cf.cfilter) {
481     /* A capture filter was specified; set it up. */
482     if (pcap_lookupnet (cf.iface, &netnum, &netmask, err_str) < 0) {
483       snprintf(errmsg, sizeof errmsg,
484         "Can't use filter:  Couldn't obtain netmask info (%s).", err_str);
485       goto error;
486     }
487     if (pcap_compile(ld.pch, &cf.fcode, cf.cfilter, 1, netmask) < 0) {
488       snprintf(errmsg, sizeof errmsg, "Unable to parse filter string (%s).",
489         pcap_geterr(ld.pch));
490       goto error;
491     }
492     if (pcap_setfilter(ld.pch, &cf.fcode) < 0) {
493       snprintf(errmsg, sizeof errmsg, "Can't install filter (%s).",
494         pcap_geterr(ld.pch));
495       goto error;
496     }
497   }
498
499   ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_datalink(ld.pch));
500   if (cf.save_file != NULL) {
501     /* Set up to write to the capture file. */
502     if (ld.linktype == WTAP_ENCAP_UNKNOWN) {
503       strcpy(errmsg, "The network you're capturing from is of a type"
504                " that Ethereal doesn't support.");
505       goto error;
506     }
507     ld.pdh = wtap_dump_open(cf.save_file, out_file_type,
508                 ld.linktype, pcap_snapshot(ld.pch), &err);
509
510     if (ld.pdh == NULL) {
511       /* We couldn't set up to write to the capture file. */
512       switch (err) {
513
514       case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
515         strcpy(errmsg, "Tethereal does not support writing capture files in that format.");
516         break;
517
518       case WTAP_ERR_UNSUPPORTED_ENCAP:
519       case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
520         strcpy(errmsg, "Tethereal cannot save this capture in that format.");
521         break;
522
523       case WTAP_ERR_CANT_OPEN:
524         strcpy(errmsg, "The file to which the capture would be written"
525                  " couldn't be created for some unknown reason.");
526         break;
527
528       case WTAP_ERR_SHORT_WRITE:
529         strcpy(errmsg, "A full header couldn't be written to the file"
530                  " to which the capture would be written.");
531         break;
532
533       default:
534         if (err < 0) {
535           sprintf(errmsg, "The file to which the capture would be"
536                        " written (\"%s\") could not be opened: Error %d.",
537                         cf.save_file, err);
538         } else {
539           sprintf(errmsg, "The file to which the capture would be"
540                        " written (\"%s\") could not be opened: %s.",
541                         cf.save_file, strerror(err));
542         }
543         break;
544       }
545       goto error;
546     }
547   }
548
549   /* Catch SIGINT and SIGTERM and, if we get either of them, clean up
550      and exit.
551      XXX - deal with signal semantics on various platforms.  Or just
552      use "sigaction()" and be done with it? */
553   signal(SIGTERM, capture_cleanup);
554   signal(SIGINT, capture_cleanup);
555   if ((oldhandler = signal(SIGHUP, capture_cleanup)) != SIG_DFL)
556     signal(SIGHUP, oldhandler);
557
558   /* Let the user know what interface was chosen. */
559   printf("Capturing on %s\n", cf.iface);
560
561   inpkts = pcap_loop(ld.pch, packet_count, capture_pcap_cb, (u_char *) &ld);
562   pcap_close(ld.pch);
563
564   return TRUE;
565
566 error:
567   g_free(cf.save_file);
568   cf.save_file = NULL;
569   fprintf(stderr, "tethereal: %s\n", errmsg);
570   if (ld.pch != NULL)
571     pcap_close(ld.pch);
572
573   return FALSE;
574 }
575
576 static void
577 capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
578   const u_char *pd)
579 {
580   struct wtap_pkthdr whdr;
581   loop_data *ld = (loop_data *) user;
582   cb_args_t args;
583
584   whdr.ts = phdr->ts;
585   whdr.caplen = phdr->caplen;
586   whdr.len = phdr->len;
587   whdr.pkt_encap = ld->linktype;
588
589   args.cf = &cf;
590   args.pdh = ld->pdh;
591   if (ld->pdh) {
592     wtap_dispatch_cb_write((u_char *)&args, &whdr, 0, pd);
593     cf.count++;
594     printf("\r%u ", cf.count);
595     fflush(stdout);
596   } else {
597     wtap_dispatch_cb_print((u_char *)&args, &whdr, 0, pd);
598   }
599 }
600
601 static void
602 capture_cleanup(int signum)
603 {
604   int err;
605
606   printf("\n");
607   pcap_close(ld.pch);
608   if (ld.pdh != NULL)
609     wtap_dump_close(ld.pdh, &err);
610   /* XXX - complain if this fails */
611   exit(0);
612 }
613 #endif /* HAVE_LIBPCAP */
614
615 static int
616 load_cap_file(capture_file *cf, int out_file_type)
617 {
618   gint         linktype;
619   wtap_dumper *pdh;
620   int          err;
621   int          success;
622   cb_args_t    args;
623
624   linktype = wtap_file_encap(cf->wth);
625   if (cf->save_file != NULL) {
626     /* Set up to write to the capture file. */
627     pdh = wtap_dump_open(cf->save_file, out_file_type,
628                 linktype, wtap_snapshot_length(cf->wth), &err);
629
630     if (pdh == NULL) {
631       /* We couldn't set up to write to the capture file. */
632       switch (err) {
633
634       case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
635         fprintf(stderr,
636                 "tethereal: Capture files can't be written in that format.\n");
637         break;
638
639       case WTAP_ERR_UNSUPPORTED_ENCAP:
640       case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
641         fprintf(stderr,
642 "tethereal: The capture file being read cannot be written in that format.\n");
643         break;
644
645       case WTAP_ERR_CANT_OPEN:
646         fprintf(stderr,
647 "tethereal: The file \"%s\" couldn't be created for some unknown reason.\n",
648                  cf->save_file);
649         break;
650
651       case WTAP_ERR_SHORT_WRITE:
652         fprintf(stderr,
653 "tethereal: A full header couldn't be written to the file \"%s\".\n",
654                 cf->save_file);
655         break;
656
657       default:
658         if (err < 0) {
659           fprintf(stderr,
660                 "tethereal: The file \"%s\" could not be opened: Error %d.\n",
661                 cf->save_file, err);
662         } else {
663           fprintf(stderr,
664                 "tethereal: The file \"%s\" could not be opened: %s\n.",
665                 cf->save_file, strerror(err));
666         }
667         break;
668       }
669       goto out;
670     }
671     args.cf = cf;
672     args.pdh = pdh;
673     success = wtap_loop(cf->wth, 0, wtap_dispatch_cb_write, (u_char *) &args,
674                         &err);
675   } else {
676     args.cf = cf;
677     args.pdh = NULL;
678     success = wtap_loop(cf->wth, 0, wtap_dispatch_cb_print, (u_char *) &args,
679                         &err);
680   }
681   if (!success) {
682     /* Print up a message box noting that the read failed somewhere along
683        the line. */
684     switch (err) {
685
686     case WTAP_ERR_CANT_READ:
687       fprintf(stderr,
688 "tethereal: An attempt to read from the file failed for some unknown reason.\n");
689       break;
690
691     case WTAP_ERR_SHORT_READ:
692       fprintf(stderr,
693 "tethereal: The capture file appears to have been cut short in the middle of a packet.\n");
694       break;
695
696     case WTAP_ERR_BAD_RECORD:
697       fprintf(stderr,
698 "tethereal: The capture file appears to be damaged or corrupt.\n");
699       break;
700
701     default:
702       fprintf(stderr,
703 "tethereal: An error occurred while reading the capture file: %s.\n",
704         wtap_strerror(err));
705       break;
706     }
707   }
708
709 out:
710   wtap_close(cf->wth);
711   cf->wth = NULL;
712
713   return err;
714 }
715
716 static void
717 fill_in_fdata(frame_data *fdata, capture_file *cf,
718         const struct wtap_pkthdr *phdr, int offset)
719 {
720   int i;
721
722   fdata->next = NULL;
723   fdata->prev = NULL;
724   fdata->pkt_len  = phdr->len;
725   fdata->cap_len  = phdr->caplen;
726   fdata->file_off = offset;
727   fdata->lnk_t = phdr->pkt_encap;
728   fdata->abs_secs  = phdr->ts.tv_sec;
729   fdata->abs_usecs = phdr->ts.tv_usec;
730   fdata->encoding = CHAR_ASCII;
731   fdata->pseudo_header = phdr->pseudo_header;
732   fdata->cinfo = NULL;
733
734   fdata->num = cf->count;
735
736   /* If we don't have the time stamp of the first packet in the
737      capture, it's because this is the first packet.  Save the time
738      stamp of this packet as the time stamp of the first packet. */
739   if (!firstsec && !firstusec) {
740     firstsec  = fdata->abs_secs;
741     firstusec = fdata->abs_usecs;
742   }
743
744   /* Get the time elapsed between the first packet and this packet. */
745   cf->esec = fdata->abs_secs - firstsec;
746   if (firstusec <= fdata->abs_usecs) {
747     cf->eusec = fdata->abs_usecs - firstusec;
748   } else {
749     cf->eusec = (fdata->abs_usecs + 1000000) - firstusec;
750     cf->esec--;
751   }
752   
753   /* If we don't have the time stamp of the previous displayed packet,
754      it's because this is the first displayed packet.  Save the time
755      stamp of this packet as the time stamp of the previous displayed
756      packet. */
757   if (!prevsec && !prevusec) {
758     prevsec  = fdata->abs_secs;
759     prevusec = fdata->abs_usecs;
760   }
761
762   /* Get the time elapsed between the first packet and this packet. */
763   fdata->rel_secs = cf->esec;
764   fdata->rel_usecs = cf->eusec;
765   
766   /* Get the time elapsed between the previous displayed packet and
767      this packet. */
768   fdata->del_secs = fdata->abs_secs - prevsec;
769   if (prevusec <= fdata->abs_usecs) {
770     fdata->del_usecs = fdata->abs_usecs - prevusec;
771   } else {
772     fdata->del_usecs = (fdata->abs_usecs + 1000000) - prevusec;
773     fdata->del_secs--;
774   }
775   prevsec = fdata->abs_secs;
776   prevusec = fdata->abs_usecs;
777
778   fdata->cinfo = &cf->cinfo;
779   for (i = 0; i < fdata->cinfo->num_cols; i++) {
780     fdata->cinfo->col_data[i][0] = '\0';
781   }
782 }
783
784 static void
785 wtap_dispatch_cb_write(u_char *user, const struct wtap_pkthdr *phdr, int offset,
786   const u_char *buf)
787 {
788   cb_args_t    *args = (cb_args_t *) user;
789   capture_file *cf = args->cf;
790   wtap_dumper  *pdh = args->pdh;
791   frame_data    fdata;
792   proto_tree   *protocol_tree;
793   int           err;
794   gboolean      passed;
795
796   cf->count++;
797   if (cf->rfcode) {
798     fill_in_fdata(&fdata, cf, phdr, offset);
799     protocol_tree = proto_tree_create_root();
800     dissect_packet(buf, &fdata, protocol_tree);
801     passed = dfilter_apply(cf->rfcode, protocol_tree, buf);
802   } else {
803     protocol_tree = NULL;
804     passed = TRUE;
805   }
806   if (passed) {
807     /* XXX - do something if this fails */
808     wtap_dump(pdh, phdr, buf, &err);
809   }
810   if (protocol_tree != NULL)
811     proto_tree_free(protocol_tree);
812 }
813
814 static void
815 wtap_dispatch_cb_print(u_char *user, const struct wtap_pkthdr *phdr, int offset,
816   const u_char *buf)
817 {
818   cb_args_t    *args = (cb_args_t *) user;
819   capture_file *cf = args->cf;
820   frame_data    fdata;
821   proto_tree   *protocol_tree;
822   gboolean      passed;
823   print_args_t print_args;
824
825   cf->count++;
826
827   fill_in_fdata(&fdata, cf, phdr, offset);
828
829   passed = TRUE;
830   if (cf->rfcode || verbose)
831     protocol_tree = proto_tree_create_root();
832   else
833     protocol_tree = NULL;
834   dissect_packet(buf, &fdata, protocol_tree);
835   if (cf->rfcode)
836     passed = dfilter_apply(cf->rfcode, protocol_tree, buf);
837   if (passed) {
838     /* The packet passed the read filter. */
839     if (verbose) {
840       /* Print the information in the protocol tree. */
841       print_args.to_file = TRUE;
842       print_args.format = PR_FMT_TEXT;
843       print_args.print_summary = FALSE;
844       print_args.print_hex = print_hex;
845       print_args.expand_all = TRUE;
846       proto_tree_print(FALSE, &print_args, (GNode *)protocol_tree,
847                         buf, &fdata, stdout);
848       if (!print_hex) {
849         /* "print_hex_data()" will put out a leading blank line, as well
850            as a trailing one; print one here, to separate the packets,
851            only if "print_hex_data()" won't be called. */
852         printf("\n");
853       }
854     } else {
855       /* Just fill in the columns. */
856       fill_in_columns(&fdata);
857       if (cf->iface == NULL) {
858          printf("%3s %10s %12s -> %-12s %s %s\n",
859                   col_info(&fdata, COL_NUMBER),
860                   col_info(&fdata, COL_CLS_TIME),
861                   col_info(&fdata, COL_DEF_SRC),
862                   col_info(&fdata, COL_DEF_DST),
863                   col_info(&fdata, COL_PROTOCOL),
864                   col_info(&fdata, COL_INFO));
865       } else {
866         printf("%12s -> %-12s %s %s\n",
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       }
872     }
873     if (print_hex) {
874       print_hex_data(stdout, print_args.format, buf,
875                         fdata.cap_len, fdata.encoding);
876       printf("\n");
877     }
878     fdata.cinfo = NULL;
879   }
880   if (protocol_tree != NULL)
881     proto_tree_free(protocol_tree);
882 }
883
884 char *
885 file_open_error_message(int err, int for_writing)
886 {
887   char *errmsg;
888   static char errmsg_errno[1024+1];
889
890   switch (err) {
891
892   case WTAP_ERR_NOT_REGULAR_FILE:
893     errmsg = "The file \"%s\" is invalid.";
894     break;
895
896   case WTAP_ERR_FILE_UNKNOWN_FORMAT:
897   case WTAP_ERR_UNSUPPORTED:
898     /* Seen only when opening a capture file for reading. */
899     errmsg = "The file \"%s\" is not a capture file in a format Ethereal understands.";
900     break;
901
902   case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
903     /* Seen only when opening a capture file for writing. */
904     errmsg = "Ethereal does not support writing capture files in that format.";
905     break;
906
907   case WTAP_ERR_UNSUPPORTED_ENCAP:
908   case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
909     /* Seen only when opening a capture file for writing. */
910     errmsg = "Ethereal cannot save this capture in that format.";
911     break;
912
913   case WTAP_ERR_BAD_RECORD:
914     errmsg = "The file \"%s\" appears to be damaged or corrupt.";
915     break;
916
917   case WTAP_ERR_CANT_OPEN:
918     if (for_writing)
919       errmsg = "The file \"%s\" could not be created for some unknown reason.";
920     else
921       errmsg = "The file \"%s\" could not be opened for some unknown reason.";
922     break;
923
924   case WTAP_ERR_SHORT_READ:
925     errmsg = "The file \"%s\" appears to have been cut short"
926              " in the middle of a packet.";
927     break;
928
929   case WTAP_ERR_SHORT_WRITE:
930     errmsg = "A full header couldn't be written to the file \"%s\".";
931     break;
932
933   case ENOENT:
934     if (for_writing)
935       errmsg = "The path to the file \"%s\" does not exist.";
936     else
937       errmsg = "The file \"%s\" does not exist.";
938     break;
939
940   case EACCES:
941     if (for_writing)
942       errmsg = "You do not have permission to create or write to the file \"%s\".";
943     else
944       errmsg = "You do not have permission to read the file \"%s\".";
945     break;
946
947   default:
948     sprintf(errmsg_errno, "The file \"%%s\" could not be opened: %s.",
949                                 wtap_strerror(err));
950     errmsg = errmsg_errno;
951     break;
952   }
953   return errmsg;
954 }
955
956 int
957 open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
958 {
959   wtap       *wth;
960   int         err;
961   FILE_T      fh;
962   int         fd;
963   struct stat cf_stat;
964   char        err_msg[2048+1];
965
966   wth = wtap_open_offline(fname, &err);
967   if (wth == NULL)
968     goto fail;
969
970   /* Find the size of the file. */
971   fh = wtap_file(wth);
972   fd = wtap_fd(wth);
973   if (fstat(fd, &cf_stat) < 0) {
974     err = errno;
975     wtap_close(wth);
976     goto fail;
977   }
978
979   /* The open succeeded.  Fill in the information for this file. */
980
981   /* Initialize the table of conversations. */
982   conversation_init();
983
984   /* Initialize protocol-specific variables */
985   init_all_protocols();
986
987   cf->wth = wth;
988   cf->fh = fh;
989   cf->filed = fd;
990   cf->f_len = cf_stat.st_size;
991
992   /* Set the file name because we need it to set the follow stream filter.
993      XXX - is that still true?  We need it for other reasons, though,
994      in any case. */
995   cf->filename = g_strdup(fname);
996
997   /* Indicate whether it's a permanent or temporary file. */
998   cf->is_tempfile = is_tempfile;
999
1000   /* If it's a temporary capture buffer file, mark it as not saved. */
1001   cf->user_saved = !is_tempfile;
1002
1003   cf->cd_t      = wtap_file_type(cf->wth);
1004   cf->count     = 0;
1005   cf->drops     = 0;
1006   cf->esec      = 0;
1007   cf->eusec     = 0;
1008   cf->snap      = wtap_snapshot_length(cf->wth);
1009   cf->update_progbar = FALSE;
1010   cf->progbar_quantum = 0;
1011   cf->progbar_nextstep = 0;
1012   firstsec = 0, firstusec = 0;
1013   prevsec = 0, prevusec = 0;
1014  
1015   return (0);
1016
1017 fail:
1018   snprintf(err_msg, sizeof err_msg, file_open_error_message(err, FALSE), fname);
1019   fprintf(stderr, "tethereal: %s\n", err_msg);
1020   return (err);
1021 }
1022
1023 /* Get the text in a given column */
1024 static gchar *
1025 col_info(frame_data *fd, gint el) {
1026   int i;
1027   
1028   if (fd->cinfo) {
1029     for (i = 0; i < fd->cinfo->num_cols; i++) {
1030       if (fd->cinfo->fmt_matx[i][el])
1031         return fd->cinfo->col_data[i];
1032     }
1033   }
1034   return NULL;
1035 }