Get rid of an unused variable.
[obnox/wireshark/wip.git] / ringbuffer.c
1 /* ringbuffer.c
2  * Routines for packet capture windows
3  *
4  * $Id: ringbuffer.c,v 1.1 2001/12/04 08:45:04 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  * 
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  * 
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #ifdef HAVE_LIBPCAP
30
31 #ifdef HAVE_IO_H
32 #include <io.h>
33 #endif
34
35 #ifdef HAVE_FCNTL_H
36 #include <fcntl.h>
37 #endif
38
39 #ifdef HAVE_SYS_TYPES_H
40 #include <sys/types.h>
41 #endif
42
43 #ifdef HAVE_SYS_STAT_H
44 #include <sys/stat.h>
45 #endif
46
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50
51 #include <stdio.h>
52 #include <string.h>
53 #include <time.h>
54 #include <errno.h>
55
56 #ifdef NEED_SNPRINTF_H
57 #include "snprintf.h"
58 #endif
59
60 #include "wiretap/wtap.h"
61 #include "ringbuffer.h"
62
63 /* Win32 needs the O_BINARY flag for open() */
64 #ifndef O_BINARY
65 #define O_BINARY        0
66 #endif
67
68 /* Ringbuffer file structure */
69 typedef struct _rb_file {
70   gchar*        name;
71   int           fd;
72   time_t        creation_time;
73   gboolean      is_new;
74   guint16       number;
75   wtap_dumper*  pdh;
76   long          start_pos;
77 } rb_file;
78
79 /* Ringbuffer data structure */
80 typedef struct _ringbuf_data {
81   rb_file*      files;
82   guint         num_files;      /* Number of ringbuffer files */
83   guint         curr_file_num;  /* Number of the current file */
84   gchar*        fprefix;        /* Filename prefix */
85   gchar*        fsuffix;        /* Filename suffix */
86 } ringbuf_data; 
87
88 /* Create the ringbuffer data structure */
89 static ringbuf_data rb_data;
90
91 /* 
92  * Initialize the ringbuffer data structure
93  */
94 int 
95 ringbuf_init(const char *capfile_name, guint num_files)
96 {
97   int          save_file_fd;
98   unsigned int i;
99   char        *pfx;
100   gchar       *save_file;
101   char         save_file_num[3+1];
102
103   /* just to be sure ... */
104   if (num_files <= RINGBUFFER_MAX_NUM_FILES) {
105     rb_data.num_files = num_files;
106   } else {
107     rb_data.num_files = RINGBUFFER_MAX_NUM_FILES;
108   }
109
110   /* Check file name */
111   if (capfile_name == NULL) {
112     /* ringbuffer does not work with temporary files! */
113     return -1;
114   }
115
116   /* Open the initial file */
117   save_file_fd = open(capfile_name, O_RDWR|O_BINARY|O_TRUNC|O_CREAT, 0600);
118   if (save_file_fd == -1) {
119     /* open failed */
120     return -1;
121   }
122  
123   /* allocate memory */
124   rb_data.files = (rb_file *)calloc(num_files, sizeof(rb_file));
125   if (rb_data.files == NULL) {
126     /* could not allocate memory */
127     return -1;
128   }
129
130   /* initialize */
131   rb_data.fprefix = NULL;
132   rb_data.fsuffix = NULL;
133   for (i=0; i<rb_data.num_files; i++) {
134     rb_data.files[i].name = NULL;
135     rb_data.files[i].fd = -1;
136   }
137
138   /* get file name prefix/suffix */
139   save_file = g_strdup(capfile_name);
140   pfx = strrchr(save_file,'.');
141   if (pfx != NULL) {
142     pfx[0] = '\0';
143     rb_data.fprefix = g_strdup(save_file);
144     pfx[0] = '.'; /* restore capfile_name */
145     rb_data.fsuffix = g_strdup(pfx);
146   } else {
147     rb_data.fprefix = g_strdup(save_file);
148     rb_data.fsuffix = NULL;
149   }
150   g_free(save_file);
151   save_file = NULL;
152
153 #ifdef _WIN32
154   _tzset();
155 #endif
156   /* save the initial file parameters */
157   rb_data.files[0].name = g_strdup(capfile_name);
158   rb_data.files[0].fd = save_file_fd;
159   rb_data.files[0].creation_time = time(NULL);
160   rb_data.files[0].number = 0;
161   rb_data.files[0].is_new = TRUE;
162
163   /* create the other files */
164   for (i=1; i<rb_data.num_files; i++) {
165     /* create a file name */
166     snprintf(save_file_num,3+1,"%03d",i);
167     save_file = g_strconcat(capfile_name, ".", save_file_num, NULL);
168     /* open the file */
169     save_file_fd = open(save_file, O_RDWR|O_BINARY|O_TRUNC|O_CREAT, 0600);
170     if (save_file_fd != -1) {
171       rb_data.files[i].name = save_file;
172       rb_data.files[i].fd = save_file_fd;
173       rb_data.files[i].creation_time = time(NULL);
174       rb_data.files[i].number = i;
175       rb_data.files[i].is_new = TRUE;
176     } else {
177       /* could not open a file  */
178       ringbuf_error_cleanup();
179       return -1;
180     }
181   }
182   
183   /* done */
184   rb_data.curr_file_num = 0;
185   return rb_data.files[0].fd;
186 }
187
188 /* 
189  * Calls wtap_dump_fdopen() for all ringbuffer files
190  */
191 wtap_dumper* 
192 ringbuf_init_wtap_dump_fdopen(int filetype, int linktype, 
193   int snaplen, int *err)
194 {
195   unsigned int  i;
196   FILE         *fh;
197
198   for (i=0; i<rb_data.num_files; i++) {
199     rb_data.files[i].pdh = wtap_dump_fdopen(rb_data.files[i].fd, filetype,
200       linktype, snaplen, err);
201     if (rb_data.files[i].pdh == NULL) {
202       /* could not open file */
203       return NULL;
204     } else {
205       /*
206        * XXX - this relies on Wiretap writing out data sequentially,
207        * and writing the entire capture file header when the file
208        * is created.  That happens to be true for libpcap files,
209        * which are Ethereal's native capture files, and which are
210        * therefore the capture file types we're writing, but is not
211        * true for all the capture file types Wiretap can write.
212        */
213       fh = wtap_dump_file(rb_data.files[i].pdh);
214       fflush(fh);
215       rb_data.files[i].start_pos = ftell(fh);
216       clearerr(fh);
217     }
218   }
219   /* done */
220   rb_data.files[0].is_new = FALSE;
221   return rb_data.files[0].pdh;
222 }
223
224 /* 
225  * Switches to the next ringbuffer file
226  */
227 gboolean
228 ringbuf_switch_file(capture_file *cf, wtap_dumper **pdh, int *err)
229 {
230   int   next_file_num;
231   FILE *fh;
232
233   /* flush the current file */
234   fh = wtap_dump_file(rb_data.files[rb_data.curr_file_num].pdh);
235   clearerr(fh);
236   fflush(fh);
237   /* get the next file number */
238   next_file_num = (rb_data.curr_file_num + 1) % rb_data.num_files;
239   /* prepare the file if it was already used */
240   if (!rb_data.files[next_file_num].is_new) {
241     /* rewind to the position after the file header */
242     fh = wtap_dump_file(rb_data.files[next_file_num].pdh);
243     fseek(fh, rb_data.files[next_file_num].start_pos, SEEK_SET);
244     wtap_set_bytes_dumped(rb_data.files[next_file_num].pdh,
245       rb_data.files[next_file_num].start_pos);
246     /* set the absolute file number */
247     rb_data.files[next_file_num].number += rb_data.num_files;
248   }
249 #ifdef _WIN32
250   _tzset();
251 #endif
252   rb_data.files[next_file_num].creation_time = time(NULL);
253   /* switch to the new file */
254   cf->save_file = rb_data.files[next_file_num].name;
255   cf->save_file_fd = rb_data.files[next_file_num].fd;
256   (*pdh) = rb_data.files[next_file_num].pdh;
257   /* mark the file as used */
258   rb_data.files[next_file_num].is_new = FALSE;
259   /* finally set the current file number */
260   rb_data.curr_file_num = next_file_num;
261
262   return TRUE;
263 }
264
265 /* 
266  * Calls wtap_dump_close() for all ringbuffer files
267  */
268 gboolean
269 ringbuf_wtap_dump_close(capture_file *cf, int *err)
270 {
271   gboolean     ret_val;
272   unsigned int i;
273   gchar       *new_name;
274   char         filenum[5+1];
275   char         timestr[14+1];
276   FILE        *fh;
277
278   /* assume success */
279   ret_val = TRUE;
280   /* close all files */
281   for (i=0; i<rb_data.num_files; i++) {
282     fh = wtap_dump_file(rb_data.files[i].pdh);
283     clearerr(fh);
284     /* Flush the file */
285     fflush(fh);
286     /* Truncate the file to the current size. This must be done in order
287        to get rid of the 'garbage' packets at the end of the file from
288        previous usage */
289     if (!rb_data.files[i].is_new) {
290       if (ftruncate(rb_data.files[i].fd,ftell(fh)) != 0) {
291         /* could not truncate the file */
292         if (err != NULL) {
293           *err = errno;
294         }
295         ret_val = FALSE;
296         /* remove the file since it contains garbage at the end */
297         close(rb_data.files[i].fd);
298         unlink(rb_data.files[i].name);
299         continue;
300       }
301     }
302     /* close the file */
303     if (!wtap_dump_close(rb_data.files[i].pdh, err)) {
304       /* error only if it is a used file */
305       if (!rb_data.files[i].is_new) {
306         ret_val = FALSE;
307       }
308     }
309     if (!rb_data.files[i].is_new) {
310       /* rename the file */
311       snprintf(filenum,5+1,"%05d",rb_data.files[i].number);
312       strftime(timestr,14+1,"%Y%m%d%H%M%S", 
313         localtime(&(rb_data.files[i].creation_time)));
314       new_name = g_strconcat(rb_data.fprefix,"_", filenum, "_", timestr, 
315         rb_data.fsuffix, NULL);
316       if (rename(rb_data.files[i].name, new_name) != 0) {
317         /* save the latest error */
318         if (err != NULL) {
319           *err = errno;
320         }
321         ret_val = FALSE;
322         g_free(new_name);
323       } else {
324         g_free(rb_data.files[i].name);
325         rb_data.files[i].name = new_name;
326       }
327     } else {
328       /* this file has never been used - remove it */
329       unlink(rb_data.files[i].name);
330     }
331   }
332   /* make the current file the save file */
333   cf->save_file = rb_data.files[rb_data.curr_file_num].name;
334   return ret_val;
335 }
336
337 /* 
338  * Frees all memory allocated by the ringbuffer
339  */
340 void
341 ringbuf_free()
342
343   unsigned int i;
344   
345   if (rb_data.files != NULL) {
346     for (i=0; i < rb_data.num_files; i++) {
347       g_free(rb_data.files[i].name);
348       rb_data.files[i].name = NULL;
349     }
350     free(rb_data.files);
351     rb_data.files = NULL;
352   }
353   g_free(rb_data.fprefix);
354   g_free(rb_data.fsuffix);
355 }
356
357 /* 
358  * Frees all memory allocated by the ringbuffer
359  */
360 void 
361 ringbuf_error_cleanup()
362 {
363   unsigned int i;
364   int err;
365   
366   if (rb_data.files == NULL) {
367     ringbuf_free();
368     return;
369   }
370
371   for (i=0; i<rb_data.num_files; i++) {
372     /* try to close via wtap */
373     if (rb_data.files[i].pdh != NULL) {
374       if (wtap_dump_close(rb_data.files[i].pdh, &err) == TRUE) {
375         /* done */
376         rb_data.files[i].fd = -1;
377       }
378     }
379     /* close directly if still open */
380     if (rb_data.files[i].fd != -1) {
381       close(rb_data.files[i].fd);
382     }
383     /* remove the other files, the initial file will be handled
384        by the calling funtion */
385     if (rb_data.files[i].name != NULL) {
386       unlink(rb_data.files[i].name);
387     }
388   }
389   /* free the memory */  
390   ringbuf_free();
391 }
392
393 #endif /* HAVE_LIBPCAP */