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