More use of wtap_optionblock_foreach_option().
[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_GETOPT_H
67 #include <getopt.h>
68 #endif
69
70 #include <glib.h>
71
72 #include <wiretap/wtap.h>
73
74 #include <wsutil/crash_info.h>
75 #include <wsutil/filesystem.h>
76 #include <wsutil/privileges.h>
77 #include <ws_version_info.h>
78 #include <wiretap/wtap_opttypes.h>
79 #include <wiretap/pcapng.h>
80
81 #ifdef HAVE_PLUGINS
82 #include <wsutil/plugins.h>
83 #endif
84
85 #include <wsutil/report_err.h>
86 #include <wsutil/str_util.h>
87 #include <wsutil/file_util.h>
88
89 #include <wsutil/wsgcrypt.h>
90
91 #ifndef HAVE_GETOPT_LONG
92 #include "wsutil/wsgetopt.h"
93 #endif
94
95 #ifdef _WIN32
96 #include <wsutil/unicode-utils.h>
97 #endif /* _WIN32 */
98
99 /*
100  * By default capinfos now continues processing
101  * the next filename if and when wiretap detects
102  * a problem opening a file.
103  * Use the '-C' option to revert back to original
104  * capinfos behavior which is to abort any
105  * additional file processing at first open file
106  * failure.
107  */
108
109 static gboolean continue_after_wtap_open_offline_failure = TRUE;
110
111 /*
112  * table report variables
113  */
114
115 static gboolean long_report        = TRUE;  /* By default generate long report       */
116 static gchar table_report_header   = TRUE;  /* Generate column header by default     */
117 static gchar field_separator       = '\t';  /* Use TAB as field separator by default */
118 static gchar quote_char            = '\0';  /* Do NOT quote fields by default        */
119 static gboolean machine_readable   = FALSE; /* Display machine-readable numbers      */
120
121 /*
122  * capinfos has the ability to report on a number of
123  * various characteristics ("infos") for each input file.
124  *
125  * By default reporting of all info fields is enabled.
126  *
127  * Optionally the reporting of any specific info field
128  * or combination of info fields can be enabled with
129  * individual options.
130  */
131
132 static gboolean report_all_infos   = TRUE;  /* Report all infos           */
133
134 static gboolean cap_file_type      = TRUE;  /* Report capture type        */
135 static gboolean cap_file_encap     = TRUE;  /* Report encapsulation       */
136 static gboolean cap_snaplen        = TRUE;  /* Packet size limit (snaplen)*/
137 static gboolean cap_packet_count   = TRUE;  /* Report packet count        */
138 static gboolean cap_file_size      = TRUE;  /* Report file size           */
139 static gboolean cap_comment        = TRUE;  /* Display the capture comment */
140 static gboolean cap_file_more_info = TRUE;  /* Report more file info      */
141 static gboolean cap_file_idb       = TRUE;  /* Report Interface info      */
142
143 static gboolean cap_data_size      = TRUE;  /* Report packet byte size    */
144 static gboolean cap_duration       = TRUE;  /* Report capture duration    */
145 static gboolean cap_start_time     = TRUE;  /* Report capture start time  */
146 static gboolean cap_end_time       = TRUE;  /* Report capture end time    */
147 static gboolean time_as_secs       = FALSE; /* Report time values as raw seconds */
148
149 static gboolean cap_data_rate_byte = TRUE;  /* Report data rate bytes/sec */
150 static gboolean cap_data_rate_bit  = TRUE;  /* Report data rate bites/sec */
151 static gboolean cap_packet_size    = TRUE;  /* Report average packet size */
152 static gboolean cap_packet_rate    = TRUE;  /* Report average packet rate */
153 static gboolean cap_order          = TRUE;  /* Report if packets are in chronological order (True/False) */
154
155 #ifdef HAVE_LIBGCRYPT
156 static gboolean cap_file_hashes    = TRUE;  /* Calculate file hashes */
157
158 #define HASH_SIZE_SHA1   20
159 #define HASH_SIZE_RMD160 20
160 #define HASH_SIZE_MD5    16
161
162 #define HASH_STR_SIZE (41) /* Max hash size * 2 + '\0' */
163 #define HASH_BUF_SIZE (1024 * 1024)
164
165
166 static gchar file_sha1[HASH_STR_SIZE];
167 static gchar file_rmd160[HASH_STR_SIZE];
168 static gchar file_md5[HASH_STR_SIZE];
169
170 #define FILE_HASH_OPT "H"
171 #else
172 #define FILE_HASH_OPT ""
173 #endif /* HAVE_LIBGCRYPT */
174
175 /*
176  * If we have at least two packets with time stamps, and they're not in
177  * order - i.e., the later packet has a time stamp older than the earlier
178  * packet - the time stamps are known not to be in order.
179  *
180  * If every packet has a time stamp, and they're all in order, the time
181  * stamp is known to be in order.
182  *
183  * Otherwise, we have no idea.
184  */
185 typedef enum {
186   IN_ORDER,
187   NOT_IN_ORDER,
188   ORDER_UNKNOWN
189 } order_t;
190
191 typedef struct _capture_info {
192   const char    *filename;
193   guint16        file_type;
194   gboolean       iscompressed;
195   int            file_encap;
196   int            file_tsprec;
197   gint64         filesize;
198   wtap_optionblock_t shb;
199   guint64        packet_bytes;
200   gboolean       times_known;
201   nstime_t       start_time;
202   int            start_time_tsprec;
203   nstime_t       stop_time;
204   int            stop_time_tsprec;
205   guint32        packet_count;
206   gboolean       snap_set;                /* If set in capture file header      */
207   guint32        snaplen;                 /* value from the capture file header */
208   guint32        snaplen_min_inferred;    /* If caplen < len for 1 or more rcds */
209   guint32        snaplen_max_inferred;    /*  ...                               */
210   gboolean       drops_known;
211   guint32        drop_count;
212
213   nstime_t       duration;
214   int            duration_tsprec;
215   double         packet_rate;
216   double         packet_size;
217   double         data_rate;              /* in bytes */
218   gboolean       know_order;
219   order_t        order;
220
221   int           *encap_counts;           /* array of per_packet encap counts; array has one entry per wtap_encap type */
222
223   guint          num_interfaces;         /* number of IDBs, and thus size of interface_ids array */
224   guint32       *interface_ids;          /* array of per_packet interface_id counts; one entry per file IDB */
225   guint32        pkt_interface_id_unknown; /* counts if packet interface_id didn't match a known one */
226   GArray        *idb_info_strings;       /* array of IDB info strings */
227 } capture_info;
228
229
230 static void
231 enable_all_infos(void)
232 {
233   report_all_infos   = TRUE;
234
235   cap_file_type      = TRUE;
236   cap_file_encap     = TRUE;
237   cap_snaplen        = TRUE;
238   cap_packet_count   = TRUE;
239   cap_file_size      = TRUE;
240   cap_comment        = TRUE;
241   cap_file_more_info = TRUE;
242   cap_file_idb       = TRUE;
243
244   cap_data_size      = TRUE;
245   cap_duration       = TRUE;
246   cap_start_time     = TRUE;
247   cap_end_time       = TRUE;
248   cap_order          = TRUE;
249
250   cap_data_rate_byte = TRUE;
251   cap_data_rate_bit  = TRUE;
252   cap_packet_size    = TRUE;
253   cap_packet_rate    = TRUE;
254
255 #ifdef HAVE_LIBGCRYPT
256   cap_file_hashes    = TRUE;
257 #endif /* HAVE_LIBGCRYPT */
258 }
259
260 static void
261 disable_all_infos(void)
262 {
263   report_all_infos   = FALSE;
264
265   cap_file_type      = FALSE;
266   cap_file_encap     = FALSE;
267   cap_snaplen        = FALSE;
268   cap_packet_count   = FALSE;
269   cap_file_size      = FALSE;
270   cap_comment        = FALSE;
271   cap_file_more_info = FALSE;
272   cap_file_idb       = FALSE;
273
274   cap_data_size      = FALSE;
275   cap_duration       = FALSE;
276   cap_start_time     = FALSE;
277   cap_end_time       = FALSE;
278   cap_order          = FALSE;
279
280   cap_data_rate_byte = FALSE;
281   cap_data_rate_bit  = FALSE;
282   cap_packet_size    = FALSE;
283   cap_packet_rate    = FALSE;
284
285 #ifdef HAVE_LIBGCRYPT
286   cap_file_hashes    = FALSE;
287 #endif /* HAVE_LIBGCRYPT */
288 }
289
290 static const gchar *
291 order_string(order_t order)
292 {
293   switch (order) {
294
295     case IN_ORDER:
296       return "True";
297
298     case NOT_IN_ORDER:
299       return "False";
300
301     case ORDER_UNKNOWN:
302       return "Unknown";
303
304     default:
305       return "???";  /* "cannot happen" (the next step is "Profit!") */
306   }
307 }
308
309 static gchar *
310 absolute_time_string(nstime_t *timer, int tsprecision, capture_info *cf_info)
311 {
312   static gchar  time_string_buf[4+1+2+1+2+1+2+1+2+1+2+1+9+1+1];
313   struct tm *ti_tm;
314
315   if (cf_info->times_known && cf_info->packet_count > 0) {
316     if (time_as_secs) {
317       switch (tsprecision) {
318
319       case WTAP_TSPREC_SEC:
320         g_snprintf(time_string_buf, sizeof time_string_buf,
321                    "%lu",
322                    (unsigned long)timer->secs);
323         break;
324
325       case WTAP_TSPREC_DSEC:
326         g_snprintf(time_string_buf, sizeof time_string_buf,
327                    "%lu.%01d",
328                    (unsigned long)timer->secs,
329                    timer->nsecs / 100000000);
330         break;
331
332       case WTAP_TSPREC_CSEC:
333         g_snprintf(time_string_buf, sizeof time_string_buf,
334                    "%lu.%02d",
335                    (unsigned long)timer->secs,
336                    timer->nsecs / 10000000);
337         break;
338
339       case WTAP_TSPREC_MSEC:
340         g_snprintf(time_string_buf, sizeof time_string_buf,
341                    "%lu.%03d",
342                    (unsigned long)timer->secs,
343                    timer->nsecs / 1000000);
344         break;
345
346       case WTAP_TSPREC_USEC:
347         g_snprintf(time_string_buf, sizeof time_string_buf,
348                    "%lu.%06d",
349                    (unsigned long)timer->secs,
350                    timer->nsecs / 1000);
351         break;
352
353       case WTAP_TSPREC_NSEC:
354         g_snprintf(time_string_buf, sizeof time_string_buf,
355                    "%lu.%09d",
356                    (unsigned long)timer->secs,
357                    timer->nsecs);
358         break;
359
360       default:
361         g_snprintf(time_string_buf, sizeof time_string_buf,
362                    "Unknown precision %d",
363                    tsprecision);
364         break;
365       }
366       return time_string_buf;
367     } else {
368       ti_tm = localtime(&timer->secs);
369       if (ti_tm == NULL) {
370         g_snprintf(time_string_buf, sizeof time_string_buf, "Not representable");
371         return time_string_buf;
372       }
373       switch (tsprecision) {
374
375       case WTAP_TSPREC_SEC:
376         g_snprintf(time_string_buf, sizeof time_string_buf,
377                    "%04d-%02d-%02d %02d:%02d:%02d",
378                    ti_tm->tm_year + 1900,
379                    ti_tm->tm_mon + 1,
380                    ti_tm->tm_mday,
381                    ti_tm->tm_hour,
382                    ti_tm->tm_min,
383                    ti_tm->tm_sec);
384         break;
385
386       case WTAP_TSPREC_DSEC:
387         g_snprintf(time_string_buf, sizeof time_string_buf,
388                    "%04d-%02d-%02d %02d:%02d:%02d.%01d",
389                    ti_tm->tm_year + 1900,
390                    ti_tm->tm_mon + 1,
391                    ti_tm->tm_mday,
392                    ti_tm->tm_hour,
393                    ti_tm->tm_min,
394                    ti_tm->tm_sec,
395                    timer->nsecs / 100000000);
396         break;
397
398       case WTAP_TSPREC_CSEC:
399         g_snprintf(time_string_buf, sizeof time_string_buf,
400                    "%04d-%02d-%02d %02d:%02d:%02d.%02d",
401                    ti_tm->tm_year + 1900,
402                    ti_tm->tm_mon + 1,
403                    ti_tm->tm_mday,
404                    ti_tm->tm_hour,
405                    ti_tm->tm_min,
406                    ti_tm->tm_sec,
407                    timer->nsecs / 10000000);
408         break;
409
410       case WTAP_TSPREC_MSEC:
411         g_snprintf(time_string_buf, sizeof time_string_buf,
412                    "%04d-%02d-%02d %02d:%02d:%02d.%03d",
413                    ti_tm->tm_year + 1900,
414                    ti_tm->tm_mon + 1,
415                    ti_tm->tm_mday,
416                    ti_tm->tm_hour,
417                    ti_tm->tm_min,
418                    ti_tm->tm_sec,
419                    timer->nsecs / 1000000);
420         break;
421
422       case WTAP_TSPREC_USEC:
423         g_snprintf(time_string_buf, sizeof time_string_buf,
424                    "%04d-%02d-%02d %02d:%02d:%02d.%06d",
425                    ti_tm->tm_year + 1900,
426                    ti_tm->tm_mon + 1,
427                    ti_tm->tm_mday,
428                    ti_tm->tm_hour,
429                    ti_tm->tm_min,
430                    ti_tm->tm_sec,
431                    timer->nsecs / 1000);
432         break;
433
434       case WTAP_TSPREC_NSEC:
435         g_snprintf(time_string_buf, sizeof time_string_buf,
436                    "%04d-%02d-%02d %02d:%02d:%02d.%09d",
437                    ti_tm->tm_year + 1900,
438                    ti_tm->tm_mon + 1,
439                    ti_tm->tm_mday,
440                    ti_tm->tm_hour,
441                    ti_tm->tm_min,
442                    ti_tm->tm_sec,
443                    timer->nsecs);
444         break;
445
446       default:
447         g_snprintf(time_string_buf, sizeof time_string_buf,
448                    "Unknown precision %d",
449                    tsprecision);
450         break;
451       }
452       return time_string_buf;
453     }
454   }
455
456   g_snprintf(time_string_buf, sizeof time_string_buf, "n/a");
457   return time_string_buf;
458 }
459
460 static gchar *
461 relative_time_string(nstime_t *timer, int tsprecision, capture_info *cf_info, gboolean want_seconds)
462 {
463   const gchar  *second = want_seconds ? " second" : "";
464   const gchar  *plural = want_seconds ? "s" : "";
465   static gchar  time_string_buf[4+1+2+1+2+1+2+1+2+1+2+1+1];
466
467   if (cf_info->times_known && cf_info->packet_count > 0) {
468     switch (tsprecision) {
469
470     case WTAP_TSPREC_SEC:
471       g_snprintf(time_string_buf, sizeof time_string_buf,
472                  "%lu%s%s",
473                  (unsigned long)timer->secs,
474                  second,
475                  timer->secs == 1 ? "" : plural);
476       break;
477
478     case WTAP_TSPREC_DSEC:
479       g_snprintf(time_string_buf, sizeof time_string_buf,
480                  "%lu.%01d%s%s",
481                  (unsigned long)timer->secs,
482                  timer->nsecs / 100000000,
483                  second,
484                  (timer->secs == 1 && timer->nsecs == 0) ? "" : plural);
485       break;
486
487     case WTAP_TSPREC_CSEC:
488       g_snprintf(time_string_buf, sizeof time_string_buf,
489                  "%lu.%02d%s%s",
490                  (unsigned long)timer->secs,
491                  timer->nsecs / 10000000,
492                  second,
493                  (timer->secs == 1 && timer->nsecs == 0) ? "" : plural);
494       break;
495
496     case WTAP_TSPREC_MSEC:
497       g_snprintf(time_string_buf, sizeof time_string_buf,
498                  "%lu.%03d%s%s",
499                  (unsigned long)timer->secs,
500                  timer->nsecs / 1000000,
501                  second,
502                  (timer->secs == 1 && timer->nsecs == 0) ? "" : plural);
503       break;
504
505     case WTAP_TSPREC_USEC:
506       g_snprintf(time_string_buf, sizeof time_string_buf,
507                  "%lu.%06d%s%s",
508                  (unsigned long)timer->secs,
509                  timer->nsecs / 1000,
510                  second,
511                  (timer->secs == 1 && timer->nsecs == 0) ? "" : plural);
512       break;
513
514     case WTAP_TSPREC_NSEC:
515       g_snprintf(time_string_buf, sizeof time_string_buf,
516                  "%lu.%09d%s%s",
517                  (unsigned long)timer->secs,
518                  timer->nsecs,
519                  second,
520                  (timer->secs == 1 && timer->nsecs == 0) ? "" : plural);
521       break;
522
523     default:
524       g_snprintf(time_string_buf, sizeof time_string_buf,
525                  "Unknown precision %d",
526                  tsprecision);
527       break;
528     }
529     return time_string_buf;
530   }
531
532   g_snprintf(time_string_buf, sizeof time_string_buf, "n/a");
533   return time_string_buf;
534 }
535
536 static void print_value(const gchar *text_p1, gint width, const gchar *text_p2, double value) {
537   if (value > 0.0)
538     printf("%s%.*f%s\n", text_p1, width, value, text_p2);
539   else
540     printf("%sn/a\n", text_p1);
541 }
542
543 /* multi-line comments would conflict with the formatting that capinfos uses
544    we replace linefeeds with spaces */
545 static void
546 string_replace_newlines(gchar *str)
547 {
548   gchar *p;
549
550   if (str) {
551     p = str;
552     while (*p != '\0') {
553       if (*p == '\n')
554         *p = ' ';
555       if (*p == '\r')
556         *p = ' ';
557       p++;
558     }
559   }
560 }
561
562 static void
563 show_comment(wtap_optionblock_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_option_type* option, void* user_data _U_)
564 {
565   char *opt_str;
566
567   switch(option_id)
568   {
569   case OPT_COMMENT:
570     if (option != NULL && option->stringval != NULL) {
571       opt_str = g_strdup(option->stringval);
572       string_replace_newlines(opt_str);
573       printf("Capture comment:     %s\n", opt_str);
574       g_free(opt_str);
575     }
576     break;
577   default:
578     /* Don't show other options */
579     break;
580   }
581 }
582
583 static void
584 show_capture_hardware(wtap_optionblock_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_option_type* option, void* user_data _U_)
585 {
586   char *opt_str;
587
588   switch(option_id)
589   {
590   case OPT_SHB_HARDWARE:
591     if (option != NULL && option->stringval != NULL) {
592       opt_str = g_strdup(option->stringval);
593       string_replace_newlines(opt_str);
594       printf("Capture hardware:    %s\n", opt_str);
595       g_free(opt_str);
596     }
597     break;
598   default:
599     /* Don't show other options */
600     break;
601   }
602 }
603
604 static void
605 show_capture_os(wtap_optionblock_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_option_type* option, void* user_data _U_)
606 {
607   char *opt_str;
608
609   switch(option_id)
610   {
611   case OPT_SHB_OS:
612     if (option != NULL && option->stringval != NULL) {
613       opt_str = g_strdup(option->stringval);
614       string_replace_newlines(opt_str);
615       printf("Capture oper-sys:    %s\n", opt_str);
616       g_free(opt_str);
617     }
618     break;
619   default:
620     /* Don't show other options */
621     break;
622   }
623 }
624
625 static void
626 show_capture_userappl(wtap_optionblock_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_option_type* option, void* user_data _U_)
627 {
628   char *opt_str;
629
630   switch(option_id)
631   {
632   case OPT_SHB_USERAPPL:
633     if (option != NULL && option->stringval != NULL) {
634       opt_str = g_strdup(option->stringval);
635       string_replace_newlines(opt_str);
636       printf("Capture application: %s\n", opt_str);
637       g_free(opt_str);
638     }
639     break;
640   default:
641     /* Don't show other options */
642     break;
643   }
644 }
645
646 static void
647 print_stats(const gchar *filename, capture_info *cf_info)
648 {
649   const gchar           *file_type_string, *file_encap_string;
650   gchar                 *size_string;
651
652   /* Build printable strings for various stats */
653   file_type_string = wtap_file_type_subtype_string(cf_info->file_type);
654   file_encap_string = wtap_encap_string(cf_info->file_encap);
655
656   if (filename)           printf     ("File name:           %s\n", filename);
657   if (cap_file_type)      printf     ("File type:           %s%s\n",
658       file_type_string,
659       cf_info->iscompressed ? " (gzip compressed)" : "");
660
661   if (cap_file_encap) {
662     printf      ("File encapsulation:  %s\n", file_encap_string);
663     if (cf_info->file_encap == WTAP_ENCAP_PER_PACKET) {
664       int i;
665       printf    ("Encapsulation in use by packets (# of pkts):\n");
666       for (i=0; i<WTAP_NUM_ENCAP_TYPES; i++) {
667         if (cf_info->encap_counts[i] > 0)
668           printf("                     %s (%d)\n",
669                  wtap_encap_string(i), cf_info->encap_counts[i]);
670       }
671     }
672   }
673   if (cap_file_more_info) {
674     printf      ("File timestamp precision:  %s (%d)\n",
675       wtap_tsprec_string(cf_info->file_tsprec), cf_info->file_tsprec);
676   }
677
678   if (cap_snaplen && cf_info->snap_set)
679     printf     ("Packet size limit:   file hdr: %u bytes\n", cf_info->snaplen);
680   else if (cap_snaplen && !cf_info->snap_set)
681     printf     ("Packet size limit:   file hdr: (not set)\n");
682   if (cf_info->snaplen_max_inferred > 0) {
683     if (cf_info->snaplen_min_inferred == cf_info->snaplen_max_inferred)
684       printf     ("Packet size limit:   inferred: %u bytes\n", cf_info->snaplen_min_inferred);
685     else
686       printf     ("Packet size limit:   inferred: %u bytes - %u bytes (range)\n",
687           cf_info->snaplen_min_inferred, cf_info->snaplen_max_inferred);
688   }
689   if (cap_packet_count) {
690     printf     ("Number of packets:   ");
691     if (machine_readable) {
692       printf ("%u\n", cf_info->packet_count);
693     } else {
694       size_string = format_size(cf_info->packet_count, format_size_unit_none);
695       printf ("%s\n", size_string);
696       g_free(size_string);
697     }
698   }
699   if (cap_file_size) {
700     printf     ("File size:           ");
701     if (machine_readable) {
702       printf     ("%" G_GINT64_MODIFIER "d bytes\n", cf_info->filesize);
703     } else {
704       size_string = format_size(cf_info->filesize, format_size_unit_bytes);
705       printf ("%s\n", size_string);
706       g_free(size_string);
707     }
708   }
709   if (cap_data_size) {
710     printf     ("Data size:           ");
711     if (machine_readable) {
712       printf     ("%" G_GINT64_MODIFIER "u bytes\n", cf_info->packet_bytes);
713     } else {
714       size_string = format_size(cf_info->packet_bytes, format_size_unit_bytes);
715       printf ("%s\n", size_string);
716       g_free(size_string);
717     }
718   }
719   if (cf_info->times_known) {
720     if (cap_duration) /* XXX - shorten to hh:mm:ss */
721                           printf("Capture duration:    %s\n", relative_time_string(&cf_info->duration, cf_info->duration_tsprec, cf_info, TRUE));
722     if (cap_start_time)
723                           printf("First packet time:   %s\n", absolute_time_string(&cf_info->start_time, cf_info->start_time_tsprec, cf_info));
724     if (cap_end_time)
725                           printf("Last packet time:    %s\n", absolute_time_string(&cf_info->stop_time, cf_info->stop_time_tsprec, cf_info));
726     if (cap_data_rate_byte) {
727                           printf("Data byte rate:      ");
728       if (machine_readable) {
729         print_value("", 2, " bytes/sec",   cf_info->data_rate);
730       } else {
731         size_string = format_size((gint64)cf_info->data_rate, format_size_unit_bytes_s);
732         printf ("%s\n", size_string);
733         g_free(size_string);
734       }
735     }
736     if (cap_data_rate_bit) {
737                           printf("Data bit rate:       ");
738       if (machine_readable) {
739         print_value("", 2, " bits/sec",    cf_info->data_rate*8);
740       } else {
741         size_string = format_size((gint64)(cf_info->data_rate*8), format_size_unit_bits_s);
742         printf ("%s\n", size_string);
743         g_free(size_string);
744       }
745     }
746   }
747   if (cap_packet_size)    printf("Average packet size: %.2f bytes\n",        cf_info->packet_size);
748   if (cf_info->times_known) {
749     if (cap_packet_rate) {
750                           printf("Average packet rate: ");
751       if (machine_readable) {
752         print_value("", 2, " packets/sec", cf_info->packet_rate);
753       } else {
754         size_string = format_size((gint64)cf_info->packet_rate, format_size_unit_packets_s);
755         printf ("%s\n", size_string);
756         g_free(size_string);
757       }
758     }
759   }
760 #ifdef HAVE_LIBGCRYPT
761   if (cap_file_hashes) {
762     printf     ("SHA1:                %s\n", file_sha1);
763     printf     ("RIPEMD160:           %s\n", file_rmd160);
764     printf     ("MD5:                 %s\n", file_md5);
765   }
766 #endif /* HAVE_LIBGCRYPT */
767   if (cap_order)          printf     ("Strict time order:   %s\n", order_string(cf_info->order));
768
769   if (cap_comment) {
770     wtap_optionblock_foreach_option(cf_info->shb, show_comment, NULL);
771   }
772   if (cap_file_more_info) {
773     wtap_optionblock_foreach_option(cf_info->shb, show_capture_hardware, NULL);
774     wtap_optionblock_foreach_option(cf_info->shb, show_capture_os, NULL);
775     wtap_optionblock_foreach_option(cf_info->shb, show_capture_userappl, NULL);
776   }
777
778   if (cap_file_idb && cf_info->num_interfaces != 0) {
779     guint i;
780     g_assert(cf_info->num_interfaces == cf_info->idb_info_strings->len);
781     printf     ("Number of interfaces in file: %u\n", cf_info->num_interfaces);
782     for (i = 0; i < cf_info->idb_info_strings->len; i++) {
783       gchar *s = g_array_index(cf_info->idb_info_strings, gchar*, i);
784       printf   ("Interface #%u info:\n", i);
785       printf   ("%s", s);
786       printf   ("                     Number of packets = %u\n", cf_info->interface_ids[i]);
787     }
788   }
789 }
790
791 static void
792 putsep(void)
793 {
794   if (field_separator) putchar(field_separator);
795 }
796
797 static void
798 putquote(void)
799 {
800   if (quote_char) putchar(quote_char);
801 }
802
803 static void
804 print_stats_table_header_label(const gchar *label)
805 {
806   putsep();
807   putquote();
808   printf("%s", label);
809   putquote();
810 }
811
812 static void
813 print_stats_table_header(void)
814 {
815   putquote();
816   printf("File name");
817   putquote();
818
819   if (cap_file_type)      print_stats_table_header_label("File type");
820   if (cap_file_encap)     print_stats_table_header_label("File encapsulation");
821   if (cap_file_more_info) print_stats_table_header_label("File time precision");
822   if (cap_snaplen)        print_stats_table_header_label("Packet size limit");
823   if (cap_snaplen)        print_stats_table_header_label("Packet size limit min (inferred)");
824   if (cap_snaplen)        print_stats_table_header_label("Packet size limit max (inferred)");
825   if (cap_packet_count)   print_stats_table_header_label("Number of packets");
826   if (cap_file_size)      print_stats_table_header_label("File size (bytes)");
827   if (cap_data_size)      print_stats_table_header_label("Data size (bytes)");
828   if (cap_duration)       print_stats_table_header_label("Capture duration (seconds)");
829   if (cap_start_time)     print_stats_table_header_label("Start time");
830   if (cap_end_time)       print_stats_table_header_label("End time");
831   if (cap_data_rate_byte) print_stats_table_header_label("Data byte rate (bytes/sec)");
832   if (cap_data_rate_bit)  print_stats_table_header_label("Data bit rate (bits/sec)");
833   if (cap_packet_size)    print_stats_table_header_label("Average packet size (bytes)");
834   if (cap_packet_rate)    print_stats_table_header_label("Average packet rate (packets/sec)");
835 #ifdef HAVE_LIBGCRYPT
836   if (cap_file_hashes) {
837     print_stats_table_header_label("SHA1");
838     print_stats_table_header_label("RIPEMD160");
839     print_stats_table_header_label("MD5");
840   }
841 #endif /* HAVE_LIBGCRYPT */
842   if (cap_order)          print_stats_table_header_label("Strict time order");
843   if (cap_comment)        print_stats_table_header_label("Capture comment");
844   if (cap_file_more_info) {
845     print_stats_table_header_label("Capture hardware");
846     print_stats_table_header_label("Capture oper-sys");
847     print_stats_table_header_label("Capture application");
848   }
849
850   printf("\n");
851 }
852
853 static void
854 put_comment(wtap_optionblock_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_option_type* option, void* user_data _U_)
855 {
856   switch(option_id)
857   {
858   case OPT_COMMENT:
859     if (option != NULL && option->stringval != NULL) {
860       putsep();
861       putquote();
862       printf("%s", option->stringval);
863       putquote();
864     }
865     break;
866   default:
867     /* Don't show other options */
868     break;
869   }
870 }
871
872 static void
873 put_capture_hardware(wtap_optionblock_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_option_type* option, void* user_data _U_)
874 {
875   switch(option_id)
876   {
877   case OPT_SHB_HARDWARE:
878     if (option != NULL && option->stringval != NULL) {
879       putsep();
880       putquote();
881       printf("%s", option->stringval);
882       putquote();
883     }
884     break;
885   default:
886     /* Don't show other options */
887     break;
888   }
889 }
890
891 static void
892 put_capture_os(wtap_optionblock_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_option_type* option, void* user_data _U_)
893 {
894   switch(option_id)
895   {
896   case OPT_SHB_OS:
897     if (option != NULL && option->stringval != NULL) {
898       putsep();
899       putquote();
900       printf("%s", option->stringval);
901       putquote();
902     }
903     break;
904   default:
905     /* Don't show other options */
906     break;
907   }
908 }
909
910 static void
911 put_capture_userappl(wtap_optionblock_t block _U_, guint option_id, wtap_opttype_e option_type _U_, wtap_option_type* option, void* user_data _U_)
912 {
913   switch(option_id)
914   {
915   case OPT_SHB_USERAPPL:
916     if (option != NULL && option->stringval != NULL) {
917       putsep();
918       putquote();
919       printf("%s", option->stringval);
920       putquote();
921     }
922     break;
923   default:
924     /* Don't show other options */
925     break;
926   }
927 }
928
929 static void
930 print_stats_table(const gchar *filename, capture_info *cf_info)
931 {
932   const gchar           *file_type_string, *file_encap_string;
933
934   /* Build printable strings for various stats */
935   file_type_string = wtap_file_type_subtype_string(cf_info->file_type);
936   file_encap_string = wtap_encap_string(cf_info->file_encap);
937
938   if (filename) {
939     putquote();
940     printf("%s", filename);
941     putquote();
942   }
943
944   if (cap_file_type) {
945     putsep();
946     putquote();
947     printf("%s", file_type_string);
948     putquote();
949   }
950
951   /* ToDo: If WTAP_ENCAP_PER_PACKET, show the list of encapsulations encountered;
952    *       Output a line for each different encap with all fields repeated except
953    *        the encapsulation field which has "Per Packet: ..." for each
954    *        encapsulation type seen ?
955    */
956   if (cap_file_encap) {
957     putsep();
958     putquote();
959     printf("%s", file_encap_string);
960     putquote();
961   }
962
963   if (cap_file_more_info) {
964     putsep();
965     putquote();
966     printf("%s", wtap_tsprec_string(cf_info->file_tsprec));
967     putquote();
968   }
969
970   if (cap_snaplen) {
971     putsep();
972     putquote();
973     if (cf_info->snap_set)
974       printf("%u", cf_info->snaplen);
975     else
976       printf("(not set)");
977     putquote();
978     if (cf_info->snaplen_max_inferred > 0) {
979       putsep();
980       putquote();
981       printf("%u", cf_info->snaplen_min_inferred);
982       putquote();
983       putsep();
984       putquote();
985       printf("%u", cf_info->snaplen_max_inferred);
986       putquote();
987     }
988     else {
989       putsep();
990       putquote();
991       printf("n/a");
992       putquote();
993       putsep();
994       putquote();
995       printf("n/a");
996       putquote();
997     }
998   }
999
1000   if (cap_packet_count) {
1001     putsep();
1002     putquote();
1003     printf("%u", cf_info->packet_count);
1004     putquote();
1005   }
1006
1007   if (cap_file_size) {
1008     putsep();
1009     putquote();
1010     printf("%" G_GINT64_MODIFIER "d", cf_info->filesize);
1011     putquote();
1012   }
1013
1014   if (cap_data_size) {
1015     putsep();
1016     putquote();
1017     printf("%" G_GINT64_MODIFIER "u", cf_info->packet_bytes);
1018     putquote();
1019   }
1020
1021   if (cap_duration) {
1022     putsep();
1023     putquote();
1024     printf("%s", relative_time_string(&cf_info->duration, cf_info->duration_tsprec, cf_info, FALSE));
1025     putquote();
1026   }
1027
1028   if (cap_start_time) {
1029     putsep();
1030     putquote();
1031     printf("%s", absolute_time_string(&cf_info->start_time, cf_info->start_time_tsprec, cf_info));
1032     putquote();
1033   }
1034
1035   if (cap_end_time) {
1036     putsep();
1037     putquote();
1038     printf("%s", absolute_time_string(&cf_info->stop_time, cf_info->stop_time_tsprec, cf_info));
1039     putquote();
1040   }
1041
1042   if (cap_data_rate_byte) {
1043     putsep();
1044     putquote();
1045     if (cf_info->times_known)
1046       printf("%.2f", cf_info->data_rate);
1047     else
1048       printf("n/a");
1049     putquote();
1050   }
1051
1052   if (cap_data_rate_bit) {
1053     putsep();
1054     putquote();
1055     if (cf_info->times_known)
1056       printf("%.2f", cf_info->data_rate*8);
1057     else
1058       printf("n/a");
1059     putquote();
1060   }
1061
1062   if (cap_packet_size) {
1063     putsep();
1064     putquote();
1065     printf("%.2f", cf_info->packet_size);
1066     putquote();
1067   }
1068
1069   if (cap_packet_rate) {
1070     putsep();
1071     putquote();
1072     if (cf_info->times_known)
1073       printf("%.2f", cf_info->packet_rate);
1074     else
1075       printf("n/a");
1076     putquote();
1077   }
1078
1079 #ifdef HAVE_LIBGCRYPT
1080   if (cap_file_hashes) {
1081     putsep();
1082     putquote();
1083     printf("%s", file_sha1);
1084     putquote();
1085
1086     putsep();
1087     putquote();
1088     printf("%s", file_rmd160);
1089     putquote();
1090
1091     putsep();
1092     putquote();
1093     printf("%s", file_md5);
1094     putquote();
1095   }
1096 #endif /* HAVE_LIBGCRYPT */
1097
1098   if (cap_order) {
1099     putsep();
1100     putquote();
1101     printf("%s", order_string(cf_info->order));
1102     putquote();
1103   }
1104
1105   /*
1106    * this is silly to put into a table format, but oh well
1107    * note that there may be *more than one* of each of these types
1108    * of options
1109    */
1110   if (cap_comment) {
1111     wtap_optionblock_foreach_option(cf_info->shb, put_comment, NULL);
1112   }
1113
1114   if (cap_file_more_info) {
1115     wtap_optionblock_foreach_option(cf_info->shb, put_capture_hardware, NULL);
1116
1117     wtap_optionblock_foreach_option(cf_info->shb, put_capture_os, NULL);
1118
1119     wtap_optionblock_foreach_option(cf_info->shb, put_capture_userappl, NULL);
1120   }
1121
1122   printf("\n");
1123 }
1124
1125 static void
1126 cleanup_capture_info(capture_info *cf_info)
1127 {
1128   guint i;
1129   g_assert(cf_info != NULL);
1130
1131   g_free(cf_info->encap_counts);
1132   cf_info->encap_counts = NULL;
1133
1134   g_free(cf_info->interface_ids);
1135   cf_info->interface_ids = NULL;
1136
1137   if (cf_info->idb_info_strings) {
1138     for (i = 0; i < cf_info->idb_info_strings->len; i++) {
1139       gchar *s = g_array_index(cf_info->idb_info_strings, gchar*, i);
1140       g_free(s);
1141     }
1142     g_array_free(cf_info->idb_info_strings, TRUE);
1143   }
1144   cf_info->idb_info_strings = NULL;
1145 }
1146
1147 static int
1148 process_cap_file(wtap *wth, const char *filename)
1149 {
1150   int                   status = 0;
1151   int                   err;
1152   gchar                *err_info;
1153   gint64                size;
1154   gint64                data_offset;
1155
1156   guint32               packet = 0;
1157   gint64                bytes  = 0;
1158   guint32               snaplen_min_inferred = 0xffffffff;
1159   guint32               snaplen_max_inferred =          0;
1160   const struct wtap_pkthdr *phdr;
1161   capture_info          cf_info;
1162   gboolean              have_times = TRUE;
1163   nstime_t              start_time;
1164   int                   start_time_tsprec;
1165   nstime_t              stop_time;
1166   int                   stop_time_tsprec;
1167   nstime_t              cur_time;
1168   nstime_t              prev_time;
1169   gboolean              know_order = FALSE;
1170   order_t               order = IN_ORDER;
1171   guint                 i;
1172   wtapng_iface_descriptions_t *idb_info;
1173
1174   g_assert(wth != NULL);
1175   g_assert(filename != NULL);
1176
1177   nstime_set_zero(&start_time);
1178   start_time_tsprec = WTAP_TSPREC_UNKNOWN;
1179   nstime_set_zero(&stop_time);
1180   stop_time_tsprec = WTAP_TSPREC_UNKNOWN;
1181   nstime_set_zero(&cur_time);
1182   nstime_set_zero(&prev_time);
1183
1184   cf_info.shb = wtap_file_get_shb(wth);
1185
1186   cf_info.encap_counts = g_new0(int,WTAP_NUM_ENCAP_TYPES);
1187
1188   idb_info = wtap_file_get_idb_info(wth);
1189
1190   g_assert(idb_info->interface_data != NULL);
1191
1192   cf_info.num_interfaces = idb_info->interface_data->len;
1193   cf_info.interface_ids  = g_new0(guint32, cf_info.num_interfaces);
1194   cf_info.pkt_interface_id_unknown = 0;
1195
1196   cf_info.idb_info_strings = g_array_sized_new(FALSE, FALSE, sizeof(gchar*), cf_info.num_interfaces);
1197
1198   /* get IDB info strings */
1199   for (i = 0; i < cf_info.num_interfaces; i++) {
1200     const wtap_optionblock_t if_descr = g_array_index(idb_info->interface_data, wtap_optionblock_t, i);
1201     gchar *s = wtap_get_debug_if_descr(if_descr, 21, "\n");
1202     g_array_append_val(cf_info.idb_info_strings, s);
1203   }
1204
1205   g_free(idb_info);
1206   idb_info = NULL;
1207
1208   /* Tally up data that we need to parse through the file to find */
1209   while (wtap_read(wth, &err, &err_info, &data_offset))  {
1210     phdr = wtap_phdr(wth);
1211     if (phdr->presence_flags & WTAP_HAS_TS) {
1212       prev_time = cur_time;
1213       cur_time = phdr->ts;
1214       if (packet == 0) {
1215         start_time = phdr->ts;
1216         start_time_tsprec = phdr->pkt_tsprec;
1217         stop_time  = phdr->ts;
1218         stop_time_tsprec = phdr->pkt_tsprec;
1219         prev_time  = phdr->ts;
1220       }
1221       if (nstime_cmp(&cur_time, &prev_time) < 0) {
1222         order = NOT_IN_ORDER;
1223       }
1224       if (nstime_cmp(&cur_time, &start_time) < 0) {
1225         start_time = cur_time;
1226         start_time_tsprec = phdr->pkt_tsprec;
1227       }
1228       if (nstime_cmp(&cur_time, &stop_time) > 0) {
1229         stop_time = cur_time;
1230         stop_time_tsprec = phdr->pkt_tsprec;
1231       }
1232     } else {
1233       have_times = FALSE; /* at least one packet has no time stamp */
1234       if (order != NOT_IN_ORDER)
1235         order = ORDER_UNKNOWN;
1236     }
1237
1238     if (phdr->rec_type == REC_TYPE_PACKET) {
1239       bytes+=phdr->len;
1240       packet++;
1241
1242       /* If caplen < len for a rcd, then presumably           */
1243       /* 'Limit packet capture length' was done for this rcd. */
1244       /* Keep track as to the min/max actual snapshot lengths */
1245       /*  seen for this file.                                 */
1246       if (phdr->caplen < phdr->len) {
1247         if (phdr->caplen < snaplen_min_inferred)
1248           snaplen_min_inferred = phdr->caplen;
1249         if (phdr->caplen > snaplen_max_inferred)
1250           snaplen_max_inferred = phdr->caplen;
1251       }
1252
1253       /* Per-packet encapsulation */
1254       if (wtap_file_encap(wth) == WTAP_ENCAP_PER_PACKET) {
1255         if ((phdr->pkt_encap > 0) && (phdr->pkt_encap < WTAP_NUM_ENCAP_TYPES)) {
1256           cf_info.encap_counts[phdr->pkt_encap] += 1;
1257         } else {
1258           fprintf(stderr, "capinfos: Unknown per-packet encapsulation %d in frame %u of file \"%s\"\n",
1259                   phdr->pkt_encap, packet, filename);
1260         }
1261       }
1262
1263       /* Packet interface_id info */
1264       if (phdr->presence_flags & WTAP_HAS_INTERFACE_ID) {
1265         /* cf_info.num_interfaces is size, not index, so it's one more than max index */
1266         if (phdr->interface_id < cf_info.num_interfaces) {
1267           cf_info.interface_ids[phdr->interface_id] += 1;
1268         }
1269         else {
1270           cf_info.pkt_interface_id_unknown += 1;
1271         }
1272       }
1273       else {
1274         /* it's for interface_id 0 */
1275         if (cf_info.num_interfaces != 0) {
1276           cf_info.interface_ids[0] += 1;
1277         }
1278         else {
1279           cf_info.pkt_interface_id_unknown += 1;
1280         }
1281       }
1282     }
1283
1284   } /* while */
1285
1286   if (err != 0) {
1287     fprintf(stderr,
1288         "capinfos: An error occurred after reading %u packets from \"%s\": %s.\n",
1289         packet, filename, wtap_strerror(err));
1290     if (err == WTAP_ERR_SHORT_READ) {
1291         /* Don't give up completely with this one. */
1292         status = 1;
1293         fprintf(stderr,
1294           "  (will continue anyway, checksums might be incorrect)\n");
1295     } else {
1296         if (err_info != NULL) {
1297             fprintf(stderr, "(%s)\n", err_info);
1298             g_free(err_info);
1299         }
1300
1301         cleanup_capture_info(&cf_info);
1302         return 1;
1303     }
1304   }
1305
1306   /* File size */
1307   size = wtap_file_size(wth, &err);
1308   if (size == -1) {
1309     fprintf(stderr,
1310         "capinfos: Can't get size of \"%s\": %s.\n",
1311         filename, g_strerror(err));
1312     cleanup_capture_info(&cf_info);
1313     return 1;
1314   }
1315
1316   cf_info.filesize = size;
1317
1318   /* File Type */
1319   cf_info.file_type = wtap_file_type_subtype(wth);
1320   cf_info.iscompressed = wtap_iscompressed(wth);
1321
1322   /* File Encapsulation */
1323   cf_info.file_encap = wtap_file_encap(wth);
1324
1325   cf_info.file_tsprec = wtap_file_tsprec(wth);
1326
1327   /* Packet size limit (snaplen) */
1328   cf_info.snaplen = wtap_snapshot_length(wth);
1329   if (cf_info.snaplen > 0)
1330     cf_info.snap_set = TRUE;
1331   else
1332     cf_info.snap_set = FALSE;
1333
1334   cf_info.snaplen_min_inferred = snaplen_min_inferred;
1335   cf_info.snaplen_max_inferred = snaplen_max_inferred;
1336
1337   /* # of packets */
1338   cf_info.packet_count = packet;
1339
1340   /* File Times */
1341   cf_info.times_known = have_times;
1342   cf_info.start_time = start_time;
1343   cf_info.start_time_tsprec = start_time_tsprec;
1344   cf_info.stop_time = stop_time;
1345   cf_info.stop_time_tsprec = stop_time_tsprec;
1346   nstime_delta(&cf_info.duration, &stop_time, &start_time);
1347   /* Duration precision is the higher of the start and stop time precisions. */
1348   if (cf_info.stop_time_tsprec > cf_info.start_time_tsprec)
1349     cf_info.duration_tsprec = cf_info.stop_time_tsprec;
1350   else
1351     cf_info.duration_tsprec = cf_info.start_time_tsprec;
1352   cf_info.know_order = know_order;
1353   cf_info.order = order;
1354
1355   /* Number of packet bytes */
1356   cf_info.packet_bytes = bytes;
1357
1358   cf_info.data_rate   = 0.0;
1359   cf_info.packet_rate = 0.0;
1360   cf_info.packet_size = 0.0;
1361
1362   if (packet > 0) {
1363     double delta_time = nstime_to_sec(&stop_time) - nstime_to_sec(&start_time);
1364     if (delta_time > 0.0) {
1365       cf_info.data_rate   = (double)bytes  / delta_time; /* Data rate per second */
1366       cf_info.packet_rate = (double)packet / delta_time; /* packet rate per second */
1367     }
1368     cf_info.packet_size = (double)bytes / packet;                  /* Avg packet size      */
1369   }
1370
1371   if (long_report) {
1372     print_stats(filename, &cf_info);
1373   } else {
1374     print_stats_table(filename, &cf_info);
1375   }
1376
1377   cleanup_capture_info(&cf_info);
1378
1379   return status;
1380 }
1381
1382 static void
1383 print_usage(FILE *output)
1384 {
1385   fprintf(output, "\n");
1386   fprintf(output, "Usage: capinfos [options] <infile> ...\n");
1387   fprintf(output, "\n");
1388   fprintf(output, "General infos:\n");
1389   fprintf(output, "  -t display the capture file type\n");
1390   fprintf(output, "  -E display the capture file encapsulation\n");
1391   fprintf(output, "  -I display the capture file interface information\n");
1392   fprintf(output, "  -F display additional capture file information\n");
1393 #ifdef HAVE_LIBGCRYPT
1394   fprintf(output, "  -H display the SHA1, RMD160, and MD5 hashes of the file\n");
1395 #endif
1396   fprintf(output, "  -k display the capture comment\n");
1397   fprintf(output, "\n");
1398   fprintf(output, "Size infos:\n");
1399   fprintf(output, "  -c display the number of packets\n");
1400   fprintf(output, "  -s display the size of the file (in bytes)\n");
1401   fprintf(output, "  -d display the total length of all packets (in bytes)\n");
1402   fprintf(output, "  -l display the packet size limit (snapshot length)\n");
1403   fprintf(output, "\n");
1404   fprintf(output, "Time infos:\n");
1405   fprintf(output, "  -u display the capture duration (in seconds)\n");
1406   fprintf(output, "  -a display the capture start time\n");
1407   fprintf(output, "  -e display the capture end time\n");
1408   fprintf(output, "  -o display the capture file chronological status (True/False)\n");
1409   fprintf(output, "  -S display start and end times as seconds\n");
1410   fprintf(output, "\n");
1411   fprintf(output, "Statistic infos:\n");
1412   fprintf(output, "  -y display average data rate (in bytes/sec)\n");
1413   fprintf(output, "  -i display average data rate (in bits/sec)\n");
1414   fprintf(output, "  -z display average packet size (in bytes)\n");
1415   fprintf(output, "  -x display average packet rate (in packets/sec)\n");
1416   fprintf(output, "\n");
1417   fprintf(output, "Output format:\n");
1418   fprintf(output, "  -L generate long report (default)\n");
1419   fprintf(output, "  -T generate table report\n");
1420   fprintf(output, "  -M display machine-readable values in long reports\n");
1421   fprintf(output, "\n");
1422   fprintf(output, "Table report options:\n");
1423   fprintf(output, "  -R generate header record (default)\n");
1424   fprintf(output, "  -r do not generate header record\n");
1425   fprintf(output, "\n");
1426   fprintf(output, "  -B separate infos with TAB character (default)\n");
1427   fprintf(output, "  -m separate infos with comma (,) character\n");
1428   fprintf(output, "  -b separate infos with SPACE character\n");
1429   fprintf(output, "\n");
1430   fprintf(output, "  -N do not quote infos (default)\n");
1431   fprintf(output, "  -q quote infos with single quotes (')\n");
1432   fprintf(output, "  -Q quote infos with double quotes (\")\n");
1433   fprintf(output, "\n");
1434   fprintf(output, "Miscellaneous:\n");
1435   fprintf(output, "  -h display this help and exit\n");
1436   fprintf(output, "  -C cancel processing if file open fails (default is to continue)\n");
1437   fprintf(output, "  -A generate all infos (default)\n");
1438   fprintf(output, "\n");
1439   fprintf(output, "Options are processed from left to right order with later options superceding\n");
1440   fprintf(output, "or adding to earlier options.\n");
1441   fprintf(output, "\n");
1442   fprintf(output, "If no options are given the default is to display all infos in long report\n");
1443   fprintf(output, "output format.\n");
1444 #ifndef HAVE_LIBGCRYPT
1445   fprintf(output, "\nFile hashing support (-H) is not present.\n");
1446 #endif
1447 }
1448
1449 #ifdef HAVE_PLUGINS
1450 /*
1451  *  Don't report failures to load plugins because most (non-wiretap) plugins
1452  *  *should* fail to load (because we're not linked against libwireshark and
1453  *  dissector plugins need libwireshark).
1454  */
1455 static void
1456 failure_message(const char *msg_format _U_, va_list ap _U_)
1457 {
1458   return;
1459 }
1460 #endif
1461
1462 #ifdef HAVE_LIBGCRYPT
1463 static void
1464 hash_to_str(const unsigned char *hash, size_t length, char *str) {
1465   int i;
1466
1467   for (i = 0; i < (int) length; i++) {
1468     g_snprintf(str+(i*2), 3, "%02x", hash[i]);
1469   }
1470 }
1471 #endif /* HAVE_LIBGCRYPT */
1472
1473 int
1474 main(int argc, char *argv[])
1475 {
1476   GString *comp_info_str;
1477   GString *runtime_info_str;
1478   wtap  *wth;
1479   int    err;
1480   gchar *err_info;
1481   int    opt;
1482   int    overall_error_status;
1483   static const struct option long_options[] = {
1484       {"help", no_argument, NULL, 'h'},
1485       {"version", no_argument, NULL, 'v'},
1486       {0, 0, 0, 0 }
1487   };
1488
1489   int status = 0;
1490 #ifdef HAVE_PLUGINS
1491   char  *init_progfile_dir_error;
1492 #endif
1493 #ifdef HAVE_LIBGCRYPT
1494   FILE  *fh;
1495   char  *hash_buf = NULL;
1496   gcry_md_hd_t hd = NULL;
1497   size_t hash_bytes;
1498 #endif
1499
1500   /* Set the C-language locale to the native environment. */
1501   setlocale(LC_ALL, "");
1502
1503   /* Get the compile-time version information string */
1504   comp_info_str = get_compiled_version_info(NULL, NULL);
1505
1506   /* Get the run-time version information string */
1507   runtime_info_str = get_runtime_version_info(NULL);
1508
1509   /* Add it to the information to be reported on a crash. */
1510   ws_add_crash_info("Capinfos (Wireshark) %s\n"
1511          "\n"
1512          "%s"
1513          "\n"
1514          "%s",
1515       get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str);
1516
1517 #ifdef _WIN32
1518   arg_list_utf_16to8(argc, argv);
1519   create_app_running_mutex();
1520 #endif /* _WIN32 */
1521
1522   /*
1523    * Get credential information for later use.
1524    */
1525   init_process_policies();
1526   init_open_routines();
1527
1528 #ifdef HAVE_PLUGINS
1529   if ((init_progfile_dir_error = init_progfile_dir(argv[0], main))) {
1530     g_warning("capinfos: init_progfile_dir(): %s", init_progfile_dir_error);
1531     g_free(init_progfile_dir_error);
1532   } else {
1533     /* Register all the plugin types we have. */
1534     wtap_register_plugin_types(); /* Types known to libwiretap */
1535
1536     init_report_err(failure_message, NULL, NULL, NULL);
1537
1538     /* Scan for plugins.  This does *not* call their registration routines;
1539        that's done later. */
1540     scan_plugins();
1541
1542     /* Register all libwiretap plugin modules. */
1543     register_all_wiretap_modules();
1544   }
1545 #endif
1546
1547   /* Process the options */
1548   /* FILE_HASH_OPT will be "H" if libgcrypt is compiled in, so don't use "H" */
1549   while ((opt = getopt_long(argc, argv, "abcdehiklmoqrstuvxyzABCEF" FILE_HASH_OPT "ILMNQRST", long_options, NULL)) !=-1) {
1550
1551     switch (opt) {
1552
1553       case 't':
1554         if (report_all_infos) disable_all_infos();
1555         cap_file_type = TRUE;
1556         break;
1557
1558       case 'E':
1559         if (report_all_infos) disable_all_infos();
1560         cap_file_encap = TRUE;
1561         break;
1562
1563       case 'l':
1564         if (report_all_infos) disable_all_infos();
1565         cap_snaplen = TRUE;
1566         break;
1567
1568       case 'c':
1569         if (report_all_infos) disable_all_infos();
1570         cap_packet_count = TRUE;
1571         break;
1572
1573       case 's':
1574         if (report_all_infos) disable_all_infos();
1575         cap_file_size = TRUE;
1576         break;
1577
1578       case 'd':
1579         if (report_all_infos) disable_all_infos();
1580         cap_data_size = TRUE;
1581         break;
1582
1583       case 'u':
1584         if (report_all_infos) disable_all_infos();
1585         cap_duration = TRUE;
1586         break;
1587
1588       case 'a':
1589         if (report_all_infos) disable_all_infos();
1590         cap_start_time = TRUE;
1591         break;
1592
1593       case 'e':
1594         if (report_all_infos) disable_all_infos();
1595         cap_end_time = TRUE;
1596         break;
1597
1598       case 'S':
1599         time_as_secs = TRUE;
1600         break;
1601
1602       case 'y':
1603         if (report_all_infos) disable_all_infos();
1604         cap_data_rate_byte = TRUE;
1605         break;
1606
1607       case 'i':
1608         if (report_all_infos) disable_all_infos();
1609         cap_data_rate_bit = TRUE;
1610         break;
1611
1612       case 'z':
1613         if (report_all_infos) disable_all_infos();
1614         cap_packet_size = TRUE;
1615         break;
1616
1617       case 'x':
1618         if (report_all_infos) disable_all_infos();
1619         cap_packet_rate = TRUE;
1620         break;
1621
1622 #ifdef HAVE_LIBGCRYPT
1623       case 'H':
1624         if (report_all_infos) disable_all_infos();
1625         cap_file_hashes = TRUE;
1626         break;
1627 #endif
1628
1629       case 'o':
1630         if (report_all_infos) disable_all_infos();
1631         cap_order = TRUE;
1632         break;
1633
1634       case 'k':
1635         if (report_all_infos) disable_all_infos();
1636         cap_comment = TRUE;
1637         break;
1638
1639       case 'F':
1640         if (report_all_infos) disable_all_infos();
1641         cap_file_more_info = TRUE;
1642         break;
1643
1644       case 'I':
1645         if (report_all_infos) disable_all_infos();
1646         cap_file_idb = TRUE;
1647         break;
1648
1649       case 'C':
1650         continue_after_wtap_open_offline_failure = FALSE;
1651         break;
1652
1653       case 'A':
1654         enable_all_infos();
1655         break;
1656
1657       case 'L':
1658         long_report = TRUE;
1659         break;
1660
1661       case 'T':
1662         long_report = FALSE;
1663         break;
1664
1665       case 'M':
1666         machine_readable = TRUE;
1667         break;
1668
1669       case 'R':
1670         table_report_header = TRUE;
1671         break;
1672
1673       case 'r':
1674         table_report_header = FALSE;
1675         break;
1676
1677       case 'N':
1678         quote_char = '\0';
1679         break;
1680
1681       case 'q':
1682         quote_char = '\'';
1683         break;
1684
1685       case 'Q':
1686         quote_char = '"';
1687         break;
1688
1689       case 'B':
1690         field_separator = '\t';
1691         break;
1692
1693       case 'm':
1694         field_separator = ',';
1695         break;
1696
1697       case 'b':
1698         field_separator = ' ';
1699         break;
1700
1701       case 'h':
1702         printf("Capinfos (Wireshark) %s\n"
1703                "Print various information (infos) about capture files.\n"
1704                "See https://www.wireshark.org for more information.\n",
1705                get_ws_vcs_version_info());
1706         print_usage(stdout);
1707         exit(0);
1708         break;
1709
1710       case 'v':
1711         show_version("Capinfos (Wireshark)", comp_info_str, runtime_info_str);
1712         g_string_free(comp_info_str, TRUE);
1713         g_string_free(runtime_info_str, TRUE);
1714         exit(0);
1715         break;
1716
1717       case '?':              /* Bad flag - print usage message */
1718         print_usage(stderr);
1719         exit(1);
1720         break;
1721     }
1722   }
1723
1724   if ((argc - optind) < 1) {
1725     print_usage(stderr);
1726     exit(1);
1727   }
1728
1729   if (!long_report && table_report_header) {
1730     print_stats_table_header();
1731   }
1732
1733 #ifdef HAVE_LIBGCRYPT
1734   if (cap_file_hashes) {
1735     gcry_check_version(NULL);
1736     gcry_md_open(&hd, GCRY_MD_SHA1, 0);
1737     if (hd) {
1738       gcry_md_enable(hd, GCRY_MD_RMD160);
1739       gcry_md_enable(hd, GCRY_MD_MD5);
1740     }
1741     hash_buf = (char *)g_malloc(HASH_BUF_SIZE);
1742   }
1743 #endif
1744
1745   overall_error_status = 0;
1746
1747   for (opt = optind; opt < argc; opt++) {
1748
1749 #ifdef HAVE_LIBGCRYPT
1750     g_strlcpy(file_sha1, "<unknown>", HASH_STR_SIZE);
1751     g_strlcpy(file_rmd160, "<unknown>", HASH_STR_SIZE);
1752     g_strlcpy(file_md5, "<unknown>", HASH_STR_SIZE);
1753
1754     if (cap_file_hashes) {
1755       fh = ws_fopen(argv[opt], "rb");
1756       if (fh && hd) {
1757         while((hash_bytes = fread(hash_buf, 1, HASH_BUF_SIZE, fh)) > 0) {
1758           gcry_md_write(hd, hash_buf, hash_bytes);
1759         }
1760         gcry_md_final(hd);
1761         hash_to_str(gcry_md_read(hd, GCRY_MD_SHA1), HASH_SIZE_SHA1, file_sha1);
1762         hash_to_str(gcry_md_read(hd, GCRY_MD_RMD160), HASH_SIZE_RMD160, file_rmd160);
1763         hash_to_str(gcry_md_read(hd, GCRY_MD_MD5), HASH_SIZE_MD5, file_md5);
1764       }
1765       if (fh) fclose(fh);
1766       if (hd) gcry_md_reset(hd);
1767     }
1768 #endif /* HAVE_LIBGCRYPT */
1769
1770     wth = wtap_open_offline(argv[opt], WTAP_TYPE_AUTO, &err, &err_info, FALSE);
1771
1772     if (!wth) {
1773       fprintf(stderr, "capinfos: Can't open %s: %s\n", argv[opt],
1774           wtap_strerror(err));
1775       if (err_info != NULL) {
1776         fprintf(stderr, "(%s)\n", err_info);
1777         g_free(err_info);
1778       }
1779       overall_error_status = 1; /* remember that an error has occurred */
1780       if (!continue_after_wtap_open_offline_failure)
1781         exit(1); /* error status */
1782     }
1783
1784     if (wth) {
1785       if ((opt > optind) && (long_report))
1786         printf("\n");
1787       status = process_cap_file(wth, argv[opt]);
1788
1789       wtap_close(wth);
1790       if (status)
1791         exit(status);
1792     }
1793   }
1794
1795   return overall_error_status;
1796 }
1797
1798 /*
1799  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1800  *
1801  * Local variables:
1802  * c-basic-offset: 2
1803  * tab-width: 8
1804  * indent-tabs-mode: nil
1805  * End:
1806  *
1807  * vi: set shiftwidth=2 tabstop=8 expandtab:
1808  * :indentSize=2:tabSize=8:noTabs=true:
1809  */