drsuapi_SupportedExtensionsExt
[wireshark-sm.git] / capinfos.c
blobc5d564e3ceb58f4707cc69893679aad123fb097c
1 /* capinfos.c
2 * Reports capture file information including # of packets, duration, others
4 * Copyright 2004 Ian Schorr
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
14 * 2009-09-19: jyoung
16 * New capinfos features
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.
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.
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.
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).
44 #include <config.h>
45 #define WS_LOG_DOMAIN LOG_DOMAIN_MAIN
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <stdarg.h>
51 #include <locale.h>
53 #include <ws_exit_codes.h>
54 #include <wsutil/ws_getopt.h>
56 #include <glib.h>
58 #include <wiretap/wtap.h>
60 #include <wsutil/cmdarg_err.h>
61 #include <wsutil/filesystem.h>
62 #include <wsutil/privileges.h>
63 #include <cli_main.h>
64 #include <wsutil/version_info.h>
65 #include <wiretap/wtap_opttypes.h>
67 #ifdef HAVE_PLUGINS
68 #include <wsutil/plugins.h>
69 #endif
71 #include <wsutil/str_util.h>
72 #include <wsutil/to_str.h>
73 #include <wsutil/file_util.h>
74 #include <wsutil/ws_assert.h>
75 #include <wsutil/wslog.h>
77 #include <gcrypt.h>
79 #include "ui/failure_message.h"
82 * By default capinfos now continues processing
83 * the next filename if and when wiretap detects
84 * a problem opening or reading a file.
85 * Use the '-C' option to revert back to original
86 * capinfos behavior which is to abort any
87 * additional file processing at the first file
88 * open or read failure.
91 static bool stop_after_failure;
94 * table report variables
97 static bool long_report = true; /* By default generate long report */
98 static bool table_report_header = true; /* Generate column header by default */
99 static char field_separator = '\t'; /* Use TAB as field separator by default */
100 static char quote_char = '\0'; /* Do NOT quote fields by default */
101 static bool machine_readable; /* Display machine-readable numbers */
104 * capinfos has the ability to report on a number of
105 * various characteristics ("infos") for each input file.
107 * By default reporting of all info fields is enabled.
109 * Optionally the reporting of any specific info field
110 * or combination of info fields can be enabled with
111 * individual options.
114 static bool report_all_infos = true; /* Report all infos */
116 static bool cap_file_type = true; /* Report capture type */
117 static bool cap_file_encap = true; /* Report encapsulation */
118 static bool cap_snaplen = true; /* Packet size limit (snaplen)*/
119 static bool cap_packet_count = true; /* Report packet count */
120 static bool cap_file_size = true; /* Report file size */
121 static bool cap_comment = true; /* Display the capture comment */
122 static bool cap_file_more_info = true; /* Report more file info */
123 static bool cap_file_idb = true; /* Report Interface info */
124 static bool cap_file_nrb = true; /* Report Name Resolution Block info */
125 static bool cap_file_dsb = true; /* Report Decryption Secrets Block info */
127 static bool cap_data_size = true; /* Report packet byte size */
128 static bool cap_duration = true; /* Report capture duration */
129 static bool cap_earliest_packet_time = true; /* Report timestamp of earliest packet */
130 static bool cap_latest_packet_time = true; /* Report timestamp of latest packet */
131 static bool time_as_secs; /* Report time values as raw seconds */
133 static bool cap_data_rate_byte = true; /* Report data rate bytes/sec */
134 static bool cap_data_rate_bit = true; /* Report data rate bites/sec */
135 static bool cap_packet_size = true; /* Report average packet size */
136 static bool cap_packet_rate = true; /* Report average packet rate */
137 static bool cap_order = true; /* Report if packets are in chronological order (True/False) */
138 static bool pkt_comments = true; /* Report individual packet comments */
140 static bool cap_file_hashes = true; /* Calculate file hashes */
142 // Strongest to weakest
143 #define HASH_SIZE_SHA256 32
144 #define HASH_SIZE_SHA1 20
146 #define HASH_STR_SIZE (65) /* Max hash size * 2 + '\0' */
147 #define HASH_BUF_SIZE (1024 * 1024)
150 static char file_sha256[HASH_STR_SIZE];
151 static char file_sha1[HASH_STR_SIZE];
153 static char *hash_buf;
154 static gcry_md_hd_t hd;
156 static unsigned int num_ipv4_addresses;
157 static unsigned int num_ipv6_addresses;
158 static unsigned int num_decryption_secrets;
161 * If we have at least two packets with time stamps, and they're not in
162 * order - i.e., the later packet has a time stamp older than the earlier
163 * packet - the time stamps are known not to be in order.
165 * If every packet has a time stamp, and they're all in order, the time
166 * stamp is known to be in order.
168 * Otherwise, we have no idea.
170 typedef enum {
171 IN_ORDER,
172 NOT_IN_ORDER,
173 ORDER_UNKNOWN
174 } order_t;
176 typedef struct _pkt_cmt {
177 int recno;
178 char *cmt;
179 struct _pkt_cmt *next;
180 } pkt_cmt;
182 typedef struct _capture_info {
183 const char *filename;
184 uint16_t file_type;
185 wtap_compression_type compression_type;
186 int file_encap;
187 int file_tsprec;
188 wtap *wth;
189 int64_t filesize;
190 uint64_t packet_bytes;
191 bool times_known;
192 nstime_t earliest_packet_time;
193 int earliest_packet_time_tsprec;
194 nstime_t latest_packet_time;
195 int latest_packet_time_tsprec;
196 uint32_t packet_count;
197 bool snap_set; /* If set in capture file header */
198 uint32_t snaplen; /* value from the capture file header */
199 uint32_t snaplen_min_inferred; /* If caplen < len for 1 or more rcds */
200 uint32_t snaplen_max_inferred; /* ... */
201 bool drops_known;
202 uint32_t drop_count;
204 nstime_t duration;
205 int duration_tsprec;
206 double packet_rate;
207 double packet_size;
208 double data_rate; /* in bytes/s */
209 bool know_order;
210 order_t order;
212 int *encap_counts; /* array of per_packet encap counts; array has one entry per wtap_encap type */
213 pkt_cmt *pkt_cmts; /* list of packet comments */
215 unsigned int num_interfaces; /* number of IDBs, and thus size of interface_packet_counts array */
216 GArray *interface_packet_counts; /* array of per_packet interface_id counts; one entry per file IDB */
217 uint32_t pkt_interface_id_unknown; /* counts if packet interface_id didn't match a known one */
218 GArray *idb_info_strings; /* array of IDB info strings */
219 } capture_info;
221 static char *decimal_point;
223 static void
224 enable_all_infos(void)
226 report_all_infos = true;
228 cap_file_type = true;
229 cap_file_encap = true;
230 cap_snaplen = true;
231 cap_packet_count = true;
232 cap_file_size = true;
233 cap_comment = true;
234 pkt_comments = true;
235 cap_file_more_info = true;
236 cap_file_idb = true;
237 cap_file_nrb = true;
238 cap_file_dsb = true;
240 cap_data_size = true;
241 cap_duration = true;
242 cap_earliest_packet_time = true;
243 cap_latest_packet_time = true;
244 cap_order = true;
246 cap_data_rate_byte = true;
247 cap_data_rate_bit = true;
248 cap_packet_size = true;
249 cap_packet_rate = true;
251 cap_file_hashes = true;
254 static void
255 disable_all_infos(void)
257 report_all_infos = false;
259 cap_file_type = false;
260 cap_file_encap = false;
261 cap_snaplen = false;
262 cap_packet_count = false;
263 cap_file_size = false;
264 cap_comment = false;
265 pkt_comments = false;
266 cap_file_more_info = false;
267 cap_file_idb = false;
268 cap_file_nrb = false;
269 cap_file_dsb = false;
271 cap_data_size = false;
272 cap_duration = false;
273 cap_earliest_packet_time = false;
274 cap_latest_packet_time = false;
275 cap_order = false;
277 cap_data_rate_byte = false;
278 cap_data_rate_bit = false;
279 cap_packet_size = false;
280 cap_packet_rate = false;
282 cap_file_hashes = false;
285 static const char *
286 order_string(order_t order)
288 switch (order) {
290 case IN_ORDER:
291 return "True";
293 case NOT_IN_ORDER:
294 return "False";
296 case ORDER_UNKNOWN:
297 return "Unknown";
299 default:
300 return "???"; /* "cannot happen" (the next step is "Profit!") */
304 static char *
305 absolute_time_string(nstime_t *timer, int tsprecision, capture_info *cf_info)
308 * https://web.archive.org/web/20120513133703/http://www.idrbt.ac.in/publications/workingpapers/Working%20Paper%20No.%209.pdf
310 * says:
312 * A 64-bit Unix time would be safe for the indefinite future, as
313 * this variable would not overflow until 2**63 or
314 * 9,223,372,036,854,775,808 (over nine quintillion) seconds
315 * after the beginning of the Unix epoch - corresponding to
316 * GMT 15:30:08, Sunday, 4th December, 292,277,026,596.
318 * So, if we're displaying the time as YYYY-MM-DD HH:MM:SS.SSSSSSSSS,
319 * we'll have the buffer be large enough for a date of the format
320 * 292277026596-MM-DD HH:MM:SS.SSSSSSSSS, which is the biggest value
321 * you'll get with a 64-bit time_t and a nanosecond-resolution
322 * fraction-of-a-second.
324 * That's 12+1+2+1+2+1+2+1+2+2+2+1+9+1, including the terminating
325 * \0, or 39.
327 * If we're displaying the time as epoch time, and the time is
328 * unsigned, 2^64-1 is 18446744073709551615, so the buffer has
329 * to be big enough for 18446744073709551615.999999999. That's
330 * 20+1+9+1, including the terminating '\0', or 31. If it's
331 * signed, 2^63 is 9223372036854775808, so the buffer has to
332 * be big enough for -9223372036854775808.999999999, which is
333 * again 20+1+9+1, or 31.
335 * So we go with 39.
337 static char time_string_buf[39];
339 if (cf_info->times_known && cf_info->packet_count > 0) {
340 if (time_as_secs) {
341 display_epoch_time(time_string_buf, sizeof time_string_buf, timer, tsprecision);
342 } else {
343 format_nstime_as_iso8601(time_string_buf, sizeof time_string_buf, timer, decimal_point, true, tsprecision);
345 } else {
346 snprintf(time_string_buf, sizeof time_string_buf, "n/a");
348 return time_string_buf;
351 static char *
352 relative_time_string(nstime_t *timer, int tsprecision, capture_info *cf_info, bool want_seconds)
354 const char *second = want_seconds ? " second" : "";
355 const char *plural = want_seconds ? "s" : "";
357 * If we're displaying the time as epoch time, and the time is
358 * unsigned, 2^64-1 is 18446744073709551615, so the buffer has
359 * to be big enough for "18446744073709551615.999999999 seconds".
360 * That's 20+1+9+1+7+1, including the terminating '\0', or 39.
361 * If it'ssigned, 2^63 is 9223372036854775808, so the buffer has to
362 * be big enough for "-9223372036854775808.999999999 seconds",
363 * which is again 20+1+9+1+7+1, or 39.
365 static char time_string_buf[39];
367 if (cf_info->times_known && cf_info->packet_count > 0) {
368 char *ptr;
369 size_t remaining;
370 int num_bytes;
372 ptr = time_string_buf;
373 remaining = sizeof time_string_buf;
374 num_bytes = snprintf(ptr, remaining,
375 "%"PRId64,
376 (int64_t)timer->secs);
377 if (num_bytes < 0) {
379 * That got an error.
380 * Not much else we can do.
382 snprintf(ptr, remaining, "snprintf() failed");
383 return time_string_buf;
385 if ((unsigned int)num_bytes >= remaining) {
387 * That filled up or would have overflowed the buffer.
388 * Nothing more we can do.
390 return time_string_buf;
392 ptr += num_bytes;
393 remaining -= num_bytes;
395 if (tsprecision != 0) {
397 * Append the fractional part.
399 num_bytes = format_fractional_part_nsecs(ptr, remaining, timer->nsecs, decimal_point, tsprecision);
400 if ((unsigned int)num_bytes >= remaining) {
402 * That filled up or would have overflowed the buffer.
403 * Nothing more we can do.
405 return time_string_buf;
407 ptr += num_bytes;
408 remaining -= num_bytes;
412 * Append the units.
414 snprintf(ptr, remaining, "%s%s",
415 second,
416 timer->secs == 1 ? "" : plural);
418 return time_string_buf;
421 snprintf(time_string_buf, sizeof time_string_buf, "n/a");
422 return time_string_buf;
425 static void print_value(const char *text_p1, int width, const char *text_p2, double value)
427 if (value > 0.0)
428 printf("%s%.*f%s\n", text_p1, width, value, text_p2);
429 else
430 printf("%sn/a\n", text_p1);
433 /* multi-line comments would conflict with the formatting that capinfos uses
434 we replace linefeeds with spaces */
435 static void
436 string_replace_newlines(char *str)
438 char *p;
440 if (str) {
441 p = str;
442 while (*p != '\0') {
443 if (*p == '\n')
444 *p = ' ';
445 if (*p == '\r')
446 *p = ' ';
447 p++;
452 static void
453 show_option_string(const char *prefix, const char *option_str)
455 char *str;
457 if (option_str != NULL && option_str[0] != '\0') {
458 str = g_strdup(option_str);
459 string_replace_newlines(str);
460 printf("%s%s\n", prefix, str);
461 g_free(str);
465 static void
466 print_stats(const char *filename, capture_info *cf_info)
468 const char *file_type_string, *file_encap_string;
469 char *size_string;
470 pkt_cmt *p, *prev;
472 /* Build printable strings for various stats */
473 if (machine_readable) {
474 file_type_string = wtap_file_type_subtype_name(cf_info->file_type);
475 file_encap_string = wtap_encap_name(cf_info->file_encap);
477 else {
478 file_type_string = wtap_file_type_subtype_description(cf_info->file_type);
479 file_encap_string = wtap_encap_description(cf_info->file_encap);
482 if (filename) printf ("File name: %s\n", filename);
483 if (cap_file_type) {
484 const char *compression_type_description;
485 compression_type_description = wtap_compression_type_description(cf_info->compression_type);
486 if (compression_type_description == NULL)
487 printf ("File type: %s\n",
488 file_type_string);
489 else
490 printf ("File type: %s (%s)\n",
491 file_type_string, compression_type_description);
493 if (cap_file_encap) {
494 printf ("File encapsulation: %s\n", file_encap_string);
495 if (cf_info->file_encap == WTAP_ENCAP_PER_PACKET) {
496 int i;
497 printf ("Encapsulation in use by packets (# of pkts):\n");
498 for (i=0; i<WTAP_NUM_ENCAP_TYPES; i++) {
499 if (cf_info->encap_counts[i] > 0)
500 printf(" %s (%d)\n",
501 wtap_encap_description(i), cf_info->encap_counts[i]);
505 if (cap_file_more_info) {
506 printf ("File timestamp precision: %s (%d)\n",
507 wtap_tsprec_string(cf_info->file_tsprec), cf_info->file_tsprec);
510 if (cap_snaplen && cf_info->snap_set)
511 printf ("Packet size limit: file hdr: %u bytes\n", cf_info->snaplen);
512 else if (cap_snaplen && !cf_info->snap_set)
513 printf ("Packet size limit: file hdr: (not set)\n");
514 if (cf_info->snaplen_max_inferred > 0) {
515 if (cf_info->snaplen_min_inferred == cf_info->snaplen_max_inferred)
516 printf ("Packet size limit: inferred: %u bytes\n", cf_info->snaplen_min_inferred);
517 else
518 printf ("Packet size limit: inferred: %u bytes - %u bytes (range)\n",
519 cf_info->snaplen_min_inferred, cf_info->snaplen_max_inferred);
521 if (cap_packet_count) {
522 printf ("Number of packets: ");
523 if (machine_readable) {
524 printf ("%u\n", cf_info->packet_count);
525 } else {
526 size_string = format_size(cf_info->packet_count, FORMAT_SIZE_UNIT_NONE, 0);
527 printf ("%s\n", size_string);
528 g_free(size_string);
531 if (cap_file_size) {
532 printf ("File size: ");
533 if (machine_readable) {
534 printf ("%" PRId64 " bytes\n", cf_info->filesize);
535 } else {
536 size_string = format_size(cf_info->filesize, FORMAT_SIZE_UNIT_BYTES, 0);
537 printf ("%s\n", size_string);
538 g_free(size_string);
541 if (cap_data_size) {
542 printf ("Data size: ");
543 if (machine_readable) {
544 printf ("%" PRIu64 " bytes\n", cf_info->packet_bytes);
545 } else {
546 size_string = format_size(cf_info->packet_bytes, FORMAT_SIZE_UNIT_BYTES, 0);
547 printf ("%s\n", size_string);
548 g_free(size_string);
551 if (cf_info->times_known) {
552 if (cap_duration) /* XXX - shorten to hh:mm:ss */
553 printf("Capture duration: %s\n", relative_time_string(&cf_info->duration, cf_info->duration_tsprec, cf_info, true));
554 if (cap_earliest_packet_time)
555 printf("Earliest packet time: %s\n", absolute_time_string(&cf_info->earliest_packet_time, cf_info->earliest_packet_time_tsprec, cf_info));
556 if (cap_latest_packet_time)
557 printf("Latest packet time: %s\n", absolute_time_string(&cf_info->latest_packet_time, cf_info->latest_packet_time_tsprec, cf_info));
558 if (cap_data_rate_byte) {
559 printf("Data byte rate: ");
560 if (machine_readable) {
561 print_value("", 2, " bytes/sec", cf_info->data_rate);
562 } else {
563 size_string = format_size((int64_t)cf_info->data_rate, FORMAT_SIZE_UNIT_BYTES_S, 0);
564 printf ("%s\n", size_string);
565 g_free(size_string);
568 if (cap_data_rate_bit) {
569 printf("Data bit rate: ");
570 if (machine_readable) {
571 print_value("", 2, " bits/sec", cf_info->data_rate*8);
572 } else {
573 size_string = format_size((int64_t)(cf_info->data_rate*8), FORMAT_SIZE_UNIT_BITS_S, 0);
574 printf ("%s\n", size_string);
575 g_free(size_string);
579 if (cap_packet_size) printf("Average packet size: %.2f bytes\n", cf_info->packet_size);
580 if (cf_info->times_known) {
581 if (cap_packet_rate) {
582 printf("Average packet rate: ");
583 if (machine_readable) {
584 print_value("", 2, " packets/sec", cf_info->packet_rate);
585 } else {
586 size_string = format_size((int64_t)cf_info->packet_rate, FORMAT_SIZE_UNIT_PACKETS_S, 0);
587 printf ("%s\n", size_string);
588 g_free(size_string);
592 if (cap_file_hashes) {
593 printf ("SHA256: %s\n", file_sha256);
594 printf ("SHA1: %s\n", file_sha1);
596 if (cap_order) printf ("Strict time order: %s\n", order_string(cf_info->order));
598 bool has_multiple_sections = (wtap_file_get_num_shbs(cf_info->wth) > 1);
600 for (unsigned int section_number = 0;
601 section_number < wtap_file_get_num_shbs(cf_info->wth);
602 section_number++) {
603 wtap_block_t shb;
605 // If we have more than one section, add headers for each section.
606 if (has_multiple_sections)
607 printf("Section %u:\n\n", section_number);
609 shb = wtap_file_get_shb(cf_info->wth, section_number);
610 if (shb != NULL) {
611 if (cap_file_more_info) {
612 char *str;
614 if (wtap_block_get_string_option_value(shb, OPT_SHB_HARDWARE, &str) == WTAP_OPTTYPE_SUCCESS)
615 show_option_string("Capture hardware: ", str);
616 if (wtap_block_get_string_option_value(shb, OPT_SHB_OS, &str) == WTAP_OPTTYPE_SUCCESS)
617 show_option_string("Capture oper-sys: ", str);
618 if (wtap_block_get_string_option_value(shb, OPT_SHB_USERAPPL, &str) == WTAP_OPTTYPE_SUCCESS)
619 show_option_string("Capture application: ", str);
621 if (cap_comment) {
622 unsigned int i;
623 char *str;
625 for (i = 0; wtap_block_get_nth_string_option_value(shb, OPT_COMMENT, i, &str) == WTAP_OPTTYPE_SUCCESS; i++) {
626 show_option_string("Capture comment: ", str);
632 if (pkt_comments && cf_info->pkt_cmts != NULL) {
633 for (p = cf_info->pkt_cmts; p != NULL; prev = p, p = p->next, g_free(prev)) {
634 if (machine_readable){
635 printf("Packet %d Comment: %s\n", p->recno, g_strescape(p->cmt, NULL));
636 } else {
637 printf("Packet %d Comment: %s\n", p->recno, p->cmt);
639 g_free(p->cmt);
643 if (cap_file_idb && cf_info->num_interfaces != 0) {
644 unsigned int i;
645 ws_assert(cf_info->num_interfaces == cf_info->idb_info_strings->len);
646 printf ("Number of interfaces in file: %u\n", cf_info->num_interfaces);
647 for (i = 0; i < cf_info->idb_info_strings->len; i++) {
648 char *s = g_array_index(cf_info->idb_info_strings, char*, i);
649 uint32_t packet_count = 0;
650 if (i < cf_info->interface_packet_counts->len)
651 packet_count = g_array_index(cf_info->interface_packet_counts, uint32_t, i);
652 printf ("Interface #%u info:\n", i);
653 printf ("%s", s);
654 printf (" Number of packets = %u\n", packet_count);
658 if (cap_file_nrb) {
659 if (num_ipv4_addresses != 0)
660 printf ("Number of resolved IPv4 addresses in file: %u\n", num_ipv4_addresses);
661 if (num_ipv6_addresses != 0)
662 printf ("Number of resolved IPv6 addresses in file: %u\n", num_ipv6_addresses);
664 if (cap_file_dsb) {
665 if (num_decryption_secrets != 0)
666 printf ("Number of decryption secrets in file: %u\n", num_decryption_secrets);
670 static void
671 putsep(void)
673 if (field_separator) putchar(field_separator);
676 static void
677 putquote(void)
679 if (quote_char) putchar(quote_char);
682 static void
683 print_stats_table_header_label(const char *label)
685 putsep();
686 putquote();
687 printf("%s", label);
688 putquote();
691 static void
692 print_stats_table_header(capture_info *cf_info)
694 pkt_cmt *p;
695 char *buf;
696 size_t buf_len;
698 putquote();
699 printf("File name");
700 putquote();
702 if (cap_file_type) print_stats_table_header_label("File type");
703 if (cap_file_encap) print_stats_table_header_label("File encapsulation");
704 if (cap_file_more_info) print_stats_table_header_label("File time precision");
705 if (cap_snaplen) {
706 print_stats_table_header_label("Packet size limit");
707 print_stats_table_header_label("Packet size limit min (inferred)");
708 print_stats_table_header_label("Packet size limit max (inferred)");
710 if (cap_packet_count) print_stats_table_header_label("Number of packets");
711 if (cap_file_size) print_stats_table_header_label("File size (bytes)");
712 if (cap_data_size) print_stats_table_header_label("Data size (bytes)");
713 if (cap_duration) print_stats_table_header_label("Capture duration (seconds)");
714 if (cap_earliest_packet_time) print_stats_table_header_label("Start time");
715 if (cap_latest_packet_time) print_stats_table_header_label("End time");
716 if (cap_data_rate_byte) print_stats_table_header_label("Data byte rate (bytes/sec)");
717 if (cap_data_rate_bit) print_stats_table_header_label("Data bit rate (bits/sec)");
718 if (cap_packet_size) print_stats_table_header_label("Average packet size (bytes)");
719 if (cap_packet_rate) print_stats_table_header_label("Average packet rate (packets/sec)");
720 if (cap_file_hashes) {
721 print_stats_table_header_label("SHA256");
722 print_stats_table_header_label("SHA1");
724 if (cap_order) print_stats_table_header_label("Strict time order");
725 if (cap_file_more_info) {
726 print_stats_table_header_label("Capture hardware");
727 print_stats_table_header_label("Capture oper-sys");
728 print_stats_table_header_label("Capture application");
730 if (cap_comment) print_stats_table_header_label("Capture comment");
732 if (pkt_comments && cf_info->pkt_cmts != NULL) {
733 /* Packet 2^64 Comment" + NULL */
734 buf_len = strlen("Packet 18446744073709551616 Comment") + 1;
735 buf = (char *)g_malloc0(buf_len);
737 for (p = cf_info->pkt_cmts; p != NULL; p = p->next) {
738 snprintf(buf, buf_len, "Packet %d Comment", p->recno);
739 print_stats_table_header_label(buf);
743 printf("\n");
746 static void
747 print_stats_table(const char *filename, capture_info *cf_info)
749 const char *file_type_string, *file_encap_string;
750 pkt_cmt *p, *prev;
752 /* Build printable strings for various stats */
753 file_type_string = wtap_file_type_subtype_name(cf_info->file_type);
754 file_encap_string = wtap_encap_name(cf_info->file_encap);
756 if (filename) {
757 putquote();
758 printf("%s", filename);
759 putquote();
762 if (cap_file_type) {
763 putsep();
764 putquote();
765 printf("%s", file_type_string);
766 putquote();
769 /* ToDo: If WTAP_ENCAP_PER_PACKET, show the list of encapsulations encountered;
770 * Output a line for each different encap with all fields repeated except
771 * the encapsulation field which has "Per Packet: ..." for each
772 * encapsulation type seen ?
774 if (cap_file_encap) {
775 putsep();
776 putquote();
777 printf("%s", file_encap_string);
778 putquote();
781 if (cap_file_more_info) {
782 putsep();
783 putquote();
784 printf("%s", wtap_tsprec_string(cf_info->file_tsprec));
785 putquote();
788 if (cap_snaplen) {
789 putsep();
790 putquote();
791 if (cf_info->snap_set)
792 printf("%u", cf_info->snaplen);
793 else
794 printf("(not set)");
795 putquote();
796 if (cf_info->snaplen_max_inferred > 0) {
797 putsep();
798 putquote();
799 printf("%u", cf_info->snaplen_min_inferred);
800 putquote();
801 putsep();
802 putquote();
803 printf("%u", cf_info->snaplen_max_inferred);
804 putquote();
806 else {
807 putsep();
808 putquote();
809 printf("n/a");
810 putquote();
811 putsep();
812 putquote();
813 printf("n/a");
814 putquote();
818 if (cap_packet_count) {
819 putsep();
820 putquote();
821 printf("%u", cf_info->packet_count);
822 putquote();
825 if (cap_file_size) {
826 putsep();
827 putquote();
828 printf("%" PRId64, cf_info->filesize);
829 putquote();
832 if (cap_data_size) {
833 putsep();
834 putquote();
835 printf("%" PRIu64, cf_info->packet_bytes);
836 putquote();
839 if (cap_duration) {
840 putsep();
841 putquote();
842 printf("%s", relative_time_string(&cf_info->duration, cf_info->duration_tsprec, cf_info, false));
843 putquote();
846 if (cap_earliest_packet_time) {
847 putsep();
848 putquote();
849 printf("%s", absolute_time_string(&cf_info->earliest_packet_time, cf_info->earliest_packet_time_tsprec, cf_info));
850 putquote();
853 if (cap_latest_packet_time) {
854 putsep();
855 putquote();
856 printf("%s", absolute_time_string(&cf_info->latest_packet_time, cf_info->latest_packet_time_tsprec, cf_info));
857 putquote();
860 if (cap_data_rate_byte) {
861 putsep();
862 putquote();
863 if (cf_info->times_known)
864 printf("%.2f", cf_info->data_rate);
865 else
866 printf("n/a");
867 putquote();
870 if (cap_data_rate_bit) {
871 putsep();
872 putquote();
873 if (cf_info->times_known)
874 printf("%.2f", cf_info->data_rate*8);
875 else
876 printf("n/a");
877 putquote();
880 if (cap_packet_size) {
881 putsep();
882 putquote();
883 printf("%.2f", cf_info->packet_size);
884 putquote();
887 if (cap_packet_rate) {
888 putsep();
889 putquote();
890 if (cf_info->times_known)
891 printf("%.2f", cf_info->packet_rate);
892 else
893 printf("n/a");
894 putquote();
897 if (cap_file_hashes) {
898 putsep();
899 putquote();
900 printf("%s", file_sha256);
901 putquote();
903 putsep();
904 putquote();
905 printf("%s", file_sha1);
906 putquote();
909 if (cap_order) {
910 putsep();
911 putquote();
912 printf("%s", order_string(cf_info->order));
913 putquote();
916 for (unsigned section_number = 0;
917 section_number < wtap_file_get_num_shbs(cf_info->wth);
918 section_number++) {
919 wtap_block_t shb;
921 shb = wtap_file_get_shb(cf_info->wth, section_number);
922 if (cap_file_more_info) {
923 char *str;
925 putsep();
926 putquote();
927 if (wtap_block_get_string_option_value(shb, OPT_SHB_HARDWARE, &str) == WTAP_OPTTYPE_SUCCESS) {
928 printf("%s", str);
930 putquote();
932 putsep();
933 putquote();
934 if (wtap_block_get_string_option_value(shb, OPT_SHB_OS, &str) == WTAP_OPTTYPE_SUCCESS) {
935 printf("%s", str);
937 putquote();
939 putsep();
940 putquote();
941 if (wtap_block_get_string_option_value(shb, OPT_SHB_USERAPPL, &str) == WTAP_OPTTYPE_SUCCESS) {
942 printf("%s", str);
944 putquote();
948 * One might argue that the following is silly to put into a table format,
949 * but oh well note that there may be *more than one* of each of these types
950 * of options. To mitigate some of the potential silliness the if(cap_comment)
951 * block is moved AFTER the if(cap_file_more_info) block. This will make any
952 * comments the last item(s) in each row. We now have a new -K option to
953 * disable cap_comment to more easily manage the potential silliness.
954 * Potential silliness includes multiple comments (therefore resulting in
955 * more than one additional column and/or comments with embedded newlines
956 * and/or possible delimiters).
958 * To mitigate embedded newlines and other special characters, use -M
960 if (cap_comment) {
961 unsigned int i;
962 char *opt_comment;
963 bool have_cap = false;
965 for (i = 0; wtap_block_get_nth_string_option_value(shb, OPT_COMMENT, i, &opt_comment) == WTAP_OPTTYPE_SUCCESS; i++) {
966 have_cap = true;
967 putsep();
968 putquote();
969 if (machine_readable){
970 printf("%s", g_strescape(opt_comment, NULL));
971 } else {
972 printf("%s", opt_comment);
974 putquote();
976 if(!have_cap) {
977 /* Maintain column alignment when we have no OPT_COMMENT */
978 putsep();
979 putquote();
980 putquote();
986 if (pkt_comments && cf_info->pkt_cmts != NULL) {
987 for(p = cf_info->pkt_cmts; p != NULL; prev = p, p = p->next, g_free(prev)) {
988 putsep();
989 putquote();
990 if (machine_readable) {
991 printf("%s", g_strescape(p->cmt, NULL));
992 } else {
993 printf("%s", p->cmt);
995 g_free(p->cmt);
996 putquote();
1000 printf("\n");
1003 static void
1004 cleanup_capture_info(capture_info *cf_info)
1006 unsigned int i;
1007 ws_assert(cf_info != NULL);
1009 g_free(cf_info->encap_counts);
1010 cf_info->encap_counts = NULL;
1012 g_array_free(cf_info->interface_packet_counts, true);
1013 cf_info->interface_packet_counts = NULL;
1015 if (cf_info->idb_info_strings) {
1016 for (i = 0; i < cf_info->idb_info_strings->len; i++) {
1017 char *s = g_array_index(cf_info->idb_info_strings, char*, i);
1018 g_free(s);
1020 g_array_free(cf_info->idb_info_strings, true);
1022 cf_info->idb_info_strings = NULL;
1025 static void
1026 count_ipv4_address(const unsigned int addr _U_, const char *name _U_, const bool static_entry _U_)
1028 num_ipv4_addresses++;
1031 static void
1032 count_ipv6_address(const void *addrp _U_, const char *name _U_, const bool static_entry _U_)
1034 num_ipv6_addresses++;
1037 static void
1038 count_decryption_secret(uint32_t secrets_type _U_, const void *secrets _U_, unsigned int size _U_)
1040 /* XXX - count them based on the secrets type (which is an opaque code,
1041 not a small integer)? */
1042 num_decryption_secrets++;
1045 static void
1046 hash_to_str(const unsigned char *hash, size_t length, char *str)
1048 int i;
1050 for (i = 0; i < (int) length; i++) {
1051 snprintf(str+(i*2), 3, "%02x", hash[i]);
1055 static void
1056 calculate_hashes(const char *filename)
1058 FILE *fh;
1059 size_t hash_bytes;
1061 (void) g_strlcpy(file_sha256, "<unknown>", HASH_STR_SIZE);
1062 (void) g_strlcpy(file_sha1, "<unknown>", HASH_STR_SIZE);
1064 if (cap_file_hashes) {
1065 fh = ws_fopen(filename, "rb");
1066 if (fh && hd) {
1067 while((hash_bytes = fread(hash_buf, 1, HASH_BUF_SIZE, fh)) > 0) {
1068 gcry_md_write(hd, hash_buf, hash_bytes);
1070 gcry_md_final(hd);
1071 hash_to_str(gcry_md_read(hd, GCRY_MD_SHA256), HASH_SIZE_SHA256, file_sha256);
1072 hash_to_str(gcry_md_read(hd, GCRY_MD_SHA1), HASH_SIZE_SHA1, file_sha1);
1074 if (fh) fclose(fh);
1075 if (hd) gcry_md_reset(hd);
1079 static int
1080 process_cap_file(const char *filename, bool need_separator)
1082 int status = 0;
1083 int err;
1084 char *err_info;
1085 int64_t size;
1086 int64_t data_offset;
1088 uint32_t packet = 0;
1089 int64_t bytes = 0;
1090 uint32_t snaplen_min_inferred = 0xffffffff;
1091 uint32_t snaplen_max_inferred = 0;
1092 wtap_rec rec;
1093 Buffer buf;
1094 capture_info cf_info;
1095 bool have_times = true;
1096 nstime_t earliest_packet_time;
1097 int earliest_packet_time_tsprec;
1098 nstime_t latest_packet_time;
1099 int latest_packet_time_tsprec;
1100 nstime_t cur_time;
1101 nstime_t prev_time;
1102 bool know_order = false;
1103 order_t order = IN_ORDER;
1104 unsigned int i;
1105 wtapng_iface_descriptions_t *idb_info;
1107 pkt_cmt *pc = NULL, *prev = NULL;
1109 cf_info.wth = wtap_open_offline(filename, WTAP_TYPE_AUTO, &err, &err_info, false);
1110 if (!cf_info.wth) {
1111 cfile_open_failure_message(filename, err, err_info);
1112 return 2;
1116 * Calculate the checksums. Do this after wtap_open_offline, so we don't
1117 * bother calculating them for files that are not known capture types
1118 * where we wouldn't print them anyway.
1120 calculate_hashes(filename);
1122 if (need_separator && long_report) {
1123 printf("\n");
1126 nstime_set_zero(&earliest_packet_time);
1127 earliest_packet_time_tsprec = WTAP_TSPREC_UNKNOWN;
1128 nstime_set_zero(&latest_packet_time);
1129 latest_packet_time_tsprec = WTAP_TSPREC_UNKNOWN;
1130 nstime_set_zero(&cur_time);
1131 nstime_set_zero(&prev_time);
1133 cf_info.encap_counts = g_new0(int,WTAP_NUM_ENCAP_TYPES);
1135 idb_info = wtap_file_get_idb_info(cf_info.wth);
1137 ws_assert(idb_info->interface_data != NULL);
1139 cf_info.pkt_cmts = NULL;
1140 cf_info.num_interfaces = idb_info->interface_data->len;
1141 cf_info.interface_packet_counts = g_array_sized_new(false, true, sizeof(uint32_t), cf_info.num_interfaces);
1142 g_array_set_size(cf_info.interface_packet_counts, cf_info.num_interfaces);
1143 cf_info.pkt_interface_id_unknown = 0;
1145 g_free(idb_info);
1146 idb_info = NULL;
1148 /* Zero out the counters for the callbacks. */
1149 num_ipv4_addresses = 0;
1150 num_ipv6_addresses = 0;
1151 num_decryption_secrets = 0;
1153 /* Register callbacks for new name<->address maps from the file and
1154 decryption secrets from the file. */
1155 wtap_set_cb_new_ipv4(cf_info.wth, count_ipv4_address);
1156 wtap_set_cb_new_ipv6(cf_info.wth, count_ipv6_address);
1157 wtap_set_cb_new_secrets(cf_info.wth, count_decryption_secret);
1159 /* Tally up data that we need to parse through the file to find */
1160 wtap_rec_init(&rec);
1161 ws_buffer_init(&buf, 1514);
1162 while (wtap_read(cf_info.wth, &rec, &buf, &err, &err_info, &data_offset)) {
1163 if (rec.presence_flags & WTAP_HAS_TS) {
1164 prev_time = cur_time;
1165 cur_time = rec.ts;
1166 if (packet == 0) {
1167 earliest_packet_time = rec.ts;
1168 earliest_packet_time_tsprec = rec.tsprec;
1169 latest_packet_time = rec.ts;
1170 latest_packet_time_tsprec = rec.tsprec;
1171 prev_time = rec.ts;
1173 if (nstime_cmp(&cur_time, &prev_time) < 0) {
1174 order = NOT_IN_ORDER;
1176 if (nstime_cmp(&cur_time, &earliest_packet_time) < 0) {
1177 earliest_packet_time = cur_time;
1178 earliest_packet_time_tsprec = rec.tsprec;
1180 if (nstime_cmp(&cur_time, &latest_packet_time) > 0) {
1181 latest_packet_time = cur_time;
1182 latest_packet_time_tsprec = rec.tsprec;
1184 } else {
1185 have_times = false; /* at least one packet has no time stamp */
1186 if (order != NOT_IN_ORDER)
1187 order = ORDER_UNKNOWN;
1190 if (rec.rec_type == REC_TYPE_PACKET) {
1191 bytes += rec.rec_header.packet_header.len;
1192 packet++;
1193 /* packet comments */
1194 if (pkt_comments && wtap_block_count_option(rec.block, OPT_COMMENT) > 0) {
1195 char *cmt_buff;
1196 for (i = 0; wtap_block_get_nth_string_option_value(rec.block, OPT_COMMENT, i, &cmt_buff) == WTAP_OPTTYPE_SUCCESS; i++) {
1197 pc = g_new0(pkt_cmt, 1);
1199 pc->recno = packet;
1200 pc->cmt = g_strdup(cmt_buff);
1201 pc->next = NULL;
1203 if (prev == NULL)
1204 cf_info.pkt_cmts = pc;
1205 else
1206 prev->next = pc;
1208 prev = pc;
1212 /* If caplen < len for a rcd, then presumably */
1213 /* 'Limit packet capture length' was done for this rcd. */
1214 /* Keep track as to the min/max actual snapshot lengths */
1215 /* seen for this file. */
1216 if (rec.rec_header.packet_header.caplen < rec.rec_header.packet_header.len) {
1217 if (rec.rec_header.packet_header.caplen < snaplen_min_inferred)
1218 snaplen_min_inferred = rec.rec_header.packet_header.caplen;
1219 if (rec.rec_header.packet_header.caplen > snaplen_max_inferred)
1220 snaplen_max_inferred = rec.rec_header.packet_header.caplen;
1223 if ((rec.rec_header.packet_header.pkt_encap > 0) &&
1224 (rec.rec_header.packet_header.pkt_encap < WTAP_NUM_ENCAP_TYPES)) {
1225 cf_info.encap_counts[rec.rec_header.packet_header.pkt_encap] += 1;
1226 } else {
1227 fprintf(stderr, "capinfos: Unknown packet encapsulation %d in frame %u of file \"%s\"\n",
1228 rec.rec_header.packet_header.pkt_encap, packet, filename);
1231 /* Packet interface_id info */
1232 if (rec.presence_flags & WTAP_HAS_INTERFACE_ID) {
1233 /* cf_info.num_interfaces is size, not index, so it's one more than max index */
1234 if (rec.rec_header.packet_header.interface_id >= cf_info.num_interfaces) {
1236 * OK, re-fetch the number of interfaces, as there might have
1237 * been an interface that was in the middle of packets, and
1238 * grow the array to be big enough for the new number of
1239 * interfaces.
1241 idb_info = wtap_file_get_idb_info(cf_info.wth);
1243 cf_info.num_interfaces = idb_info->interface_data->len;
1244 g_array_set_size(cf_info.interface_packet_counts, cf_info.num_interfaces);
1246 g_free(idb_info);
1247 idb_info = NULL;
1249 if (rec.rec_header.packet_header.interface_id < cf_info.num_interfaces) {
1250 g_array_index(cf_info.interface_packet_counts, uint32_t,
1251 rec.rec_header.packet_header.interface_id) += 1;
1253 else {
1254 cf_info.pkt_interface_id_unknown += 1;
1257 else {
1258 /* it's for interface_id 0 */
1259 if (cf_info.num_interfaces != 0) {
1260 g_array_index(cf_info.interface_packet_counts, uint32_t, 0) += 1;
1262 else {
1263 cf_info.pkt_interface_id_unknown += 1;
1268 wtap_rec_reset(&rec);
1269 } /* while */
1270 wtap_rec_cleanup(&rec);
1271 ws_buffer_free(&buf);
1274 * Get IDB info strings.
1275 * We do this at the end, so we can get information for all IDBs in
1276 * the file, even those that come after packet records, and so that
1277 * we get, for example, a count of the number of statistics entries
1278 * for each interface as of the *end* of the file.
1280 idb_info = wtap_file_get_idb_info(cf_info.wth);
1282 cf_info.idb_info_strings = g_array_sized_new(false, false, sizeof(char*), cf_info.num_interfaces);
1283 cf_info.num_interfaces = idb_info->interface_data->len;
1284 for (i = 0; i < cf_info.num_interfaces; i++) {
1285 const wtap_block_t if_descr = g_array_index(idb_info->interface_data, wtap_block_t, i);
1286 char *s = wtap_get_debug_if_descr(if_descr, 21, "\n");
1287 g_array_append_val(cf_info.idb_info_strings, s);
1290 g_free(idb_info);
1291 idb_info = NULL;
1293 if (err != 0) {
1294 fprintf(stderr,
1295 "capinfos: An error occurred after reading %u packets from \"%s\".\n",
1296 packet, filename);
1297 cfile_read_failure_message(filename, err, err_info);
1298 if (err == WTAP_ERR_SHORT_READ) {
1299 /* Don't give up completely with this one. */
1300 status = 1;
1301 fprintf(stderr,
1302 " (will continue anyway, checksums might be incorrect)\n");
1303 } else {
1304 cleanup_capture_info(&cf_info);
1305 wtap_close(cf_info.wth);
1306 return 2;
1310 /* File size */
1311 size = wtap_file_size(cf_info.wth, &err);
1312 if (size == -1) {
1313 fprintf(stderr,
1314 "capinfos: Can't get size of \"%s\": %s.\n",
1315 filename, g_strerror(err));
1316 cleanup_capture_info(&cf_info);
1317 wtap_close(cf_info.wth);
1318 return 2;
1321 cf_info.filesize = size;
1323 /* File Type */
1324 cf_info.file_type = wtap_file_type_subtype(cf_info.wth);
1325 cf_info.compression_type = wtap_get_compression_type(cf_info.wth);
1327 /* File Encapsulation */
1328 cf_info.file_encap = wtap_file_encap(cf_info.wth);
1330 cf_info.file_tsprec = wtap_file_tsprec(cf_info.wth);
1332 /* Packet size limit (snaplen) */
1333 cf_info.snaplen = wtap_snapshot_length(cf_info.wth);
1334 if (cf_info.snaplen > 0)
1335 cf_info.snap_set = true;
1336 else
1337 cf_info.snap_set = false;
1339 cf_info.snaplen_min_inferred = snaplen_min_inferred;
1340 cf_info.snaplen_max_inferred = snaplen_max_inferred;
1342 /* # of packets */
1343 cf_info.packet_count = packet;
1345 /* File Times */
1346 cf_info.times_known = have_times;
1347 cf_info.earliest_packet_time = earliest_packet_time;
1348 cf_info.earliest_packet_time_tsprec = earliest_packet_time_tsprec;
1349 cf_info.latest_packet_time = latest_packet_time;
1350 cf_info.latest_packet_time_tsprec = latest_packet_time_tsprec;
1351 nstime_delta(&cf_info.duration, &latest_packet_time, &earliest_packet_time);
1352 /* Duration precision is the higher of the earliest and latest packet timestamp precisions. */
1353 if (cf_info.latest_packet_time_tsprec > cf_info.earliest_packet_time_tsprec)
1354 cf_info.duration_tsprec = cf_info.latest_packet_time_tsprec;
1355 else
1356 cf_info.duration_tsprec = cf_info.earliest_packet_time_tsprec;
1357 cf_info.know_order = know_order;
1358 cf_info.order = order;
1360 /* Number of packet bytes */
1361 cf_info.packet_bytes = bytes;
1363 cf_info.data_rate = 0.0;
1364 cf_info.packet_rate = 0.0;
1365 cf_info.packet_size = 0.0;
1367 if (packet > 0) {
1368 double delta_time = nstime_to_sec(&latest_packet_time) - nstime_to_sec(&earliest_packet_time);
1369 if (delta_time > 0.0) {
1370 cf_info.data_rate = (double)bytes / delta_time; /* Data rate per second */
1371 cf_info.packet_rate = (double)packet / delta_time; /* packet rate per second */
1373 cf_info.packet_size = (double)bytes / packet; /* Avg packet size */
1376 if (!long_report && table_report_header) {
1377 print_stats_table_header(&cf_info);
1380 if (long_report) {
1381 print_stats(filename, &cf_info);
1382 } else {
1383 print_stats_table(filename, &cf_info);
1386 cleanup_capture_info(&cf_info);
1387 wtap_close(cf_info.wth);
1389 return status;
1392 static void
1393 print_usage(FILE *output)
1395 fprintf(output, "\n");
1396 fprintf(output, "Usage: capinfos [options] <infile> ...\n");
1397 fprintf(output, "\n");
1398 fprintf(output, "General infos:\n");
1399 fprintf(output, " -t display the capture file type\n");
1400 fprintf(output, " -E display the capture file encapsulation\n");
1401 fprintf(output, " -I display the capture file interface information\n");
1402 fprintf(output, " -F display additional capture file information\n");
1403 fprintf(output, " -H display the SHA256 and SHA1 hashes of the file\n");
1404 fprintf(output, " -k display the capture comment\n");
1405 fprintf(output, " -p display individual packet comments\n");
1406 fprintf(output, "\n");
1407 fprintf(output, "Size infos:\n");
1408 fprintf(output, " -c display the number of packets\n");
1409 fprintf(output, " -s display the size of the file (in bytes)\n");
1410 fprintf(output, " -d display the total length of all packets (in bytes)\n");
1411 fprintf(output, " -l display the packet size limit (snapshot length)\n");
1412 fprintf(output, "\n");
1413 fprintf(output, "Time infos:\n");
1414 fprintf(output, " -u display the capture duration (in seconds)\n");
1415 fprintf(output, " -a display the timestamp of the earliest packet\n");
1416 fprintf(output, " -e display the timestamp of the latest packet\n");
1417 fprintf(output, " -o display the capture file chronological status (True/False)\n");
1418 fprintf(output, " -S display earliest and latest packet timestamps as seconds\n");
1419 fprintf(output, "\n");
1420 fprintf(output, "Statistic infos:\n");
1421 fprintf(output, " -y display average data rate (in bytes/sec)\n");
1422 fprintf(output, " -i display average data rate (in bits/sec)\n");
1423 fprintf(output, " -z display average packet size (in bytes)\n");
1424 fprintf(output, " -x display average packet rate (in packets/sec)\n");
1425 fprintf(output, "\n");
1426 fprintf(output, "Metadata infos:\n");
1427 fprintf(output, " -n display number of resolved IPv4 and IPv6 addresses\n");
1428 fprintf(output, " -D display number of decryption secrets\n");
1429 fprintf(output, "\n");
1430 fprintf(output, "Output format:\n");
1431 fprintf(output, " -L generate long report (default)\n");
1432 fprintf(output, " -T generate table report\n");
1433 fprintf(output, " -M display machine-readable values in long reports\n");
1434 fprintf(output, "\n");
1435 fprintf(output, "Table report options:\n");
1436 fprintf(output, " -R generate header record (default)\n");
1437 fprintf(output, " -r do not generate header record\n");
1438 fprintf(output, "\n");
1439 fprintf(output, " -B separate infos with TAB character (default)\n");
1440 fprintf(output, " -m separate infos with comma (,) character\n");
1441 fprintf(output, " -b separate infos with SPACE character\n");
1442 fprintf(output, "\n");
1443 fprintf(output, " -N do not quote infos (default)\n");
1444 fprintf(output, " -q quote infos with single quotes (')\n");
1445 fprintf(output, " -Q quote infos with double quotes (\")\n");
1446 fprintf(output, "\n");
1447 fprintf(output, "Miscellaneous:\n");
1448 fprintf(output, " -h, --help display this help and exit\n");
1449 fprintf(output, " -v, --version display version info and exit\n");
1450 fprintf(output, " -C cancel processing if file open fails (default is to continue)\n");
1451 fprintf(output, " -A generate all infos (default)\n");
1452 fprintf(output, " -K disable displaying the capture comment\n");
1453 fprintf(output, " -P disable displaying individual packet comments\n");
1454 fprintf(output, "\n");
1455 fprintf(output, "Options are processed from left to right order with later options superseding\n");
1456 fprintf(output, "or adding to earlier options.\n");
1457 fprintf(output, "\n");
1458 fprintf(output, "If no options are given the default is to display all infos in long report\n");
1459 fprintf(output, "output format.\n");
1463 * Report an error in command-line arguments.
1465 static void
1466 capinfos_cmdarg_err(const char *msg_format, va_list ap)
1468 fprintf(stderr, "capinfos: ");
1469 vfprintf(stderr, msg_format, ap);
1470 fprintf(stderr, "\n");
1474 * Report additional information for an error in command-line arguments.
1476 static void
1477 capinfos_cmdarg_err_cont(const char *msg_format, va_list ap)
1479 vfprintf(stderr, msg_format, ap);
1480 fprintf(stderr, "\n");
1484 main(int argc, char *argv[])
1486 char *configuration_init_error;
1487 bool need_separator = false;
1488 int opt;
1489 int overall_error_status = EXIT_SUCCESS;
1490 static const struct ws_option long_options[] = {
1491 {"help", ws_no_argument, NULL, 'h'},
1492 {"version", ws_no_argument, NULL, 'v'},
1493 {0, 0, 0, 0 }
1496 int status = 0;
1499 * Set the C-language locale to the native environment and set the
1500 * code page to UTF-8 on Windows.
1502 #ifdef _WIN32
1503 setlocale(LC_ALL, ".UTF-8");
1504 #else
1505 setlocale(LC_ALL, "");
1506 #endif
1508 cmdarg_err_init(capinfos_cmdarg_err, capinfos_cmdarg_err_cont);
1510 /* Initialize log handler early so we can have proper logging during startup. */
1511 ws_log_init("capinfos", vcmdarg_err);
1513 /* Early logging command-line initialization. */
1514 ws_log_parse_args(&argc, argv, vcmdarg_err, WS_EXIT_INVALID_OPTION);
1516 ws_noisy("Finished log init and parsing command line log arguments");
1518 /* Get the decimal point. */
1519 decimal_point = g_strdup(localeconv()->decimal_point);
1521 /* Initialize the version information. */
1522 ws_init_version_info("Capinfos", NULL, NULL);
1524 #ifdef _WIN32
1525 create_app_running_mutex();
1526 #endif /* _WIN32 */
1529 * Get credential information for later use.
1531 init_process_policies();
1534 * Attempt to get the pathname of the directory containing the
1535 * executable file.
1537 configuration_init_error = configuration_init(argv[0], NULL);
1538 if (configuration_init_error != NULL) {
1539 fprintf(stderr,
1540 "capinfos: Can't get pathname of directory containing the capinfos program: %s.\n",
1541 configuration_init_error);
1542 g_free(configuration_init_error);
1545 init_report_failure_message("capinfos");
1547 wtap_init(true);
1549 /* Process the options */
1550 while ((opt = ws_getopt_long(argc, argv, "abcdehiklmnopqrstuvxyzABCDEFHIKLMNPQRST", long_options, NULL)) !=-1) {
1552 switch (opt) {
1554 case 't':
1555 if (report_all_infos) disable_all_infos();
1556 cap_file_type = true;
1557 break;
1559 case 'E':
1560 if (report_all_infos) disable_all_infos();
1561 cap_file_encap = true;
1562 break;
1564 case 'l':
1565 if (report_all_infos) disable_all_infos();
1566 cap_snaplen = true;
1567 break;
1569 case 'c':
1570 if (report_all_infos) disable_all_infos();
1571 cap_packet_count = true;
1572 break;
1574 case 's':
1575 if (report_all_infos) disable_all_infos();
1576 cap_file_size = true;
1577 break;
1579 case 'd':
1580 if (report_all_infos) disable_all_infos();
1581 cap_data_size = true;
1582 break;
1584 case 'u':
1585 if (report_all_infos) disable_all_infos();
1586 cap_duration = true;
1587 break;
1589 case 'a':
1590 if (report_all_infos) disable_all_infos();
1591 cap_earliest_packet_time = true;
1592 break;
1594 case 'e':
1595 if (report_all_infos) disable_all_infos();
1596 cap_latest_packet_time = true;
1597 break;
1599 case 'S':
1600 time_as_secs = true;
1601 break;
1603 case 'y':
1604 if (report_all_infos) disable_all_infos();
1605 cap_data_rate_byte = true;
1606 break;
1608 case 'i':
1609 if (report_all_infos) disable_all_infos();
1610 cap_data_rate_bit = true;
1611 break;
1613 case 'z':
1614 if (report_all_infos) disable_all_infos();
1615 cap_packet_size = true;
1616 break;
1618 case 'x':
1619 if (report_all_infos) disable_all_infos();
1620 cap_packet_rate = true;
1621 break;
1623 case 'H':
1624 if (report_all_infos) disable_all_infos();
1625 cap_file_hashes = true;
1626 break;
1628 case 'o':
1629 if (report_all_infos) disable_all_infos();
1630 cap_order = true;
1631 break;
1633 case 'k':
1634 if (report_all_infos) disable_all_infos();
1635 cap_comment = true;
1636 break;
1638 case 'p':
1639 if (report_all_infos) disable_all_infos();
1640 pkt_comments = true;
1641 break;
1643 case 'K':
1644 cap_comment = false;
1645 break;
1647 case 'P':
1648 pkt_comments = false;
1649 break;
1651 case 'F':
1652 if (report_all_infos) disable_all_infos();
1653 cap_file_more_info = true;
1654 break;
1656 case 'I':
1657 if (report_all_infos) disable_all_infos();
1658 cap_file_idb = true;
1659 break;
1661 case 'n':
1662 if (report_all_infos) disable_all_infos();
1663 cap_file_nrb = true;
1664 break;
1666 case 'D':
1667 if (report_all_infos) disable_all_infos();
1668 cap_file_dsb = true;
1669 break;
1671 case 'C':
1672 stop_after_failure = true;
1673 break;
1675 case 'A':
1676 enable_all_infos();
1677 break;
1679 case 'L':
1680 long_report = true;
1681 break;
1683 case 'T':
1684 long_report = false;
1685 break;
1687 case 'M':
1688 machine_readable = true;
1689 break;
1691 case 'R':
1692 table_report_header = true;
1693 break;
1695 case 'r':
1696 table_report_header = false;
1697 break;
1699 case 'N':
1700 quote_char = '\0';
1701 break;
1703 case 'q':
1704 quote_char = '\'';
1705 break;
1707 case 'Q':
1708 quote_char = '"';
1709 break;
1711 case 'B':
1712 field_separator = '\t';
1713 break;
1715 case 'm':
1716 field_separator = ',';
1717 break;
1719 case 'b':
1720 field_separator = ' ';
1721 break;
1723 case 'h':
1724 show_help_header("Print various information (infos) about capture files.");
1725 print_usage(stdout);
1726 goto exit;
1727 break;
1729 case 'v':
1730 show_version();
1731 goto exit;
1732 break;
1734 case '?': /* Bad flag - print usage message */
1735 print_usage(stderr);
1736 overall_error_status = WS_EXIT_INVALID_OPTION;
1737 goto exit;
1738 break;
1742 if ((argc - ws_optind) < 1) {
1743 print_usage(stderr);
1744 overall_error_status = WS_EXIT_INVALID_OPTION;
1745 goto exit;
1748 if (cap_file_hashes) {
1749 gcry_check_version(NULL);
1750 gcry_md_open(&hd, GCRY_MD_SHA256, 0);
1751 if (hd)
1752 gcry_md_enable(hd, GCRY_MD_SHA1);
1754 hash_buf = (char *)g_malloc(HASH_BUF_SIZE);
1757 overall_error_status = 0;
1759 for (opt = ws_optind; opt < argc; opt++) {
1761 status = process_cap_file(argv[opt], need_separator);
1762 if (status) {
1763 /* Something failed. It's been reported; remember that processing
1764 one file failed and, if -C was specified, stop. */
1765 overall_error_status = status;
1766 if (stop_after_failure)
1767 goto exit;
1769 if (status != 2) {
1770 /* Either it succeeded or it got a "short read" but printed
1771 information anyway. Note that we need a blank line before
1772 the next file's information, to separate it from the
1773 previous file. */
1774 need_separator = true;
1778 exit:
1779 g_free(hash_buf);
1780 gcry_md_close(hd);
1781 wtap_cleanup();
1782 free_progdirs();
1783 return overall_error_status;