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