[GTPv2] Throttling Delay unit values are not the same as the timer values,
[metze/wireshark/wip.git] / capinfos.c
1 /* capinfos.c
2  * Reports capture file information including # of packets, duration, others
3  *
4  * Copyright 2004 Ian Schorr
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 /*
26  * 2009-09-19: jyoung
27  *
28  * New capinfos features
29  *
30  * Continue processing additional files after
31  * a wiretap open failure.  The new -C option
32  * reverts to capinfos' original behavior which
33  * is to cancel any further file processing at
34  * first file open failure.
35  *
36  * Change the behavior of how the default display
37  * of all infos is initiated.  This gets rid of a
38  * special post getopt() argument count test.
39  *
40  * Add new table output format (with related options)
41  * This feature allows outputting the various infos
42  * into a tab delimited text file, or to a comma
43  * separated variables file (*.csv) instead of the
44  * original "long" format.
45  *
46  * 2011-04-05: wmeier
47  * behaviour changed: Upon exit capinfos will return
48  *  an error status if an error occurred at any
49  *  point during "continuous" file processing.
50  *  (Previously a success status was always
51  *   returned if the -C option was not used).
52  *
53
54  */
55
56
57 #include <config.h>
58
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <stdarg.h>
63 #include <locale.h>
64 #include <errno.h>
65
66 #ifdef HAVE_UNISTD_H
67 #include <unistd.h>
68 #endif
69
70 #ifdef HAVE_GETOPT_H
71 #include <getopt.h>
72 #endif
73
74 #include <glib.h>
75
76 #ifdef HAVE_LIBZ
77 #include <zlib.h>     /* to get the libz version number */
78 #endif
79
80 #include <wsutil/crash_info.h>
81 #include <wsutil/filesystem.h>
82 #include <wsutil/privileges.h>
83 #include <wsutil/ws_diag_control.h>
84 #include <wsutil/ws_version_info.h>
85
86 #ifdef HAVE_PLUGINS
87 #include <wsutil/plugins.h>
88 #endif
89
90 #include "wtap.h"
91 #include <wsutil/report_err.h>
92 #include <wsutil/str_util.h>
93 #include <wsutil/file_util.h>
94
95 #ifdef HAVE_LIBGCRYPT
96 #include <wsutil/wsgcrypt.h>
97 #endif
98
99 #ifndef HAVE_GETOPT_LONG
100 #include "wsutil/wsgetopt.h"
101 #endif
102
103 #ifdef _WIN32
104 #include <wsutil/unicode-utils.h>
105 #endif /* _WIN32 */
106
107 /*
108  * By default capinfos now continues processing
109  * the next filename if and when wiretap detects
110  * a problem opening a file.
111  * Use the '-C' option to revert back to original
112  * capinfos behavior which is to abort any
113  * additional file processing at first open file
114  * failure.
115  */
116
117 static gboolean continue_after_wtap_open_offline_failure = TRUE;
118
119 /*
120  * table report variables
121  */
122
123 static gboolean long_report        = TRUE;  /* By default generate long report       */
124 static gchar table_report_header   = TRUE;  /* Generate column header by default     */
125 static gchar field_separator       = '\t';  /* Use TAB as field separator by default */
126 static gchar quote_char            = '\0';  /* Do NOT quote fields by default        */
127 static gboolean machine_readable   = FALSE; /* Display machine-readable numbers      */
128
129 /*
130  * capinfos has the ability to report on a number of
131  * various characteristics ("infos") for each input file.
132  *
133  * By default reporting of all info fields is enabled.
134  *
135  * Optionally the reporting of any specific info field
136  * or combination of info fields can be enabled with
137  * individual options.
138  */
139
140 static gboolean report_all_infos   = TRUE;  /* Report all infos           */
141
142 static gboolean cap_file_type      = TRUE;  /* Report capture type        */
143 static gboolean cap_file_encap     = TRUE;  /* Report encapsulation       */
144 static gboolean cap_snaplen        = TRUE;  /* Packet size limit (snaplen)*/
145 static gboolean cap_packet_count   = TRUE;  /* Report packet count        */
146 static gboolean cap_file_size      = TRUE;  /* Report file size           */
147 static gboolean cap_comment        = TRUE;  /* Display the capture comment */
148
149 static gboolean cap_data_size      = TRUE;  /* Report packet byte size    */
150 static gboolean cap_duration       = TRUE;  /* Report capture duration    */
151 static gboolean cap_start_time     = TRUE;  /* Report capture start time  */
152 static gboolean cap_end_time       = TRUE;  /* Report capture end time    */
153 static gboolean time_as_secs       = FALSE; /* Report time values as raw seconds */
154
155 static gboolean cap_data_rate_byte = TRUE;  /* Report data rate bytes/sec */
156 static gboolean cap_data_rate_bit  = TRUE;  /* Report data rate bites/sec */
157 static gboolean cap_packet_size    = TRUE;  /* Report average packet size */
158 static gboolean cap_packet_rate    = TRUE;  /* Report average packet rate */
159 static gboolean cap_order          = TRUE;  /* Report if packets are in chronological order (True/False) */
160
161 #ifdef HAVE_LIBGCRYPT
162 static gboolean cap_file_hashes    = TRUE;  /* Calculate file hashes */
163 #endif
164
165 #ifdef USE_GOPTION
166 static gboolean cap_help     = FALSE;
167 static gboolean table_report = FALSE;
168
169 static GOptionEntry general_entries[] =
170 {
171   /* General */
172   { "type", 't', 0, G_OPTION_ARG_NONE, &cap_file_type,
173     "display the capture file type", NULL },
174   { "Encapsulation", 'E', 0, G_OPTION_ARG_NONE, &cap_file_encap,
175     "display the capture file encapsulation", NULL },
176 #ifdef HAVE_LIBGCRYPT
177   { "Hash", 'H', 0, G_OPTION_ARG_NONE, &cap_file_hashes,
178     "display the SHA1, RMD160, and MD5 hashes of the file", NULL },
179 #endif /* HAVE_LIBGCRYPT */
180   { "capture-comment", 'k', 0, G_OPTION_ARG_NONE, &cap_comment,
181     "display the capture comment ", NULL },
182   { NULL,'\0',0,G_OPTION_ARG_NONE,NULL,NULL,NULL }
183 };
184 static GOptionEntry size_entries[] =
185 {
186   /* Size */
187   { "packets", 'c', 0, G_OPTION_ARG_NONE, &cap_packet_count,
188     "display the number of packets", NULL },
189   { "size", 's', 0, G_OPTION_ARG_NONE, &cap_file_size,
190     "display the size of the file (in bytes)", NULL },
191   { "tot-len-of-pkts", 'd', 0, G_OPTION_ARG_NONE, &cap_data_size,
192     "display the total length of all packets (in bytes)", NULL },
193   { "snap", 'l', 0, G_OPTION_ARG_NONE, &cap_snaplen,
194     "display the packet size limit (snapshot length)", NULL },
195   { NULL,'\0',0,G_OPTION_ARG_NONE,NULL,NULL,NULL }
196 };
197 static GOptionEntry time_entries[] =
198 {
199   /* Time */
200   { "duration", 'u', 0, G_OPTION_ARG_NONE, &cap_duration,
201     "display the capture duration (in seconds)", NULL },
202   { "start", 'a', 0, G_OPTION_ARG_NONE, &cap_start_time,
203     "display the capture start time", NULL },
204   { "end", 'e', 0, G_OPTION_ARG_NONE, &cap_end_time,
205     "display the capture end time", NULL },
206   { "cron", 'o', 0, G_OPTION_ARG_NONE, &cap_order,
207     "display the capture file chronological status (True/False)", NULL },
208   { "start-end-time-sec", 'S', 0, G_OPTION_ARG_NONE, &time_as_secs,
209     "display start and end times as seconds", NULL },
210   { NULL,'\0',0,G_OPTION_ARG_NONE,NULL,NULL,NULL }
211 };
212
213 static GOptionEntry stats_entries[] =
214 {
215   /* Statistics */
216   { "bytes", 'y', 0, G_OPTION_ARG_NONE, &cap_data_rate_byte,
217     "display average data rate (in bytes/s)", NULL },
218   { "bits", 'i', 0, G_OPTION_ARG_NONE, &cap_data_rate_bit,
219     "display average data rate (in bits/s)", NULL },
220   { "packet-bytes", 'z', 0, G_OPTION_ARG_NONE, &cap_packet_size,
221     "display average packet size (in bytes)", NULL },
222   { "packets", 'x', 0, G_OPTION_ARG_NONE, &cap_packet_rate,
223     "display average packet rate (in packets/s)", NULL },
224   { NULL,'\0',0,G_OPTION_ARG_NONE,NULL,NULL,NULL }
225 };
226
227 static GOptionEntry output_format_entries[] =
228 {
229   /* Output format */
230   { "long", 'L', 0, G_OPTION_ARG_NONE, &long_report,
231     "generate long report (default)", NULL },
232   { "Table", 'T', 0, G_OPTION_ARG_NONE, &table_report,
233     "generate table report", NULL },
234   { "machine-readable", 'M', 0, G_OPTION_ARG_NONE, &machine_readable,
235     "display machine-readable (unabbreviated) values in long reports", NULL },
236   { NULL,'\0',0,G_OPTION_ARG_NONE,NULL,NULL,NULL }
237 };
238
239 static GOptionEntry table_report_entries[] =
240 {
241   /* Table report */
242   { "header-rec", 'R', 0, G_OPTION_ARG_NONE, &table_report_header,
243     "generate header record (default)", NULL },
244   { "no-table", 'r', 0, G_OPTION_ARG_NONE, &table_report_header,
245     "do not generate header record", NULL },
246   { NULL,'\0',0,G_OPTION_ARG_NONE,NULL,NULL,NULL }
247 };
248
249 static GOptionEntry misc_entries[] =
250 {
251   { "helpcompat", 'h', 0, G_OPTION_ARG_NONE, &cap_help,
252     "display help", NULL },
253   { NULL,'\0',0,G_OPTION_ARG_NONE,NULL,NULL,NULL }
254 };
255
256 GOptionContext *ctx;
257 GOptionGroup *general_grp, *size_grp, *time_grp, *stats_grp, *output_grp, *table_report_grp;
258 GError *parse_err = NULL;
259
260 #endif /* USE_GOPTION */
261
262 #ifdef HAVE_LIBGCRYPT
263 #define HASH_SIZE_SHA1   20
264 #define HASH_SIZE_RMD160 20
265 #define HASH_SIZE_MD5    16
266
267 #define HASH_STR_SIZE (41) /* Max hash size * 2 + '\0' */
268 #define HASH_BUF_SIZE (1024 * 1024)
269
270
271 static gchar file_sha1[HASH_STR_SIZE];
272 static gchar file_rmd160[HASH_STR_SIZE];
273 static gchar file_md5[HASH_STR_SIZE];
274
275 #define FILE_HASH_OPT "H"
276 #else
277 #define FILE_HASH_OPT ""
278 #endif /* HAVE_LIBGCRYPT */
279
280 /*
281  * If we have at least two packets with time stamps, and they're not in
282  * order - i.e., the later packet has a time stamp older than the earlier
283  * packet - the time stamps are known not to be in order.
284  *
285  * If every packet has a time stamp, and they're all in order, the time
286  * stamp is known to be in order.
287  *
288  * Otherwise, we have no idea.
289  */
290 typedef enum {
291   IN_ORDER,
292   NOT_IN_ORDER,
293   ORDER_UNKNOWN
294 } order_t;
295
296 typedef struct _capture_info {
297   const char    *filename;
298   guint16        file_type;
299   gboolean       iscompressed;
300   int            file_encap;
301   gint64         filesize;
302   gchar         *comment;
303
304   guint64        packet_bytes;
305   gboolean       times_known;
306   double         start_time;
307   double         stop_time;
308   guint32        packet_count;
309   gboolean       snap_set;                /* If set in capture file header      */
310   guint32        snaplen;                 /* value from the capture file header */
311   guint32        snaplen_min_inferred;    /* If caplen < len for 1 or more rcds */
312   guint32        snaplen_max_inferred;    /*  ...                               */
313   gboolean       drops_known;
314   guint32        drop_count;
315
316   double         duration;
317   double         packet_rate;
318   double         packet_size;
319   double         data_rate;              /* in bytes */
320   gboolean       know_order;
321   order_t        order;
322
323   int           *encap_counts;           /* array of per_packet encap counts; array has one entry per wtap_encap type */
324 } capture_info;
325
326
327 static void
328 enable_all_infos(void)
329 {
330   report_all_infos   = TRUE;
331
332   cap_file_type      = TRUE;
333   cap_file_encap     = TRUE;
334   cap_snaplen        = TRUE;
335   cap_packet_count   = TRUE;
336   cap_file_size      = TRUE;
337   cap_comment        = TRUE;
338
339   cap_data_size      = TRUE;
340   cap_duration       = TRUE;
341   cap_start_time     = TRUE;
342   cap_end_time       = TRUE;
343   cap_order          = TRUE;
344
345   cap_data_rate_byte = TRUE;
346   cap_data_rate_bit  = TRUE;
347   cap_packet_size    = TRUE;
348   cap_packet_rate    = TRUE;
349
350 #ifdef HAVE_LIBGCRYPT
351   cap_file_hashes    = TRUE;
352 #endif /* HAVE_LIBGCRYPT */
353 }
354
355 static void
356 disable_all_infos(void)
357 {
358   report_all_infos   = FALSE;
359
360   cap_file_type      = FALSE;
361   cap_file_encap     = FALSE;
362   cap_snaplen        = FALSE;
363   cap_packet_count   = FALSE;
364   cap_file_size      = FALSE;
365   cap_comment        = FALSE;
366
367   cap_data_size      = FALSE;
368   cap_duration       = FALSE;
369   cap_start_time     = FALSE;
370   cap_end_time       = FALSE;
371   cap_order          = FALSE;
372
373   cap_data_rate_byte = FALSE;
374   cap_data_rate_bit  = FALSE;
375   cap_packet_size    = FALSE;
376   cap_packet_rate    = FALSE;
377
378 #ifdef HAVE_LIBGCRYPT
379   cap_file_hashes    = FALSE;
380 #endif /* HAVE_LIBGCRYPT */
381 }
382
383 static const gchar *
384 order_string(order_t order)
385 {
386   switch (order) {
387
388     case IN_ORDER:
389       return "True";
390
391     case NOT_IN_ORDER:
392       return "False";
393
394     case ORDER_UNKNOWN:
395       return "Unknown";
396
397     default:
398       return "???";  /* "cannot happen" (the next step is "Profit!") */
399   }
400 }
401
402 static gchar *
403 time_string(time_t timer, capture_info *cf_info, gboolean want_lf)
404 {
405   const gchar  *lf = want_lf ? "\n" : "";
406   static gchar  time_string_buf[4+1+2+1+2+1+2+1+2+1+2+1+1];
407   struct tm *ti_tm;
408
409   if (cf_info->times_known && cf_info->packet_count > 0) {
410     if (time_as_secs) {
411       /* XXX - Would it be useful to show sub-second precision? */
412       g_snprintf(time_string_buf, 20, "%lu%s", (unsigned long)timer, lf);
413       return time_string_buf;
414     } else {
415       ti_tm = localtime(&timer);
416       if (ti_tm == NULL) {
417         g_snprintf(time_string_buf, 20, "Not representable%s", lf);
418         return time_string_buf;
419       }
420       g_snprintf(time_string_buf, sizeof time_string_buf,
421              "%04d-%02d-%02d %02d:%02d:%02d%s",
422              ti_tm->tm_year + 1900,
423              ti_tm->tm_mon + 1,
424              ti_tm->tm_mday,
425              ti_tm->tm_hour,
426              ti_tm->tm_min,
427              ti_tm->tm_sec,
428              lf);
429       return time_string_buf;
430     }
431   }
432
433   g_snprintf(time_string_buf, 15, "n/a%s", lf);
434   return time_string_buf;
435 }
436
437 static void print_value(const gchar *text_p1, gint width, const gchar *text_p2, double value) {
438   if (value > 0.0)
439     printf("%s%.*f%s\n", text_p1, width, value, text_p2);
440   else
441     printf("%sn/a\n", text_p1);
442 }
443
444 static void
445 print_stats(const gchar *filename, capture_info *cf_info)
446 {
447   const gchar           *file_type_string, *file_encap_string;
448   time_t                 start_time_t;
449   time_t                 stop_time_t;
450   gchar                 *size_string;
451
452   /* Build printable strings for various stats */
453   file_type_string = wtap_file_type_subtype_string(cf_info->file_type);
454   file_encap_string = wtap_encap_string(cf_info->file_encap);
455   start_time_t = (time_t)cf_info->start_time;
456   stop_time_t = (time_t)cf_info->stop_time;
457
458   if (filename)           printf     ("File name:           %s\n", filename);
459   if (cap_file_type)      printf     ("File type:           %s%s\n",
460       file_type_string,
461       cf_info->iscompressed ? " (gzip compressed)" : "");
462   if (cap_file_encap)     printf     ("File encapsulation:  %s\n", file_encap_string);
463   if (cap_file_encap && (cf_info->file_encap == WTAP_ENCAP_PER_PACKET)) {
464     int i;
465     for (i=0; i<WTAP_NUM_ENCAP_TYPES; i++) {
466       if (cf_info->encap_counts[i] > 0)
467         printf("                       %s\n", wtap_encap_string(i));
468     }
469   }
470   if (cap_snaplen && cf_info->snap_set)
471     printf     ("Packet size limit:   file hdr: %u bytes\n", cf_info->snaplen);
472   else if (cap_snaplen && !cf_info->snap_set)
473     printf     ("Packet size limit:   file hdr: (not set)\n");
474   if (cf_info->snaplen_max_inferred > 0) {
475     if (cf_info->snaplen_min_inferred == cf_info->snaplen_max_inferred)
476       printf     ("Packet size limit:   inferred: %u bytes\n", cf_info->snaplen_min_inferred);
477     else
478       printf     ("Packet size limit:   inferred: %u bytes - %u bytes (range)\n",
479           cf_info->snaplen_min_inferred, cf_info->snaplen_max_inferred);
480   }
481   if (cap_packet_count) {
482     printf     ("Number of packets:   ");
483     if (machine_readable) {
484       printf ("%u\n", cf_info->packet_count);
485     } else {
486       size_string = format_size(cf_info->packet_count, format_size_unit_none);
487       printf ("%s\n", size_string);
488       g_free(size_string);
489     }
490   }
491   if (cap_file_size) {
492     printf     ("File size:           ");
493     if (machine_readable) {
494       printf     ("%" G_GINT64_MODIFIER "d bytes\n", cf_info->filesize);
495     } else {
496       size_string = format_size(cf_info->filesize, format_size_unit_bytes);
497       printf ("%s\n", size_string);
498       g_free(size_string);
499     }
500   }
501   if (cap_data_size) {
502     printf     ("Data size:           ");
503     if (machine_readable) {
504       printf     ("%" G_GINT64_MODIFIER "u bytes\n", cf_info->packet_bytes);
505     } else {
506       size_string = format_size(cf_info->packet_bytes, format_size_unit_bytes);
507       printf ("%s\n", size_string);
508       g_free(size_string);
509     }
510   }
511   if (cf_info->times_known) {
512     if (cap_duration) /* XXX - shorten to hh:mm:ss */
513                           print_value("Capture duration:    ", 0, " seconds",   cf_info->duration);
514     if (cap_start_time)
515                           printf     ("First packet time:   %s", time_string(start_time_t, cf_info, TRUE));
516     if (cap_end_time)
517                           printf     ("Last packet time:    %s", time_string(stop_time_t, cf_info, TRUE));
518     if (cap_data_rate_byte) {
519                           printf     ("Data byte rate:      ");
520       if (machine_readable) {
521         print_value("", 2, " bytes/sec",   cf_info->data_rate);
522       } else {
523         size_string = format_size((gint64)cf_info->data_rate, format_size_unit_bytes_s);
524         printf ("%s\n", size_string);
525         g_free(size_string);
526       }
527     }
528     if (cap_data_rate_bit) {
529                           printf     ("Data bit rate:       ");
530       if (machine_readable) {
531         print_value("", 2, " bits/sec",    cf_info->data_rate*8);
532       } else {
533         size_string = format_size((gint64)(cf_info->data_rate*8), format_size_unit_bits_s);
534         printf ("%s\n", size_string);
535         g_free(size_string);
536       }
537     }
538   }
539   if (cap_packet_size)    printf     ("Average packet size: %.2f bytes\n",        cf_info->packet_size);
540   if (cf_info->times_known) {
541     if (cap_packet_rate) {
542                           printf     ("Average packet rate: ");
543       if (machine_readable) {
544         print_value("", 2, " packets/sec", cf_info->packet_rate);
545       } else {
546         size_string = format_size((gint64)cf_info->packet_rate, format_size_unit_packets_s);
547         printf ("%s\n", size_string);
548         g_free(size_string);
549       }
550     }
551   }
552 #ifdef HAVE_LIBGCRYPT
553   if (cap_file_hashes) {
554     printf     ("SHA1:                %s\n", file_sha1);
555     printf     ("RIPEMD160:           %s\n", file_rmd160);
556     printf     ("MD5:                 %s\n", file_md5);
557   }
558 #endif /* HAVE_LIBGCRYPT */
559   if (cap_order)          printf     ("Strict time order:   %s\n", order_string(cf_info->order));
560   if (cap_comment && cf_info->comment)
561     printf     ("Capture comment:     %s\n", cf_info->comment);
562 }
563
564 static void
565 putsep(void)
566 {
567   if (field_separator) putchar(field_separator);
568 }
569
570 static void
571 putquote(void)
572 {
573   if (quote_char) putchar(quote_char);
574 }
575
576 static void
577 print_stats_table_header_label(const gchar *label)
578 {
579   putsep();
580   putquote();
581   printf("%s", label);
582   putquote();
583 }
584
585 static void
586 print_stats_table_header(void)
587 {
588   putquote();
589   printf("File name");
590   putquote();
591
592   if (cap_file_type)      print_stats_table_header_label("File type");
593   if (cap_file_encap)     print_stats_table_header_label("File encapsulation");
594   if (cap_snaplen)        print_stats_table_header_label("Packet size limit");
595   if (cap_snaplen)        print_stats_table_header_label("Packet size limit min (inferred)");
596   if (cap_snaplen)        print_stats_table_header_label("Packet size limit max (inferred)");
597   if (cap_packet_count)   print_stats_table_header_label("Number of packets");
598   if (cap_file_size)      print_stats_table_header_label("File size (bytes)");
599   if (cap_data_size)      print_stats_table_header_label("Data size (bytes)");
600   if (cap_duration)       print_stats_table_header_label("Capture duration (seconds)");
601   if (cap_start_time)     print_stats_table_header_label("Start time");
602   if (cap_end_time)       print_stats_table_header_label("End time");
603   if (cap_data_rate_byte) print_stats_table_header_label("Data byte rate (bytes/sec)");
604   if (cap_data_rate_bit)  print_stats_table_header_label("Data bit rate (bits/sec)");
605   if (cap_packet_size)    print_stats_table_header_label("Average packet size (bytes)");
606   if (cap_packet_rate)    print_stats_table_header_label("Average packet rate (packets/sec)");
607 #ifdef HAVE_LIBGCRYPT
608   if (cap_file_hashes) {
609     print_stats_table_header_label("SHA1");
610     print_stats_table_header_label("RIPEMD160");
611     print_stats_table_header_label("MD5");
612   }
613 #endif /* HAVE_LIBGCRYPT */
614   if (cap_order)          print_stats_table_header_label("Strict time order");
615   if (cap_comment)        print_stats_table_header_label("Capture comment");
616
617   printf("\n");
618 }
619
620 static void
621 print_stats_table(const gchar *filename, capture_info *cf_info)
622 {
623   const gchar           *file_type_string, *file_encap_string;
624   time_t                 start_time_t;
625   time_t                 stop_time_t;
626
627   /* Build printable strings for various stats */
628   file_type_string = wtap_file_type_subtype_string(cf_info->file_type);
629   file_encap_string = wtap_encap_string(cf_info->file_encap);
630   start_time_t = (time_t)cf_info->start_time;
631   stop_time_t = (time_t)cf_info->stop_time;
632
633   if (filename) {
634     putquote();
635     printf("%s", filename);
636     putquote();
637   }
638
639   if (cap_file_type) {
640     putsep();
641     putquote();
642     printf("%s", file_type_string);
643     putquote();
644   }
645
646   /* ToDo: If WTAP_ENCAP_PER_PACKET, show the list of encapsulations encountered;
647    *       Output a line for each different encap with all fields repeated except
648    *        the encapsulation field which has "Per Packet: ..." for each
649    *        encapsulation type seen ?
650    */
651   if (cap_file_encap) {
652     putsep();
653     putquote();
654     printf("%s", file_encap_string);
655     putquote();
656   }
657
658   if (cap_snaplen) {
659     putsep();
660     putquote();
661     if (cf_info->snap_set)
662       printf("%u", cf_info->snaplen);
663     else
664       printf("(not set)");
665     putquote();
666     if (cf_info->snaplen_max_inferred > 0) {
667       putsep();
668       putquote();
669       printf("%u", cf_info->snaplen_min_inferred);
670       putquote();
671       putsep();
672       putquote();
673       printf("%u", cf_info->snaplen_max_inferred);
674       putquote();
675     }
676     else {
677       putsep();
678       putquote();
679       printf("n/a");
680       putquote();
681       putsep();
682       putquote();
683       printf("n/a");
684       putquote();
685     }
686   }
687
688   if (cap_packet_count) {
689     putsep();
690     putquote();
691     printf("%u", cf_info->packet_count);
692     putquote();
693   }
694
695   if (cap_file_size) {
696     putsep();
697     putquote();
698     printf("%" G_GINT64_MODIFIER "d", cf_info->filesize);
699     putquote();
700   }
701
702   if (cap_data_size) {
703     putsep();
704     putquote();
705     printf("%" G_GINT64_MODIFIER "u", cf_info->packet_bytes);
706     putquote();
707   }
708
709   if (cap_duration) {
710     putsep();
711     putquote();
712     if (cf_info->times_known)
713       printf("%f", cf_info->duration);
714     else
715       printf("n/a");
716     putquote();
717   }
718
719   if (cap_start_time) {
720     putsep();
721     putquote();
722     printf("%s", time_string(start_time_t, cf_info, FALSE));
723     putquote();
724   }
725
726   if (cap_end_time) {
727     putsep();
728     putquote();
729     printf("%s", time_string(stop_time_t, cf_info, FALSE));
730     putquote();
731   }
732
733   if (cap_data_rate_byte) {
734     putsep();
735     putquote();
736     if (cf_info->times_known)
737       printf("%.2f", cf_info->data_rate);
738     else
739       printf("n/a");
740     putquote();
741   }
742
743   if (cap_data_rate_bit) {
744     putsep();
745     putquote();
746     if (cf_info->times_known)
747       printf("%.2f", cf_info->data_rate*8);
748     else
749       printf("n/a");
750     putquote();
751   }
752
753   if (cap_packet_size) {
754     putsep();
755     putquote();
756     printf("%.2f", cf_info->packet_size);
757     putquote();
758   }
759
760   if (cap_packet_rate) {
761     putsep();
762     putquote();
763     if (cf_info->times_known)
764       printf("%.2f", cf_info->packet_rate);
765     else
766       printf("n/a");
767     putquote();
768   }
769
770 #ifdef HAVE_LIBGCRYPT
771   if (cap_file_hashes) {
772     putsep();
773     putquote();
774     printf("%s", file_sha1);
775     putquote();
776
777     putsep();
778     putquote();
779     printf("%s", file_rmd160);
780     putquote();
781
782     putsep();
783     putquote();
784     printf("%s", file_md5);
785     putquote();
786   }
787 #endif /* HAVE_LIBGCRYPT */
788
789   if (cap_order) {
790     putsep();
791     putquote();
792     printf("%s", order_string(cf_info->order));
793     putquote();
794   }
795
796   if (cap_comment) {
797     putsep();
798     putquote();
799     printf("%s", cf_info->comment);
800     putquote();
801   }
802
803
804   printf("\n");
805 }
806
807 static int
808 process_cap_file(wtap *wth, const char *filename)
809 {
810   int                   status = 0;
811   int                   err;
812   gchar                *err_info;
813   gint64                size;
814   gint64                data_offset;
815
816   guint32               packet = 0;
817   gint64                bytes  = 0;
818   guint32               snaplen_min_inferred = 0xffffffff;
819   guint32               snaplen_max_inferred =          0;
820   const struct wtap_pkthdr *phdr;
821   capture_info          cf_info;
822   gboolean              have_times = TRUE;
823   double                start_time = 0;
824   double                stop_time  = 0;
825   double                cur_time   = 0;
826   double                prev_time = 0;
827   gboolean              know_order = FALSE;
828   order_t               order = IN_ORDER;
829   wtapng_section_t     *shb_inf;
830   gchar                *p;
831
832
833   cf_info.encap_counts = g_new0(int,WTAP_NUM_ENCAP_TYPES);
834
835   /* Tally up data that we need to parse through the file to find */
836   while (wtap_read(wth, &err, &err_info, &data_offset))  {
837     phdr = wtap_phdr(wth);
838     if (phdr->presence_flags & WTAP_HAS_TS) {
839       prev_time = cur_time;
840       cur_time = nstime_to_sec(&phdr->ts);
841       if (packet == 0) {
842         start_time = cur_time;
843         stop_time  = cur_time;
844         prev_time  = cur_time;
845       }
846       if (cur_time < prev_time) {
847         order = NOT_IN_ORDER;
848       }
849       if (cur_time < start_time) {
850         start_time = cur_time;
851       }
852       if (cur_time > stop_time) {
853         stop_time = cur_time;
854       }
855     } else {
856       have_times = FALSE; /* at least one packet has no time stamp */
857       if (order != NOT_IN_ORDER)
858         order = ORDER_UNKNOWN;
859     }
860
861     if (phdr->rec_type == REC_TYPE_PACKET) {
862       bytes+=phdr->len;
863       packet++;
864
865       /* If caplen < len for a rcd, then presumably           */
866       /* 'Limit packet capture length' was done for this rcd. */
867       /* Keep track as to the min/max actual snapshot lengths */
868       /*  seen for this file.                                 */
869       if (phdr->caplen < phdr->len) {
870         if (phdr->caplen < snaplen_min_inferred)
871           snaplen_min_inferred = phdr->caplen;
872         if (phdr->caplen > snaplen_max_inferred)
873           snaplen_max_inferred = phdr->caplen;
874       }
875
876       /* Per-packet encapsulation */
877       if (wtap_file_encap(wth) == WTAP_ENCAP_PER_PACKET) {
878         if ((phdr->pkt_encap > 0) && (phdr->pkt_encap < WTAP_NUM_ENCAP_TYPES)) {
879           cf_info.encap_counts[phdr->pkt_encap] += 1;
880         } else {
881           fprintf(stderr, "capinfos: Unknown per-packet encapsulation %d in frame %u of file \"%s\"\n",
882                   phdr->pkt_encap, packet, filename);
883         }
884       }
885     }
886
887   } /* while */
888
889   if (err != 0) {
890     fprintf(stderr,
891         "capinfos: An error occurred after reading %u packets from \"%s\": %s.\n",
892         packet, filename, wtap_strerror(err));
893     if (err == WTAP_ERR_SHORT_READ) {
894         /* Don't give up completely with this one. */
895         status = 1;
896         fprintf(stderr,
897           "  (will continue anyway, checksums might be incorrect)\n");
898     } else {
899         if (err_info != NULL) {
900             fprintf(stderr, "(%s)\n", err_info);
901             g_free(err_info);
902         }
903
904         g_free(cf_info.encap_counts);
905         return 1;
906     }
907   }
908
909   /* File size */
910   size = wtap_file_size(wth, &err);
911   if (size == -1) {
912     fprintf(stderr,
913         "capinfos: Can't get size of \"%s\": %s.\n",
914         filename, g_strerror(err));
915     g_free(cf_info.encap_counts);
916     return 1;
917   }
918
919   cf_info.filesize = size;
920
921   /* File Type */
922   cf_info.file_type = wtap_file_type_subtype(wth);
923   cf_info.iscompressed = wtap_iscompressed(wth);
924
925   /* File Encapsulation */
926   cf_info.file_encap = wtap_file_encap(wth);
927
928   /* Packet size limit (snaplen) */
929   cf_info.snaplen = wtap_snapshot_length(wth);
930   if (cf_info.snaplen > 0)
931     cf_info.snap_set = TRUE;
932   else
933     cf_info.snap_set = FALSE;
934
935   cf_info.snaplen_min_inferred = snaplen_min_inferred;
936   cf_info.snaplen_max_inferred = snaplen_max_inferred;
937
938   /* # of packets */
939   cf_info.packet_count = packet;
940
941   /* File Times */
942   cf_info.times_known = have_times;
943   cf_info.start_time = start_time;
944   cf_info.stop_time = stop_time;
945   cf_info.duration = stop_time-start_time;
946   cf_info.know_order = know_order;
947   cf_info.order = order;
948
949   /* Number of packet bytes */
950   cf_info.packet_bytes = bytes;
951
952   cf_info.data_rate   = 0.0;
953   cf_info.packet_rate = 0.0;
954   cf_info.packet_size = 0.0;
955
956   if (packet > 0) {
957     if (cf_info.duration > 0.0) {
958       cf_info.data_rate   = (double)bytes  / (stop_time-start_time); /* Data rate per second */
959       cf_info.packet_rate = (double)packet / (stop_time-start_time); /* packet rate per second */
960     }
961     cf_info.packet_size = (double)bytes / packet;                  /* Avg packet size      */
962   }
963
964   cf_info.comment = NULL;
965   shb_inf = wtap_file_get_shb_info(wth);
966   if (shb_inf) {
967     /* opt_comment is always 0-terminated by pcapng_read_section_header_block */
968     cf_info.comment = g_strdup(shb_inf->opt_comment);
969   }
970   g_free(shb_inf);
971   if (cf_info.comment) {
972     /* multi-line comments would conflict with the formatting that capinfos uses
973        we replace linefeeds with spaces */
974     p = cf_info.comment;
975     while (*p != '\0') {
976       if (*p == '\n')
977         *p = ' ';
978       p++;
979     }
980   }
981
982   if (long_report) {
983     print_stats(filename, &cf_info);
984   } else {
985     print_stats_table(filename, &cf_info);
986   }
987
988   g_free(cf_info.encap_counts);
989   g_free(cf_info.comment);
990
991   return status;
992 }
993
994 static void
995 print_usage(FILE *output)
996 {
997   fprintf(output, "\n");
998   fprintf(output, "Usage: capinfos [options] <infile> ...\n");
999   fprintf(output, "\n");
1000   fprintf(output, "General infos:\n");
1001   fprintf(output, "  -t display the capture file type\n");
1002   fprintf(output, "  -E display the capture file encapsulation\n");
1003 #ifdef HAVE_LIBGCRYPT
1004   fprintf(output, "  -H display the SHA1, RMD160, and MD5 hashes of the file\n");
1005 #endif
1006   fprintf(output, "  -k display the capture comment\n");
1007   fprintf(output, "\n");
1008   fprintf(output, "Size infos:\n");
1009   fprintf(output, "  -c display the number of packets\n");
1010   fprintf(output, "  -s display the size of the file (in bytes)\n");
1011   fprintf(output, "  -d display the total length of all packets (in bytes)\n");
1012   fprintf(output, "  -l display the packet size limit (snapshot length)\n");
1013   fprintf(output, "\n");
1014   fprintf(output, "Time infos:\n");
1015   fprintf(output, "  -u display the capture duration (in seconds)\n");
1016   fprintf(output, "  -a display the capture start time\n");
1017   fprintf(output, "  -e display the capture end time\n");
1018   fprintf(output, "  -o display the capture file chronological status (True/False)\n");
1019   fprintf(output, "  -S display start and end times as seconds\n");
1020   fprintf(output, "\n");
1021   fprintf(output, "Statistic infos:\n");
1022   fprintf(output, "  -y display average data rate (in bytes/sec)\n");
1023   fprintf(output, "  -i display average data rate (in bits/sec)\n");
1024   fprintf(output, "  -z display average packet size (in bytes)\n");
1025   fprintf(output, "  -x display average packet rate (in packets/sec)\n");
1026   fprintf(output, "\n");
1027   fprintf(output, "Output format:\n");
1028   fprintf(output, "  -L generate long report (default)\n");
1029   fprintf(output, "  -T generate table report\n");
1030   fprintf(output, "  -M display machine-readable values in long reports\n");
1031   fprintf(output, "\n");
1032   fprintf(output, "Table report options:\n");
1033   fprintf(output, "  -R generate header record (default)\n");
1034   fprintf(output, "  -r do not generate header record\n");
1035   fprintf(output, "\n");
1036   fprintf(output, "  -B separate infos with TAB character (default)\n");
1037   fprintf(output, "  -m separate infos with comma (,) character\n");
1038   fprintf(output, "  -b separate infos with SPACE character\n");
1039   fprintf(output, "\n");
1040   fprintf(output, "  -N do not quote infos (default)\n");
1041   fprintf(output, "  -q quote infos with single quotes (')\n");
1042   fprintf(output, "  -Q quote infos with double quotes (\")\n");
1043   fprintf(output, "\n");
1044   fprintf(output, "Miscellaneous:\n");
1045   fprintf(output, "  -h display this help and exit\n");
1046   fprintf(output, "  -C cancel processing if file open fails (default is to continue)\n");
1047   fprintf(output, "  -A generate all infos (default)\n");
1048   fprintf(output, "\n");
1049   fprintf(output, "Options are processed from left to right order with later options superceding\n");
1050   fprintf(output, "or adding to earlier options.\n");
1051   fprintf(output, "\n");
1052   fprintf(output, "If no options are given the default is to display all infos in long report\n");
1053   fprintf(output, "output format.\n");
1054 #ifndef HAVE_LIBGCRYPT
1055   fprintf(output, "\nFile hashing support (-H) is not present.\n");
1056 #endif
1057 }
1058
1059 #ifdef HAVE_PLUGINS
1060 /*
1061  *  Don't report failures to load plugins because most (non-wiretap) plugins
1062  *  *should* fail to load (because we're not linked against libwireshark and
1063  *  dissector plugins need libwireshark).
1064  */
1065 static void
1066 failure_message(const char *msg_format _U_, va_list ap _U_)
1067 {
1068   return;
1069 }
1070 #endif
1071
1072 #ifdef HAVE_LIBGCRYPT
1073 static void
1074 hash_to_str(const unsigned char *hash, size_t length, char *str) {
1075   int i;
1076
1077   for (i = 0; i < (int) length; i++) {
1078     g_snprintf(str+(i*2), 3, "%02x", hash[i]);
1079   }
1080 }
1081 #endif /* HAVE_LIBGCRYPT */
1082
1083 static void
1084 get_capinfos_compiled_info(GString *str)
1085 {
1086   /* LIBZ */
1087   g_string_append(str, ", ");
1088 #ifdef HAVE_LIBZ
1089   g_string_append(str, "with libz ");
1090 #ifdef ZLIB_VERSION
1091   g_string_append(str, ZLIB_VERSION);
1092 #else /* ZLIB_VERSION */
1093   g_string_append(str, "(version unknown)");
1094 #endif /* ZLIB_VERSION */
1095 #else /* HAVE_LIBZ */
1096   g_string_append(str, "without libz");
1097 #endif /* HAVE_LIBZ */
1098 }
1099
1100 static void
1101 get_capinfos_runtime_info(GString *str)
1102 {
1103   /* zlib */
1104 #if defined(HAVE_LIBZ) && !defined(_WIN32)
1105   g_string_append_printf(str, ", with libz %s", zlibVersion());
1106 #endif
1107 }
1108
1109 int
1110 main(int argc, char *argv[])
1111 {
1112   GString *comp_info_str;
1113   GString *runtime_info_str;
1114   wtap  *wth;
1115   int    err;
1116   gchar *err_info;
1117   int    opt;
1118   int    overall_error_status;
1119 DIAG_OFF(cast-qual)
1120   static const struct option long_options[] = {
1121       {(char *)"help", no_argument, NULL, 'h'},
1122       {(char *)"version", no_argument, NULL, 'v'},
1123       {0, 0, 0, 0 }
1124   };
1125 DIAG_ON(cast-qual)
1126
1127   int status = 0;
1128 #ifdef HAVE_PLUGINS
1129   char  *init_progfile_dir_error;
1130 #endif
1131 #ifdef HAVE_LIBGCRYPT
1132   FILE  *fh;
1133   char  *hash_buf = NULL;
1134   gcry_md_hd_t hd = NULL;
1135   size_t hash_bytes;
1136 #endif
1137
1138   /* Set the C-language locale to the native environment. */
1139   setlocale(LC_ALL, "");
1140
1141   /* Get the compile-time version information string */
1142   comp_info_str = get_compiled_version_info(NULL, get_capinfos_compiled_info);
1143
1144   /* Get the run-time version information string */
1145   runtime_info_str = get_runtime_version_info(get_capinfos_runtime_info);
1146
1147   /* Add it to the information to be reported on a crash. */
1148   ws_add_crash_info("Capinfos (Wireshark) %s\n"
1149          "\n"
1150          "%s"
1151          "\n"
1152          "%s",
1153       get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str);
1154
1155 #ifdef _WIN32
1156   arg_list_utf_16to8(argc, argv);
1157   create_app_running_mutex();
1158 #endif /* _WIN32 */
1159
1160   /*
1161    * Get credential information for later use.
1162    */
1163   init_process_policies();
1164   init_open_routines();
1165
1166 #ifdef HAVE_PLUGINS
1167   if ((init_progfile_dir_error = init_progfile_dir(argv[0], (void *)main))) {
1168     g_warning("capinfos: init_progfile_dir(): %s", init_progfile_dir_error);
1169     g_free(init_progfile_dir_error);
1170   } else {
1171     /* Register all the plugin types we have. */
1172     wtap_register_plugin_types(); /* Types known to libwiretap */
1173
1174     init_report_err(failure_message, NULL, NULL, NULL);
1175
1176     /* Scan for plugins.  This does *not* call their registration routines;
1177        that's done later. */
1178     scan_plugins();
1179
1180     /* Register all libwiretap plugin modules. */
1181     register_all_wiretap_modules();
1182   }
1183 #endif
1184
1185   /* Process the options */
1186 #ifdef USE_GOPTION
1187   ctx = g_option_context_new(" <infile> ... - print information about capture file(s)");
1188   general_grp = g_option_group_new("gen", "General infos:",
1189       "Show general options", NULL, NULL);
1190   size_grp = g_option_group_new("size", "Size infos:",
1191       "Show size options", NULL, NULL);
1192   time_grp = g_option_group_new("time", "Time infos:",
1193       "Show time options", NULL, NULL);
1194   stats_grp = g_option_group_new("stats", "Statistics infos:",
1195       "Show statistics options", NULL, NULL);
1196   output_grp = g_option_group_new("output", "Output format:",
1197       "Show output format options", NULL, NULL);
1198   table_report_grp = g_option_group_new("table", "Table report options:",
1199       "Show table report options", NULL, NULL);
1200   g_option_group_add_entries(general_grp, general_entries);
1201   g_option_group_add_entries(size_grp, size_entries);
1202   g_option_group_add_entries(time_grp, time_entries);
1203   g_option_group_add_entries(stats_grp, stats_entries);
1204   g_option_group_add_entries(output_grp, output_format_entries);
1205   g_option_group_add_entries(table_report_grp, table_report_entries);
1206   g_option_context_add_main_entries(ctx, misc_entries, NULL);
1207   g_option_context_add_group(ctx, general_grp);
1208   g_option_context_add_group(ctx, size_grp);
1209   g_option_context_add_group(ctx, time_grp);
1210   g_option_context_add_group(ctx, stats_grp);
1211   g_option_context_add_group(ctx, output_grp);
1212   g_option_context_add_group(ctx, table_report_grp);
1213   /* There's probably a better way to do this, but this works for now.
1214      GOptions displays the name in argv[0] as the name of the
1215      application.  This is reasonable, but because we actually have a
1216      script wrapper that calls the executable.  The name that gets
1217      displayed is not exactly the same as the command the user used
1218      ran.
1219    */
1220   argv[0] = (char *)"capinfos";
1221
1222   /* if we have at least one cmdline option, we disable printing all infos */
1223   if (argc > 2 && report_all_infos)
1224     disable_all_infos();
1225
1226   if ( !g_option_context_parse(ctx, &argc, &argv, &parse_err) ) {
1227     if (parse_err)
1228       g_printerr ("option parsing failed: %s\n", parse_err->message);
1229     g_printerr("%s", g_option_context_get_help (ctx, TRUE, NULL));
1230     exit(1);
1231   }
1232   if ( cap_help ) {
1233     g_print("%s", g_option_context_get_help (ctx, FALSE, NULL));
1234     exit(0);
1235   }
1236   if ( argc < 2 ) {
1237     g_printerr("%s", g_option_context_get_help (ctx, FALSE, NULL));
1238     exit(1);
1239   }
1240   g_option_context_free(ctx);
1241
1242 #endif /* USE_GOPTION */
1243   while ((opt = getopt_long(argc, argv, "tEcs" FILE_HASH_OPT "dluaeyizvhxokCALTMRrSNqQBmb", long_options, NULL)) !=-1) {
1244
1245     switch (opt) {
1246
1247       case 't':
1248         if (report_all_infos) disable_all_infos();
1249         cap_file_type = TRUE;
1250         break;
1251
1252       case 'E':
1253         if (report_all_infos) disable_all_infos();
1254         cap_file_encap = TRUE;
1255         break;
1256
1257       case 'l':
1258         if (report_all_infos) disable_all_infos();
1259         cap_snaplen = TRUE;
1260         break;
1261
1262       case 'c':
1263         if (report_all_infos) disable_all_infos();
1264         cap_packet_count = TRUE;
1265         break;
1266
1267       case 's':
1268         if (report_all_infos) disable_all_infos();
1269         cap_file_size = TRUE;
1270         break;
1271
1272       case 'd':
1273         if (report_all_infos) disable_all_infos();
1274         cap_data_size = TRUE;
1275         break;
1276
1277       case 'u':
1278         if (report_all_infos) disable_all_infos();
1279         cap_duration = TRUE;
1280         break;
1281
1282       case 'a':
1283         if (report_all_infos) disable_all_infos();
1284         cap_start_time = TRUE;
1285         break;
1286
1287       case 'e':
1288         if (report_all_infos) disable_all_infos();
1289         cap_end_time = TRUE;
1290         break;
1291
1292       case 'S':
1293         time_as_secs = TRUE;
1294         break;
1295
1296       case 'y':
1297         if (report_all_infos) disable_all_infos();
1298         cap_data_rate_byte = TRUE;
1299         break;
1300
1301       case 'i':
1302         if (report_all_infos) disable_all_infos();
1303         cap_data_rate_bit = TRUE;
1304         break;
1305
1306       case 'z':
1307         if (report_all_infos) disable_all_infos();
1308         cap_packet_size = TRUE;
1309         break;
1310
1311       case 'x':
1312         if (report_all_infos) disable_all_infos();
1313         cap_packet_rate = TRUE;
1314         break;
1315
1316 #ifdef HAVE_LIBGCRYPT
1317       case 'H':
1318         if (report_all_infos) disable_all_infos();
1319         cap_file_hashes = TRUE;
1320         break;
1321 #endif
1322
1323       case 'o':
1324         if (report_all_infos) disable_all_infos();
1325         cap_order = TRUE;
1326         break;
1327
1328       case 'k':
1329         if (report_all_infos) disable_all_infos();
1330         cap_comment = TRUE;
1331         break;
1332
1333       case 'C':
1334         continue_after_wtap_open_offline_failure = FALSE;
1335         break;
1336
1337       case 'A':
1338         enable_all_infos();
1339         break;
1340
1341       case 'L':
1342         long_report = TRUE;
1343         break;
1344
1345       case 'T':
1346         long_report = FALSE;
1347         break;
1348
1349       case 'M':
1350         machine_readable = TRUE;
1351         break;
1352
1353       case 'R':
1354         table_report_header = TRUE;
1355         break;
1356
1357       case 'r':
1358         table_report_header = FALSE;
1359         break;
1360
1361       case 'N':
1362         quote_char = '\0';
1363         break;
1364
1365       case 'q':
1366         quote_char = '\'';
1367         break;
1368
1369       case 'Q':
1370         quote_char = '"';
1371         break;
1372
1373       case 'B':
1374         field_separator = '\t';
1375         break;
1376
1377       case 'm':
1378         field_separator = ',';
1379         break;
1380
1381       case 'b':
1382         field_separator = ' ';
1383         break;
1384
1385       case 'h':
1386         printf("Capinfos (Wireshark) %s\n"
1387                "Print various information (infos) about capture files.\n"
1388                "See http://www.wireshark.org for more information.\n",
1389                get_ws_vcs_version_info());
1390         print_usage(stdout);
1391         exit(0);
1392         break;
1393
1394       case 'v':
1395         show_version("Capinfos (Wireshark)", comp_info_str, runtime_info_str);
1396         g_string_free(comp_info_str, TRUE);
1397         g_string_free(runtime_info_str, TRUE);
1398         exit(0);
1399         break;
1400
1401       case '?':              /* Bad flag - print usage message */
1402         print_usage(stderr);
1403         exit(1);
1404         break;
1405     }
1406   }
1407
1408   if ((argc - optind) < 1) {
1409     print_usage(stderr);
1410     exit(1);
1411   }
1412
1413   if (!long_report && table_report_header) {
1414     print_stats_table_header();
1415   }
1416
1417 #ifdef HAVE_LIBGCRYPT
1418   if (cap_file_hashes) {
1419     gcry_check_version(NULL);
1420     gcry_md_open(&hd, GCRY_MD_SHA1, 0);
1421     if (hd) {
1422       gcry_md_enable(hd, GCRY_MD_RMD160);
1423       gcry_md_enable(hd, GCRY_MD_MD5);
1424     }
1425     hash_buf = (char *)g_malloc(HASH_BUF_SIZE);
1426   }
1427 #endif
1428
1429   overall_error_status = 0;
1430
1431   for (opt = optind; opt < argc; opt++) {
1432
1433 #ifdef HAVE_LIBGCRYPT
1434     g_strlcpy(file_sha1, "<unknown>", HASH_STR_SIZE);
1435     g_strlcpy(file_rmd160, "<unknown>", HASH_STR_SIZE);
1436     g_strlcpy(file_md5, "<unknown>", HASH_STR_SIZE);
1437
1438     if (cap_file_hashes) {
1439       fh = ws_fopen(argv[opt], "rb");
1440       if (fh && hd) {
1441         while((hash_bytes = fread(hash_buf, 1, HASH_BUF_SIZE, fh)) > 0) {
1442           gcry_md_write(hd, hash_buf, hash_bytes);
1443         }
1444         gcry_md_final(hd);
1445         hash_to_str(gcry_md_read(hd, GCRY_MD_SHA1), HASH_SIZE_SHA1, file_sha1);
1446         hash_to_str(gcry_md_read(hd, GCRY_MD_RMD160), HASH_SIZE_RMD160, file_rmd160);
1447         hash_to_str(gcry_md_read(hd, GCRY_MD_MD5), HASH_SIZE_MD5, file_md5);
1448       }
1449       if (fh) fclose(fh);
1450       if (hd) gcry_md_reset(hd);
1451     }
1452 #endif /* HAVE_LIBGCRYPT */
1453
1454     wth = wtap_open_offline(argv[opt], WTAP_TYPE_AUTO, &err, &err_info, FALSE);
1455
1456     if (!wth) {
1457       fprintf(stderr, "capinfos: Can't open %s: %s\n", argv[opt],
1458           wtap_strerror(err));
1459       if (err_info != NULL) {
1460         fprintf(stderr, "(%s)\n", err_info);
1461         g_free(err_info);
1462       }
1463       overall_error_status = 1; /* remember that an error has occurred */
1464       if (!continue_after_wtap_open_offline_failure)
1465         exit(1); /* error status */
1466     }
1467
1468     if (wth) {
1469       if ((opt > optind) && (long_report))
1470         printf("\n");
1471       status = process_cap_file(wth, argv[opt]);
1472
1473       wtap_close(wth);
1474       if (status)
1475         exit(status);
1476     }
1477   }
1478
1479   return overall_error_status;
1480 }
1481
1482 /*
1483  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1484  *
1485  * Local variables:
1486  * c-basic-offset: 2
1487  * tab-width: 8
1488  * indent-tabs-mode: nil
1489  * End:
1490  *
1491  * vi: set shiftwidth=2 tabstop=8 expandtab:
1492  * :indentSize=2:tabSize=8:noTabs=true:
1493  */