1 /* Reorder the frames from an input dump file, and write to output dump file.
2 * Martin Mathieson and Jakub Jawadzki
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
12 #define WS_LOG_DOMAIN LOG_DOMAIN_MAIN
19 #include <ws_exit_codes.h>
20 #include <wsutil/ws_getopt.h>
22 #include <wiretap/wtap.h>
24 #include <wsutil/cmdarg_err.h>
25 #include <wsutil/filesystem.h>
26 #include <wsutil/file_util.h>
27 #include <wsutil/privileges.h>
29 #include <wsutil/version_info.h>
30 #include <wiretap/wtap_opttypes.h>
33 #include <wsutil/plugins.h>
36 #include <wsutil/report_message.h>
37 #include <wsutil/wslog.h>
39 #include "ui/failure_message.h"
41 /* Additional exit codes */
42 #define OUTPUT_FILE_ERROR 1
44 /* Show command-line usage */
46 print_usage(FILE *output
)
48 fprintf(output
, "\n");
49 fprintf(output
, "Usage: reordercap [options] <infile> <outfile>\n");
50 fprintf(output
, "\n");
51 fprintf(output
, "Options:\n");
52 fprintf(output
, " -n don't write to output file if the input file is ordered.\n");
53 fprintf(output
, " -h, --help display this help and exit.\n");
54 fprintf(output
, " -v, --version print version information and exit.\n");
57 /* Remember where this frame was in the file */
58 typedef struct FrameRecord_t
{
66 /**************************************************/
69 /* Enable this symbol to see debug output */
70 /* #define REORDER_DEBUG */
73 #define DEBUG_PRINT printf
75 #define DEBUG_PRINT(...)
77 /**************************************************/
81 frame_write(FrameRecord_t
*frame
, wtap
*wth
, wtap_dumper
*pdh
,
82 wtap_rec
*rec
, Buffer
*buf
, const char *infile
,
88 DEBUG_PRINT("\nDumping frame (offset=%" PRIu64
")\n",
92 /* Re-read the frame from the stored location */
93 if (!wtap_seek_read(wth
, frame
->offset
, rec
, buf
, &err
, &err_info
)) {
95 /* Print a message noting that the read failed somewhere along the line. */
97 "reordercap: An error occurred while re-reading \"%s\".\n",
99 cfile_read_failure_message(infile
, err
, err_info
);
104 /* Copy, and set length and timestamp from item. */
105 /* TODO: remove when wtap_seek_read() fills in rec,
106 including time stamps, for all file types */
107 rec
->ts
= frame
->frame_time
;
109 /* Dump frame to outfile */
110 if (!wtap_dump(pdh
, rec
, ws_buffer_start_ptr(buf
), &err
, &err_info
)) {
111 cfile_write_failure_message(infile
, outfile
, err
, err_info
, frame
->num
,
112 wtap_file_type_subtype(wth
));
118 /* Comparing timestamps between 2 frames.
119 negative if (t1 < t2)
121 positive if (t1 > t2)
124 frames_compare(gconstpointer a
, gconstpointer b
)
126 const FrameRecord_t
*frame1
= *(const FrameRecord_t
*const *) a
;
127 const FrameRecord_t
*frame2
= *(const FrameRecord_t
*const *) b
;
129 const nstime_t
*time1
= &frame1
->frame_time
;
130 const nstime_t
*time2
= &frame2
->frame_time
;
132 return nstime_cmp(time1
, time2
);
136 * General errors and warnings are reported with an console message
140 reordercap_cmdarg_err(const char *msg_format
, va_list ap
)
142 fprintf(stderr
, "reordercap: ");
143 vfprintf(stderr
, msg_format
, ap
);
144 fprintf(stderr
, "\n");
148 * Report additional information for an error in command-line arguments.
151 reordercap_cmdarg_err_cont(const char *msg_format
, va_list ap
)
153 vfprintf(stderr
, msg_format
, ap
);
154 fprintf(stderr
, "\n");
157 /********************************************************************/
159 /********************************************************************/
161 main(int argc
, char *argv
[])
163 char *configuration_init_error
;
164 static const struct report_message_routines reordercap_message_routines
= {
167 open_failure_message
,
168 read_failure_message
,
169 write_failure_message
,
170 cfile_open_failure_message
,
171 cfile_dump_open_failure_message
,
172 cfile_read_failure_message
,
173 cfile_write_failure_message
,
174 cfile_close_failure_message
177 wtap_dumper
*pdh
= NULL
;
183 guint wrong_order_count
= 0;
184 gboolean write_output_regardless
= TRUE
;
186 wtap_dump_params params
;
187 int ret
= EXIT_SUCCESS
;
190 FrameRecord_t
*prevFrame
= NULL
;
193 static const struct ws_option long_options
[] = {
194 {"help", ws_no_argument
, NULL
, 'h'},
195 {"version", ws_no_argument
, NULL
, 'v'},
202 cmdarg_err_init(reordercap_cmdarg_err
, reordercap_cmdarg_err_cont
);
204 /* Initialize log handler early so we can have proper logging during startup. */
205 ws_log_init("reordercap", vcmdarg_err
);
207 /* Early logging command-line initialization. */
208 ws_log_parse_args(&argc
, argv
, vcmdarg_err
, WS_EXIT_INVALID_OPTION
);
210 ws_noisy("Finished log init and parsing command line log arguments");
212 /* Initialize the version information. */
213 ws_init_version_info("Reordercap", NULL
, NULL
);
216 * Get credential information for later use.
218 init_process_policies();
221 * Attempt to get the pathname of the directory containing the
224 configuration_init_error
= configuration_init(argv
[0], NULL
);
225 if (configuration_init_error
!= NULL
) {
227 "reordercap: Can't get pathname of directory containing the reordercap program: %s.\n",
228 configuration_init_error
);
229 g_free(configuration_init_error
);
232 init_report_message("reordercap", &reordercap_message_routines
);
236 /* Process the options first */
237 while ((opt
= ws_getopt_long(argc
, argv
, "hnv", long_options
, NULL
)) != -1) {
240 write_output_regardless
= FALSE
;
243 show_help_header("Reorder timestamps of input file frames into output file.");
251 ret
= WS_EXIT_INVALID_OPTION
;
256 /* Remaining args are file names */
257 file_count
= argc
- ws_optind
;
258 if (file_count
== 2) {
259 infile
= argv
[ws_optind
];
260 outfile
= argv
[ws_optind
+1];
264 ret
= WS_EXIT_INVALID_OPTION
;
269 /* TODO: if reordercap is ever changed to give the user a choice of which
270 open_routine reader to use, then the following needs to change. */
271 wth
= wtap_open_offline(infile
, WTAP_TYPE_AUTO
, &err
, &err_info
, TRUE
);
273 cfile_open_failure_message(infile
, err
, err_info
);
274 ret
= WS_EXIT_OPEN_ERROR
;
277 DEBUG_PRINT("file_type_subtype is %d\n", wtap_file_type_subtype(wth
));
279 /* Allocate the array of frame pointers. */
280 frames
= g_ptr_array_new();
282 /* Read each frame from infile */
284 ws_buffer_init(&buf
, 1514);
285 while (wtap_read(wth
, &rec
, &buf
, &err
, &err_info
, &data_offset
)) {
286 FrameRecord_t
*newFrameRecord
;
288 newFrameRecord
= g_slice_new(FrameRecord_t
);
289 newFrameRecord
->num
= frames
->len
+ 1;
290 newFrameRecord
->offset
= data_offset
;
291 if (rec
.presence_flags
& WTAP_HAS_TS
) {
292 newFrameRecord
->frame_time
= rec
.ts
;
294 nstime_set_unset(&newFrameRecord
->frame_time
);
297 if (prevFrame
&& frames_compare(&newFrameRecord
, &prevFrame
) < 0) {
301 g_ptr_array_add(frames
, newFrameRecord
);
302 prevFrame
= newFrameRecord
;
303 wtap_rec_reset(&rec
);
305 wtap_rec_cleanup(&rec
);
306 ws_buffer_free(&buf
);
308 /* Print a message noting that the read failed somewhere along the line. */
309 cfile_read_failure_message(infile
, err
, err_info
);
312 printf("%u frames, %u out of order\n", frames
->len
, wrong_order_count
);
314 wtap_dump_params_init(¶ms
, wth
);
316 /* Sort the frames */
317 /* XXX - Does this handle multiple SHBs correctly? */
318 if (wrong_order_count
> 0) {
319 g_ptr_array_sort(frames
, frames_compare
);
323 /* Avoid writing if already sorted and configured to */
324 if (write_output_regardless
|| (wrong_order_count
> 0)) {
325 /* Open outfile (same filetype/encap as input file) */
326 if (strcmp(outfile
, "-") == 0) {
327 pdh
= wtap_dump_open_stdout(wtap_file_type_subtype(wth
),
328 WTAP_UNCOMPRESSED
, ¶ms
, &err
, &err_info
);
330 pdh
= wtap_dump_open(outfile
, wtap_file_type_subtype(wth
),
331 WTAP_UNCOMPRESSED
, ¶ms
, &err
, &err_info
);
333 g_free(params
.idb_inf
);
334 params
.idb_inf
= NULL
;
337 cfile_dump_open_failure_message(outfile
, err
, err_info
,
338 wtap_file_type_subtype(wth
));
339 wtap_dump_params_cleanup(¶ms
);
340 ret
= OUTPUT_FILE_ERROR
;
345 /* Write out each sorted frame in turn */
347 ws_buffer_init(&buf
, 1514);
348 for (i
= 0; i
< frames
->len
; i
++) {
349 FrameRecord_t
*frame
= (FrameRecord_t
*)frames
->pdata
[i
];
351 frame_write(frame
, wth
, pdh
, &rec
, &buf
, infile
, outfile
);
353 g_slice_free(FrameRecord_t
, frame
);
356 wtap_rec_cleanup(&rec
);
357 ws_buffer_free(&buf
);
362 if (!wtap_dump_close(pdh
, NULL
, &err
, &err_info
)) {
363 cfile_close_failure_message(outfile
, err
, err_info
);
364 wtap_dump_params_cleanup(¶ms
);
365 ret
= OUTPUT_FILE_ERROR
;
369 printf("Not writing output file because input file is already in order.\n");
371 /* Free frame memory */
372 for (i
= 0; i
< frames
->len
; i
++) {
373 FrameRecord_t
*frame
= (FrameRecord_t
*)frames
->pdata
[i
];
375 g_slice_free(FrameRecord_t
, frame
);
380 /* Free the whole array */
381 g_ptr_array_free(frames
, TRUE
);
383 wtap_dump_params_cleanup(¶ms
);
385 /* Finally, close infile and release resources. */
395 * Editor modelines - https://www.wireshark.org/tools/modelines.html
400 * indent-tabs-mode: nil
403 * vi: set shiftwidth=4 tabstop=8 expandtab:
404 * :indentSize=4:tabSize=8:noTabs=true: