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