attr_dissector_fn_t
[wireshark-sm.git] / reordercap.c
blob70e7b5337364e3d64df6ec5ba42756b8292234fe
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
9 */
11 #include <config.h>
12 #define WS_LOG_DOMAIN LOG_DOMAIN_MAIN
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <glib.h>
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>
28 #include <cli_main.h>
29 #include <wsutil/version_info.h>
30 #include <wiretap/wtap_opttypes.h>
32 #ifdef HAVE_PLUGINS
33 #include <wsutil/plugins.h>
34 #endif
36 #include <wsutil/wslog.h>
38 #include "ui/failure_message.h"
40 /* Additional exit codes */
41 #define OUTPUT_FILE_ERROR 1
43 /* Show command-line usage */
44 static void
45 print_usage(FILE *output)
47 fprintf(output, "\n");
48 fprintf(output, "Usage: reordercap [options] <infile> <outfile>\n");
49 fprintf(output, "\n");
50 fprintf(output, "Options:\n");
51 fprintf(output, " -n don't write to output file if the input file is ordered.\n");
52 fprintf(output, " -h, --help display this help and exit.\n");
53 fprintf(output, " -v, --version print version information and exit.\n");
56 /* Remember where this frame was in the file */
57 typedef struct FrameRecord_t {
58 int64_t offset;
59 unsigned num;
61 nstime_t frame_time;
62 } FrameRecord_t;
65 /**************************************************/
66 /* Debugging only */
68 /* Enable this symbol to see debug output */
69 /* #define REORDER_DEBUG */
71 #ifdef REORDER_DEBUG
72 #define DEBUG_PRINT printf
73 #else
74 #define DEBUG_PRINT(...)
75 #endif
76 /**************************************************/
79 static void
80 frame_write(FrameRecord_t *frame, wtap *wth, wtap_dumper *pdh,
81 wtap_rec *rec, Buffer *buf, const char *infile,
82 const char *outfile)
84 int err;
85 char *err_info;
87 DEBUG_PRINT("\nDumping frame (offset=%" PRIu64 ")\n",
88 frame->offset);
91 /* Re-read the frame from the stored location */
92 if (!wtap_seek_read(wth, frame->offset, rec, buf, &err, &err_info)) {
93 if (err != 0) {
94 /* Print a message noting that the read failed somewhere along the line. */
95 fprintf(stderr,
96 "reordercap: An error occurred while re-reading \"%s\".\n",
97 infile);
98 cfile_read_failure_message(infile, err, err_info);
99 exit(1);
103 /* Copy, and set length and timestamp from item. */
104 /* TODO: remove when wtap_seek_read() fills in rec,
105 including time stamps, for all file types */
106 rec->ts = frame->frame_time;
108 /* Dump frame to outfile */
109 if (!wtap_dump(pdh, rec, ws_buffer_start_ptr(buf), &err, &err_info)) {
110 cfile_write_failure_message(infile, outfile, err, err_info, frame->num,
111 wtap_file_type_subtype(wth));
112 exit(1);
114 wtap_rec_reset(rec);
117 /* Comparing timestamps between 2 frames.
118 negative if (t1 < t2)
119 zero if (t1 == t2)
120 positive if (t1 > t2)
122 static int
123 frames_compare(const void *a, const void *b)
125 const FrameRecord_t *frame1 = *(const FrameRecord_t *const *) a;
126 const FrameRecord_t *frame2 = *(const FrameRecord_t *const *) b;
128 const nstime_t *time1 = &frame1->frame_time;
129 const nstime_t *time2 = &frame2->frame_time;
131 return nstime_cmp(time1, time2);
135 * General errors and warnings are reported with an console message
136 * in reordercap.
138 static void
139 reordercap_cmdarg_err(const char *msg_format, va_list ap)
141 fprintf(stderr, "reordercap: ");
142 vfprintf(stderr, msg_format, ap);
143 fprintf(stderr, "\n");
147 * Report additional information for an error in command-line arguments.
149 static void
150 reordercap_cmdarg_err_cont(const char *msg_format, va_list ap)
152 vfprintf(stderr, msg_format, ap);
153 fprintf(stderr, "\n");
156 /********************************************************************/
157 /* Main function. */
158 /********************************************************************/
160 main(int argc, char *argv[])
162 char *configuration_init_error;
163 wtap *wth = NULL;
164 wtap_dumper *pdh = NULL;
165 wtap_rec rec;
166 Buffer buf;
167 int err;
168 char *err_info;
169 int64_t data_offset;
170 unsigned wrong_order_count = 0;
171 bool write_output_regardless = true;
172 unsigned i;
173 wtap_dump_params params;
174 int ret = EXIT_SUCCESS;
176 GPtrArray *frames;
177 FrameRecord_t *prevFrame = NULL;
179 int opt;
180 static const struct ws_option long_options[] = {
181 {"help", ws_no_argument, NULL, 'h'},
182 {"version", ws_no_argument, NULL, 'v'},
183 {0, 0, 0, 0 }
185 int file_count;
186 char *infile;
187 const char *outfile;
189 cmdarg_err_init(reordercap_cmdarg_err, reordercap_cmdarg_err_cont);
191 /* Initialize log handler early so we can have proper logging during startup. */
192 ws_log_init("reordercap", vcmdarg_err);
194 /* Early logging command-line initialization. */
195 ws_log_parse_args(&argc, argv, vcmdarg_err, WS_EXIT_INVALID_OPTION);
197 ws_noisy("Finished log init and parsing command line log arguments");
199 /* Initialize the version information. */
200 ws_init_version_info("Reordercap", NULL, NULL);
203 * Get credential information for later use.
205 init_process_policies();
208 * Attempt to get the pathname of the directory containing the
209 * executable file.
211 configuration_init_error = configuration_init(argv[0], NULL);
212 if (configuration_init_error != NULL) {
213 fprintf(stderr,
214 "reordercap: Can't get pathname of directory containing the reordercap program: %s.\n",
215 configuration_init_error);
216 g_free(configuration_init_error);
219 init_report_failure_message("reordercap");
221 wtap_init(true);
223 /* Process the options first */
224 while ((opt = ws_getopt_long(argc, argv, "hnv", long_options, NULL)) != -1) {
225 switch (opt) {
226 case 'n':
227 write_output_regardless = false;
228 break;
229 case 'h':
230 show_help_header("Reorder timestamps of input file frames into output file.");
231 print_usage(stdout);
232 goto clean_exit;
233 case 'v':
234 show_version();
235 goto clean_exit;
236 case '?':
237 print_usage(stderr);
238 ret = WS_EXIT_INVALID_OPTION;
239 goto clean_exit;
243 /* Remaining args are file names */
244 file_count = argc - ws_optind;
245 if (file_count == 2) {
246 infile = argv[ws_optind];
247 outfile = argv[ws_optind+1];
249 else {
250 print_usage(stderr);
251 ret = WS_EXIT_INVALID_OPTION;
252 goto clean_exit;
255 /* Open infile */
256 /* TODO: if reordercap is ever changed to give the user a choice of which
257 open_routine reader to use, then the following needs to change. */
258 wth = wtap_open_offline(infile, WTAP_TYPE_AUTO, &err, &err_info, true);
259 if (wth == NULL) {
260 cfile_open_failure_message(infile, err, err_info);
261 ret = WS_EXIT_OPEN_ERROR;
262 goto clean_exit;
264 DEBUG_PRINT("file_type_subtype is %d\n", wtap_file_type_subtype(wth));
266 /* Allocate the array of frame pointers. */
267 frames = g_ptr_array_new();
269 /* Read each frame from infile */
270 wtap_rec_init(&rec);
271 ws_buffer_init(&buf, 1514);
272 while (wtap_read(wth, &rec, &buf, &err, &err_info, &data_offset)) {
273 FrameRecord_t *newFrameRecord;
275 newFrameRecord = g_slice_new(FrameRecord_t);
276 newFrameRecord->num = frames->len + 1;
277 newFrameRecord->offset = data_offset;
278 if (rec.presence_flags & WTAP_HAS_TS) {
279 newFrameRecord->frame_time = rec.ts;
280 } else {
281 nstime_set_unset(&newFrameRecord->frame_time);
284 if (prevFrame && frames_compare(&newFrameRecord, &prevFrame) < 0) {
285 wrong_order_count++;
288 g_ptr_array_add(frames, newFrameRecord);
289 prevFrame = newFrameRecord;
290 wtap_rec_reset(&rec);
292 wtap_rec_cleanup(&rec);
293 ws_buffer_free(&buf);
294 if (err != 0) {
295 /* Print a message noting that the read failed somewhere along the line. */
296 cfile_read_failure_message(infile, err, err_info);
299 printf("%u frames, %u out of order\n", frames->len, wrong_order_count);
301 wtap_dump_params_init(&params, wth);
303 /* Sort the frames */
304 /* XXX - Does this handle multiple SHBs correctly? */
305 if (wrong_order_count > 0) {
306 g_ptr_array_sort(frames, frames_compare);
310 /* Avoid writing if already sorted and configured to */
311 if (write_output_regardless || (wrong_order_count > 0)) {
312 /* Open outfile (same filetype/encap as input file) */
313 if (strcmp(outfile, "-") == 0) {
314 pdh = wtap_dump_open_stdout(wtap_file_type_subtype(wth),
315 WTAP_UNCOMPRESSED, &params, &err, &err_info);
316 } else {
317 pdh = wtap_dump_open(outfile, wtap_file_type_subtype(wth),
318 WTAP_UNCOMPRESSED, &params, &err, &err_info);
320 g_free(params.idb_inf);
321 params.idb_inf = NULL;
323 if (pdh == NULL) {
324 cfile_dump_open_failure_message(outfile, err, err_info,
325 wtap_file_type_subtype(wth));
326 wtap_dump_params_cleanup(&params);
327 ret = OUTPUT_FILE_ERROR;
328 goto clean_exit;
332 /* Write out each sorted frame in turn */
333 wtap_rec_init(&rec);
334 ws_buffer_init(&buf, 1514);
335 for (i = 0; i < frames->len; i++) {
336 FrameRecord_t *frame = (FrameRecord_t *)frames->pdata[i];
338 frame_write(frame, wth, pdh, &rec, &buf, infile, outfile);
340 g_slice_free(FrameRecord_t, frame);
343 wtap_rec_cleanup(&rec);
344 ws_buffer_free(&buf);
348 /* Close outfile */
349 if (!wtap_dump_close(pdh, NULL, &err, &err_info)) {
350 cfile_close_failure_message(outfile, err, err_info);
351 wtap_dump_params_cleanup(&params);
352 ret = OUTPUT_FILE_ERROR;
353 goto clean_exit;
355 } else {
356 printf("Not writing output file because input file is already in order.\n");
358 /* Free frame memory */
359 for (i = 0; i < frames->len; i++) {
360 FrameRecord_t *frame = (FrameRecord_t *)frames->pdata[i];
362 g_slice_free(FrameRecord_t, frame);
367 /* Free the whole array */
368 g_ptr_array_free(frames, TRUE);
370 wtap_dump_params_cleanup(&params);
372 /* Finally, close infile and release resources. */
373 wtap_close(wth);
375 clean_exit:
376 wtap_cleanup();
377 free_progdirs();
378 return ret;
382 * Editor modelines - https://www.wireshark.org/tools/modelines.html
384 * Local variables:
385 * c-basic-offset: 4
386 * tab-width: 8
387 * indent-tabs-mode: nil
388 * End:
390 * vi: set shiftwidth=4 tabstop=8 expandtab:
391 * :indentSize=4:tabSize=8:noTabs=true: