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