Change some of the merge.c APIs to return more information on failure,
[obnox/wireshark/wip.git] / mergecap.c
1 /* Combine two dump files, either by appending or by merging by timestamp
2  *
3  * $Id$
4  *
5  * Written by Scott Renfro <scott@renfro.org> based on
6  * editcap by Richard Sharpe and Guy Harris
7  *
8  */
9
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <errno.h>
17 #include <glib.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #ifdef HAVE_SYS_TIME_H
24 #include <sys/time.h>
25 #endif
26
27 #include <string.h>
28 #include "wtap.h"
29
30 #ifdef NEED_GETOPT_H
31 #include "getopt.h"
32 #endif
33
34 #include "svnversion.h"
35 #include "merge.h"
36
37 #ifdef HAVE_IO_H
38 # include <io.h>
39 #endif
40
41 #ifdef HAVE_FCNTL_H
42 #include <fcntl.h>
43 #endif
44
45 /* Win32 needs the O_BINARY flag for open() */
46 #ifndef O_BINARY
47 #define O_BINARY        0
48 #endif
49
50 static int
51 get_natural_int(const char *string, const char *name)
52 {
53   long number;
54   char *p;
55
56   number = strtol(string, &p, 10);
57   if (p == string || *p != '\0') {
58     fprintf(stderr, "mergecap: The specified %s \"%s\" is not a decimal number\n",
59             name, string);
60     exit(1);
61   }
62   if (number < 0) {
63     fprintf(stderr, "mergecap: The specified %s is a negative number\n",
64             name);
65     exit(1);
66   }
67   if (number > INT_MAX) {
68     fprintf(stderr, "mergecap: The specified %s is too large (greater than %d)\n",
69             name, INT_MAX);
70     exit(1);
71   }
72   return number;
73 }
74
75 static int
76 get_positive_int(const char *string, const char *name)
77 {
78   long number;
79
80   number = get_natural_int(string, name);
81
82   if (number == 0) {
83     fprintf(stderr, "mergecap: The specified %s is zero\n",
84             name);
85     exit(1);
86   }
87
88   return number;
89 }
90
91 /*
92  * Show the usage
93  */
94 static void
95 usage(void)
96 {
97   int i;
98   const char *string;
99
100   printf("Usage: mergecap [-hva] [-s <snaplen>] [-T <encap type>]\n");
101   printf("          [-F <capture type>] -w <outfile> <infile> [...]\n\n");
102   printf("  where\t-h produces this help listing.\n");
103   printf("       \t-v verbose operation, default is silent\n");
104   printf("       \t-a files should be concatenated, not merged\n");
105   printf("       \t     Default merges based on frame timestamps\n");
106   printf("       \t-s <snaplen>: truncate packets to <snaplen> bytes of data\n");
107   printf("       \t-w <outfile>: sets output filename to <outfile>\n");
108   printf("       \t-T <encap type> encapsulation type to use:\n");
109   for (i = 0; i < WTAP_NUM_ENCAP_TYPES; i++) {
110       string = wtap_encap_short_string(i);
111       if (string != NULL)
112         printf("       \t     %s - %s\n",
113           string, wtap_encap_string(i));
114   }
115   printf("       \t     default is the same as the first input file\n");
116   printf("       \t-F <capture type> capture file type to write:\n");
117   for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
118     if (wtap_dump_can_open(i))
119       printf("       \t     %s - %s\n",
120         wtap_file_type_short_string(i), wtap_file_type_string(i));
121   }
122   printf("       \t     default is libpcap\n");
123 }
124
125
126
127 int
128 main(int argc, char *argv[])
129 {
130   extern char *optarg;
131   extern int   optind;
132   int          opt;
133   gboolean     do_append     = FALSE;
134   int          in_file_count = 0;
135   int          snaplen = 0;
136   int          file_type = WTAP_FILE_PCAP;      /* default to libpcap format */
137   int          frame_type = -2;
138   int          out_fd;
139   merge_in_file_t   *in_files      = NULL;
140   merge_out_file_t   out_file;
141   int          err;
142   gchar       *err_info;
143   int          err_fileno;
144   char        *out_filename = NULL;
145
146   merge_verbose = VERBOSE_ERRORS;
147
148   /* Process the options first */
149   while ((opt = getopt(argc, argv, "hvas:T:F:w:")) != -1) {
150
151     switch (opt) {
152     case 'w':
153       out_filename = optarg;
154       break;
155
156     case 'a':
157       do_append = !do_append;
158       break;
159
160     case 'T':
161       frame_type = wtap_short_string_to_encap(optarg);
162       if (frame_type < 0) {
163         fprintf(stderr, "mergecap: \"%s\" is not a valid encapsulation type\n",
164             optarg);
165         exit(1);
166       }
167       break;
168
169     case 'F':
170       file_type = wtap_short_string_to_file_type(optarg);
171       if (file_type < 0) {
172         fprintf(stderr, "mergecap: \"%s\" is not a valid capture file type\n",
173             optarg);
174         exit(1);
175       }
176       break;
177
178     case 'v':
179       merge_verbose = VERBOSE_ALL;
180       break;
181
182     case 's':
183       snaplen = get_positive_int(optarg, "snapshot length");
184       break;
185
186     case 'h':
187       printf("mergecap version %s"
188 #ifdef SVNVERSION
189           " (" SVNVERSION ")"
190 #endif
191           "\n", VERSION);
192       usage();
193       exit(0);
194       break;
195
196     case '?':              /* Bad options if GNU getopt */
197       usage();
198       exit(1);
199       break;
200
201     }
202
203   }
204
205   /* check for proper args; at a minimum, must have an output
206    * filename and one input file
207    */
208   in_file_count = argc - optind;
209   if (!out_filename) {
210     fprintf(stderr, "mergecap: an output filename must be set with -w\n");
211     fprintf(stderr, "          run with -h for help\n");
212     exit(1);
213   }
214   if (in_file_count < 1) {
215     fprintf(stderr, "mergecap: No input files were specified\n");
216     exit(1);
217   }
218
219   /* open the input files */
220   in_file_count = merge_open_in_files(in_file_count, &argv[optind], &in_files,
221                                       &err, &err_info, &err_fileno);
222   if (in_file_count < 1) {
223     fprintf(stderr, "mergecap: No valid input files\n");
224     exit(1);
225   }
226
227   if (snaplen == 0) {
228     /*
229      * Snapshot length not specified - default to the maximum of the
230      * snapshot lengths of the input files.
231      */
232     snaplen = merge_max_snapshot_length(in_file_count, in_files);
233   }
234
235   /* set the outfile frame type */
236   if (frame_type == -2) {
237     /*
238      * Default to the appropriate frame type for the input files.
239      */
240     frame_type = merge_select_frame_type(in_file_count, in_files);
241   }
242
243   /* open the outfile */
244   if (strncmp(out_filename, "-", 2) == 0) {  
245     /* use stdout as the outfile */
246     out_fd = 1 /*stdout*/;
247   } else {
248     /* open the outfile */
249     out_fd = open(out_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
250     if (out_fd == -1) {
251       fprintf(stderr, "mergecap: Couldn't open output file %s: %s\n",
252               out_filename, strerror(errno));
253       exit(1);
254     }
255   }  
256     
257   /* prepare the outfile */
258   if (!merge_open_outfile(&out_file, out_fd, file_type, frame_type, snaplen,
259                           &err)) {
260     merge_close_in_files(in_file_count, in_files);
261     exit(1);
262   }
263
264   /* do the merge (or append) */
265   if (do_append)
266     merge_append_files(in_file_count, in_files, &out_file, &err);
267   else
268     merge_files(in_file_count, in_files, &out_file, &err);
269
270   merge_close_in_files(in_file_count, in_files);
271   merge_close_outfile(&out_file, &err);
272
273   free(in_files);
274
275   return 0;
276 }