Allow the user to save either all of the current capture, or only the
[obnox/wireshark/wip.git] / capture.c
1 /* capture.c
2  * Routines for packet capture windows
3  *
4  * $Id: capture.c,v 1.84 1999/11/30 20:49:45 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_LIBPCAP
32
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
35 #endif
36
37 #ifdef HAVE_SYS_STAT_H
38 # include <sys/stat.h>
39 #endif
40
41 #ifdef HAVE_SYS_WAIT_H
42 # include <sys/wait.h>
43 #endif
44
45 #include <gtk/gtk.h>
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <ctype.h>
49 #include <string.h>
50 #include <fcntl.h>
51
52 #ifdef HAVE_UNISTD_H
53 #include <unistd.h>
54 #endif
55
56 #include <time.h>
57
58 #ifdef HAVE_SYS_SOCKET_H
59 #include <sys/socket.h>
60 #endif
61
62 #ifdef HAVE_SYS_IOCTL_H
63 #include <sys/ioctl.h>
64 #endif
65
66 #ifdef HAVE_NET_IF_H
67 #include <net/if.h>
68 #endif
69
70 #include <signal.h>
71 #include <errno.h>
72
73 #ifdef NEED_SNPRINTF_H
74 # ifdef HAVE_STDARG_H
75 #  include <stdarg.h>
76 # else
77 #  include <varargs.h>
78 # endif
79 # include "snprintf.h"
80 #endif
81
82 #ifndef lib_pcap_h
83 #include <pcap.h>
84 #endif
85
86 #include "gtk/main.h"
87 #include "gtk/gtkglobals.h"
88 #include "packet.h"
89 #include "file.h"
90 #include "gtk/menu.h"
91 #include "capture.h"
92 #include "util.h"
93 #include "prefs.h"
94 #include "globals.h"
95
96 int sync_mode;  /* fork a child to do the capture, and sync between them */
97 static int sync_pipe[2]; /* used to sync father */
98 int quit_after_cap; /* Makes a "capture only mode". Implies -k */
99 gboolean capture_child; /* if this is the child for "-S" */
100 static guint cap_input_id;
101
102 static void cap_file_input_cb(gpointer, gint, GdkInputCondition);
103 static void capture_stop_cb(GtkWidget *, gpointer);
104 static void capture_pcap_cb(u_char *, const struct pcap_pkthdr *,
105   const u_char *);
106 static float pct(gint, gint);
107
108 typedef struct _loop_data {
109   gint           go;
110   gint           max;
111   gint           linktype;
112   gint           sync_packets;
113   packet_counts  counts;
114   wtap_dumper   *pdh;
115 } loop_data;
116
117 /* Open a specified file, or create a temporary file, and start a capture
118    to the file in question. */
119 void
120 do_capture(char *capfile_name)
121 {
122   char tmpname[128+1];
123   gboolean is_tempfile;
124   u_char c;
125   int i;
126   guint byte_count;
127   char *msg;
128   int err;
129   int capture_succeeded;
130
131   if (capfile_name != NULL) {
132     /* Try to open/create the specified file for use as a capture buffer. */
133     cf.save_file_fd = open(capfile_name, O_RDWR|O_TRUNC|O_CREAT, 0600);
134     is_tempfile = FALSE;
135   } else {
136     /* Choose a random name for the capture buffer */
137     cf.save_file_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
138     capfile_name = g_strdup(tmpname);
139     is_tempfile = TRUE;
140   }
141   if (cf.save_file_fd == -1) {
142     simple_dialog(ESD_TYPE_WARN, NULL,
143         "The file to which the capture would be saved (\"%s\")"
144         "could not be opened: %s.", capfile_name, strerror(errno));
145     return;
146   }
147   close_cap_file(&cf, info_bar);
148   g_assert(cf.save_file == NULL);
149   cf.save_file = capfile_name;
150
151   if (sync_mode) {      /*  use fork() for capture */
152     int  fork_child;
153     char ssnap[24];
154     char scount[24];    /* need a constant for len of numbers */
155     char save_file_fd[24];
156
157     sprintf(ssnap,"%d",cf.snap); /* in lieu of itoa */
158     sprintf(scount,"%d",cf.count);
159     sprintf(save_file_fd,"%d",cf.save_file_fd);
160     signal(SIGCHLD, SIG_IGN);
161     pipe(sync_pipe);
162     if ((fork_child = fork()) == 0) {
163       /*
164        * Child process - run Ethereal with the right arguments to make
165        * it just pop up the live capture dialog box and capture with
166        * the specified capture parameters, writing to the specified file.
167        *
168        * args: -i interface specification
169        * -w file to write
170        * -W file descriptor to write
171        * -c count to capture
172        * -s snaplen
173        * -m / -b fonts
174        * -f "filter expression"
175        */
176       close(1);
177       dup(sync_pipe[1]);
178       close(sync_pipe[0]);
179       execlp(ethereal_path, CHILD_NAME, "-i", cf.iface,
180                 "-w", cf.save_file, "-W", save_file_fd,
181                 "-c", scount, "-s", ssnap, 
182                 "-m", medium_font, "-b", bold_font,
183                 (cf.cfilter == NULL)? 0 : "-f",
184                 (cf.cfilter == NULL)? 0 : cf.cfilter,
185                 (const char *)NULL);    
186     } else {
187       /* Parent process - read messages from the child process over the
188          sync pipe. */
189       close(sync_pipe[1]);
190
191       /* Read a byte count from "sync_pipe[0]", terminated with a
192          colon; if the count is 0, the child process created the
193          capture file and we should start reading from it, otherwise
194          the capture couldn't start and the count is a count of bytes
195          of error message, and we should display the message. */
196       byte_count = 0;
197       for (;;) {
198         i = read(sync_pipe[0], &c, 1);
199         if (i == 0) {
200           /* EOF - the child process died.
201              Close the read side of the sync pipe, remove the capture file,
202              and report the failure.
203              XXX - reap the child process and report the status in detail. */
204           close(sync_pipe[0]);
205           unlink(cf.save_file);
206           g_free(cf.save_file);
207           cf.save_file = NULL;
208           simple_dialog(ESD_TYPE_WARN, NULL, "Capture child process died");
209           return;
210         }
211         if (c == ';')
212           break;
213         if (!isdigit(c)) {
214           /* Child process handed us crap.
215              Close the read side of the sync pipe, remove the capture file,
216              and report the failure. */
217           close(sync_pipe[0]);
218           unlink(cf.save_file);
219           g_free(cf.save_file);
220           cf.save_file = NULL;
221           simple_dialog(ESD_TYPE_WARN, NULL,
222              "Capture child process sent us a bad message");
223           return;
224         }
225         byte_count = byte_count*10 + c - '0';
226       }
227       if (byte_count == 0) {
228         /* Success.  Open the capture file, and set up to read it. */
229         err = start_tail_cap_file(cf.save_file, is_tempfile, &cf);
230         if (err == 0) {
231           /* We were able to open and set up to read the capture file;
232              arrange that our callback be called whenever it's possible
233              to read from the sync pipe, so that it's called when
234              the child process wants to tell us something. */
235           cap_input_id = gtk_input_add_full(sync_pipe[0],
236                                        GDK_INPUT_READ,
237                                        cap_file_input_cb,
238                                        NULL,
239                                        (gpointer) &cf,
240                                        NULL);
241         } else {
242           /* We weren't able to open the capture file; complain, and
243              close the sync pipe. */
244           simple_dialog(ESD_TYPE_WARN, NULL,
245                         file_open_error_message(err, FALSE), cf.save_file);
246
247           /* Close the sync pipe. */
248           close(sync_pipe[0]);
249
250           /* Don't unlink the save file - leave it around, for debugging
251              purposes. */
252           g_free(cf.save_file);
253           cf.save_file = NULL;
254         }
255       } else {
256         /* Failure - the child process sent us a message indicating
257            what the problem was. */
258         msg = g_malloc(byte_count + 1);
259         if (msg == NULL) {
260           simple_dialog(ESD_TYPE_WARN, NULL,
261                 "Capture child process failed, but its error message was too big.");
262         } else {
263           i = read(sync_pipe[0], msg, byte_count);
264           if (i < 0) {
265             simple_dialog(ESD_TYPE_WARN, NULL,
266                   "Capture child process failed: Error %s reading its error message.",
267                   strerror(errno));
268           } else if (i == 0) {
269             simple_dialog(ESD_TYPE_WARN, NULL,
270                   "Capture child process failed: EOF reading its error message.");
271           } else
272             simple_dialog(ESD_TYPE_WARN, NULL, msg);
273           g_free(msg);
274
275           /* Close the sync pipe. */
276           close(sync_pipe[0]);
277
278           /* Get rid of the save file - the capture never started. */
279           unlink(cf.save_file);
280           g_free(cf.save_file);
281           cf.save_file = NULL;
282         }
283       }
284     }
285   } else {
286     /* Not sync mode. */
287     capture_succeeded = capture();
288     if (quit_after_cap) {
289       /* DON'T unlink the save file.  Presumably someone wants it. */
290       gtk_exit(0);
291     }
292     if (capture_succeeded) {
293       /* Capture succeeded; read in the capture file. */
294       if ((err = open_cap_file(cf.save_file, is_tempfile, &cf)) == 0) {
295         /* Set the read filter to NULL. */
296         cf.rfcode = NULL;
297         err = read_cap_file(&cf);
298       }
299     }
300     /* We're not doing a capture any more, so we don't have a save
301        file. */
302     g_free(cf.save_file);
303     cf.save_file = NULL;
304   }
305 }
306
307 /* There's stuff to read from the sync pipe, meaning the child has sent
308    us a message, or the sync pipe has closed, meaning the child has
309    closed it (perhaps because it exited). */
310 static void 
311 cap_file_input_cb(gpointer data, gint source, GdkInputCondition condition)
312 {
313   capture_file *cf = (capture_file *)data;
314   char buffer[256+1], *p = buffer, *q = buffer;
315   int  nread;
316   int  to_read = 0;
317   gboolean exit_loop = FALSE;
318   int  err;
319   int  wstatus;
320   int  wsignal;
321   char *msg;
322   char *sigmsg;
323   char sigmsg_buf[6+1+3+1];
324   char *coredumped;
325
326   /* avoid reentrancy problems and stack overflow */
327   gtk_input_remove(cap_input_id);
328
329   if ((nread = read(sync_pipe[0], buffer, 256)) <= 0) {
330     /* The child has closed the sync pipe, meaning it's not going to be
331        capturing any more packets.  Pick up its exit status, and
332        complain if it died of a signal. */
333     if (wait(&wstatus) != -1) {
334       /* XXX - are there any platforms on which we can run that *don't*
335          support POSIX.1's <sys/wait.h> and macros therein? */
336       wsignal = wstatus & 0177;
337       coredumped = "";
338       if (wstatus == 0177) {
339         /* It stopped, rather than exiting.  "Should not happen." */
340         msg = "stopped";
341         wsignal = (wstatus >> 8) & 0xFF;
342       } else {
343         msg = "terminated";
344         if (wstatus & 0200)
345           coredumped = " - core dumped";
346       }
347       if (wsignal != 0) {
348         switch (wsignal) {
349
350         case SIGHUP:
351           sigmsg = "Hangup";
352           break;
353
354         case SIGINT:
355           sigmsg = "Interrupted";
356           break;
357
358         case SIGQUIT:
359           sigmsg = "Quit";
360           break;
361
362         case SIGILL:
363           sigmsg = "Illegal instruction";
364           break;
365
366         case SIGTRAP:
367           sigmsg = "Trace trap";
368           break;
369
370         case SIGABRT:
371           sigmsg = "Abort";
372           break;
373
374         case SIGFPE:
375           sigmsg = "Arithmetic exception";
376           break;
377
378         case SIGKILL:
379           sigmsg = "Killed";
380           break;
381
382         case SIGBUS:
383           sigmsg = "Bus error";
384           break;
385
386         case SIGSEGV:
387           sigmsg = "Segmentation violation";
388           break;
389
390         /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO 
391                 Linux is POSIX compliant.  These are not POSIX-defined signals ---
392                   ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
393
394                ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
395                 were omitted from POSIX.1 because their behavior is
396                 implementation dependent and could not be adequately catego-
397                 rized.  Conforming implementations may deliver these sig-
398                 nals, but must document the circumstances under which they
399                 are delivered and note any restrictions concerning their
400                 delivery.''
401         */
402
403         #ifdef SIGSYS
404         case SIGSYS:
405           sigmsg = "Bad system call";
406           break;
407         #endif
408
409         case SIGPIPE:
410           sigmsg = "Broken pipe";
411           break;
412
413         case SIGALRM:
414           sigmsg = "Alarm clock";
415           break;
416
417         case SIGTERM:
418           sigmsg = "Terminated";
419           break;
420
421         default:
422           sprintf(sigmsg_buf, "Signal %d", wsignal);
423           sigmsg = sigmsg_buf;
424           break;
425         }
426         simple_dialog(ESD_TYPE_WARN, NULL,
427                 "Child capture process %s: %s%s", msg, sigmsg, coredumped);
428       }
429     }
430       
431     /* Read what remains of the capture file, and finish the capture.
432        XXX - do something if this fails? */
433     err = finish_tail_cap_file(cf);
434
435     /* We're not doing a capture any more, so we don't have a save
436        file. */
437     g_free(cf->save_file);
438     cf->save_file = NULL;
439
440     return;
441   }
442
443   buffer[nread] = '\0';
444
445   while(!exit_loop) {
446     /* look for (possibly multiple) '*' */
447     switch (*q) {
448     case '*' :
449       to_read += atoi(p);
450       p = q + 1; 
451       q++;
452       break;
453     case '\0' :
454       /* XXX should handle the case of a pipe full (i.e. no star found) */
455       exit_loop = TRUE;
456       break;
457     default :
458       q++;
459       break;
460     } 
461   }
462
463   /* Read from the capture file the number of records the child told us
464      it added.
465      XXX - do something if this fails? */
466   err = continue_tail_cap_file(cf, to_read);
467
468   /* restore pipe handler */
469   cap_input_id = gtk_input_add_full (sync_pipe[0],
470                                      GDK_INPUT_READ,
471                                      cap_file_input_cb,
472                                      NULL,
473                                      (gpointer) cf,
474                                      NULL);
475 }
476
477 /* Do the low-level work of a capture.
478    Returns TRUE if it succeeds, FALSE otherwise. */
479 int
480 capture(void)
481 {
482   GtkWidget  *cap_w, *main_vb, *count_lb, *tcp_lb, *udp_lb, *icmp_lb,
483              *ospf_lb, *gre_lb, *netbios_lb, *other_lb, *stop_bt;
484   pcap_t     *pch;
485   gchar       err_str[PCAP_ERRBUF_SIZE], label_str[32];
486   loop_data   ld;
487   bpf_u_int32 netnum, netmask;
488   time_t      upd_time, cur_time;
489   int         err, inpkts;
490   char        errmsg[1024+1];
491
492   ld.go             = TRUE;
493   ld.counts.total   = 0;
494   ld.max            = cf.count;
495   ld.linktype       = WTAP_ENCAP_UNKNOWN;
496   ld.sync_packets   = 0;
497   ld.counts.tcp     = 0;
498   ld.counts.udp     = 0;
499   ld.counts.icmp    = 0;
500   ld.counts.ospf    = 0;
501   ld.counts.gre     = 0;
502   ld.counts.netbios = 0;
503   ld.counts.other   = 0;
504   ld.pdh            = NULL;
505
506   /* Open the network interface to capture from it. */
507   pch = pcap_open_live(cf.iface, cf.snap, 1, 250, err_str);
508
509   if (pch == NULL) {
510     /* Well, we couldn't start the capture.
511        If this is a child process that does the capturing in sync
512        mode or fork mode, it shouldn't do any UI stuff until we pop up the
513        capture-progress window, and, since we couldn't start the
514        capture, we haven't popped it up. */
515     if (!capture_child) {
516       while (gtk_events_pending()) gtk_main_iteration();
517     }
518     snprintf(errmsg, sizeof errmsg,
519       "The capture session could not be initiated (%s).\n"
520       "Please check to make sure you have sufficient permissions, and that\n"
521       "you have the proper interface specified.", err_str);
522     goto error;
523   }
524
525   if (cf.cfilter) {
526     /* A capture filter was specified; set it up. */
527     if (pcap_lookupnet (cf.iface, &netnum, &netmask, err_str) < 0) {
528       snprintf(errmsg, sizeof errmsg,
529         "Can't use filter:  Couldn't obtain netmask info (%s).", err_str);
530       goto error;
531     }
532     if (pcap_compile(pch, &cf.fcode, cf.cfilter, 1, netmask) < 0) {
533       snprintf(errmsg, sizeof errmsg, "Unable to parse filter string (%s).",
534         pcap_geterr(pch));
535       goto error;
536     }
537     if (pcap_setfilter(pch, &cf.fcode) < 0) {
538       snprintf(errmsg, sizeof errmsg, "Can't install filter (%s).",
539         pcap_geterr(pch));
540       goto error;
541     }
542   }
543
544   /* Set up to write to the capture file. */
545   ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_datalink(pch));
546   if (ld.linktype == WTAP_ENCAP_UNKNOWN) {
547     strcpy(errmsg, "The network you're capturing from is of a type"
548              " that Ethereal doesn't support.");
549     goto error;
550   }
551   ld.pdh = wtap_dump_fdopen(cf.save_file_fd, WTAP_FILE_PCAP,
552                 ld.linktype, pcap_snapshot(pch), &err);
553
554   if (ld.pdh == NULL) {
555     /* We couldn't set up to write to the capture file. */
556     switch (err) {
557
558     case WTAP_ERR_CANT_OPEN:
559       strcpy(errmsg, "The file to which the capture would be saved"
560                " couldn't be created for some unknown reason.");
561       break;
562
563     case WTAP_ERR_SHORT_WRITE:
564       strcpy(errmsg, "A full header couldn't be written to the file"
565                " to which the capture would be saved.");
566       break;
567
568     default:
569       if (err < 0) {
570         sprintf(errmsg, "The file to which the capture would be"
571                      " saved (\"%s\") could not be opened: Error %d.",
572                         cf.save_file, err);
573       } else {
574         sprintf(errmsg, "The file to which the capture would be"
575                      " saved (\"%s\") could not be opened: %s.",
576                         cf.save_file, strerror(err));
577       }
578       break;
579     }
580     goto error;
581   }
582
583   if (capture_child) {
584     /* Well, we should be able to start capturing.
585
586        This is the child process for a sync mode capture, so sync out
587        the capture file, so the header makes it to the file system,
588        and send a "capture started successfully and capture file created"
589        message to our parent so that they'll open the capture file and
590        update its windows to indicate that we have a live capture in
591        progress. */
592     fflush(wtap_dump_file(ld.pdh));
593     write(1, "0;", 2);
594   }
595
596   cap_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
597   gtk_window_set_title(GTK_WINDOW(cap_w), "Ethereal: Capture / Playback");
598
599   /* Container for capture display widgets */
600   main_vb = gtk_vbox_new(FALSE, 1);
601   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
602   gtk_container_add(GTK_CONTAINER(cap_w), main_vb);
603   gtk_widget_show(main_vb);
604
605   count_lb = gtk_label_new("Count: 0");
606   gtk_box_pack_start(GTK_BOX(main_vb), count_lb, FALSE, FALSE, 3);
607   gtk_widget_show(count_lb);
608
609   tcp_lb = gtk_label_new("TCP: 0 (0.0%)");
610   gtk_box_pack_start(GTK_BOX(main_vb), tcp_lb, FALSE, FALSE, 3);
611   gtk_widget_show(tcp_lb);
612
613   udp_lb = gtk_label_new("UDP: 0 (0.0%)");
614   gtk_box_pack_start(GTK_BOX(main_vb), udp_lb, FALSE, FALSE, 3);
615   gtk_widget_show(udp_lb);
616
617   icmp_lb = gtk_label_new("ICMP: 0 (0.0%)");
618   gtk_box_pack_start(GTK_BOX(main_vb), icmp_lb, FALSE, FALSE, 3);
619   gtk_widget_show(icmp_lb);
620
621   ospf_lb = gtk_label_new("OSPF: 0 (0.0%)");
622   gtk_box_pack_start(GTK_BOX(main_vb), ospf_lb, FALSE, FALSE, 3);
623   gtk_widget_show(ospf_lb);
624
625   gre_lb = gtk_label_new("GRE: 0 (0.0%)");
626   gtk_box_pack_start(GTK_BOX(main_vb), gre_lb, FALSE, FALSE, 3);
627   gtk_widget_show(gre_lb);
628
629   netbios_lb = gtk_label_new("NetBIOS: 0 (0.0%)");
630   gtk_box_pack_start(GTK_BOX(main_vb), netbios_lb, FALSE, FALSE, 3);
631   gtk_widget_show(netbios_lb);
632
633   other_lb = gtk_label_new("Other: 0 (0.0%)");
634   gtk_box_pack_start(GTK_BOX(main_vb), other_lb, FALSE, FALSE, 3);
635   gtk_widget_show(other_lb);
636
637   stop_bt = gtk_button_new_with_label ("Stop");
638   gtk_signal_connect(GTK_OBJECT(stop_bt), "clicked",
639     GTK_SIGNAL_FUNC(capture_stop_cb), (gpointer) &ld);
640   gtk_box_pack_end(GTK_BOX(main_vb), stop_bt, FALSE, FALSE, 3);
641   GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
642   gtk_widget_grab_default(stop_bt);
643   GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
644   gtk_widget_grab_default(stop_bt);
645   gtk_widget_show(stop_bt);
646
647   gtk_widget_show(cap_w);
648   gtk_grab_add(cap_w);
649
650   upd_time = time(NULL);
651   while (ld.go) {
652     while (gtk_events_pending()) gtk_main_iteration();
653     inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld);
654     if (inpkts > 0)
655       ld.sync_packets += inpkts;
656     /* Only update once a second so as not to overload slow displays */
657     cur_time = time(NULL);
658     if (cur_time > upd_time) {
659       upd_time = cur_time;
660
661       sprintf(label_str, "Count: %d", ld.counts.total);
662       gtk_label_set(GTK_LABEL(count_lb), label_str);
663
664       sprintf(label_str, "TCP: %d (%.1f%%)", ld.counts.tcp,
665                 pct(ld.counts.tcp, ld.counts.total));
666       gtk_label_set(GTK_LABEL(tcp_lb), label_str);
667
668       sprintf(label_str, "UDP: %d (%.1f%%)", ld.counts.udp,
669                 pct(ld.counts.udp, ld.counts.total));
670       gtk_label_set(GTK_LABEL(udp_lb), label_str);
671
672       sprintf(label_str, "ICMP: %d (%.1f%%)", ld.counts.icmp,
673                 pct(ld.counts.icmp, ld.counts.total));
674       gtk_label_set(GTK_LABEL(icmp_lb), label_str);
675
676       sprintf(label_str, "OSPF: %d (%.1f%%)", ld.counts.ospf,
677                 pct(ld.counts.ospf, ld.counts.total));
678       gtk_label_set(GTK_LABEL(ospf_lb), label_str);
679
680       sprintf(label_str, "GRE: %d (%.1f%%)", ld.counts.gre,
681                 pct(ld.counts.gre, ld.counts.total));
682       gtk_label_set(GTK_LABEL(gre_lb), label_str);
683
684       sprintf(label_str, "NetBIOS: %d (%.1f%%)", ld.counts.netbios,
685                 pct(ld.counts.netbios, ld.counts.total));
686       gtk_label_set(GTK_LABEL(netbios_lb), label_str);
687
688       sprintf(label_str, "Other: %d (%.1f%%)", ld.counts.other,
689                 pct(ld.counts.other, ld.counts.total));
690       gtk_label_set(GTK_LABEL(other_lb), label_str);
691
692       /* do sync here, too */
693       fflush(wtap_dump_file(ld.pdh));
694       if (capture_child && ld.sync_packets) {
695         /* This is the child process for a sync mode capture, so send
696            our parent a message saying we've written out "ld.sync_packets"
697            packets to the capture file. */
698         char tmp[20];
699         sprintf(tmp, "%d*", ld.sync_packets);
700         write(1, tmp, strlen(tmp));
701         ld.sync_packets = 0;
702       }
703     }
704   }
705     
706   if (!wtap_dump_close(ld.pdh, &err)) {
707     /* XXX - in fork mode, this may not pop up, or, if it does,
708        it may disappear as soon as we exit.
709
710        We should have the parent process, while it's reading
711        the packet count update messages, catch error messages
712        and pop up a message box if it sees one. */
713     switch (err) {
714
715     case WTAP_ERR_CANT_CLOSE:
716       simple_dialog(ESD_TYPE_WARN, NULL,
717                 "The file to which the capture was being saved"
718                 " couldn't be closed for some unknown reason.");
719       break;
720
721     case WTAP_ERR_SHORT_WRITE:
722       simple_dialog(ESD_TYPE_WARN, NULL,
723                 "Not all the data could be written to the file"
724                 " to which the capture was being saved.");
725       break;
726
727     default:
728       simple_dialog(ESD_TYPE_WARN, NULL,
729                 "The file to which the capture was being"
730                 " saved (\"%s\") could not be closed: %s.",
731                 cf.save_file, wtap_strerror(err));
732       break;
733     }
734   }
735   pcap_close(pch);
736
737   gtk_grab_remove(GTK_WIDGET(cap_w));
738   gtk_widget_destroy(GTK_WIDGET(cap_w));
739
740   return TRUE;
741
742 error:
743   /* We couldn't even start the capture, so get rid of the capture
744      file. */
745   unlink(cf.save_file); /* silently ignore error */
746   g_free(cf.save_file);
747   cf.save_file = NULL;
748   if (capture_child) {
749     /* This is the child process for a sync mode capture.
750        Send the error message to our parent, so they can display a
751        dialog box containing it. */
752     int msglen = strlen(errmsg);
753     char lenbuf[10+1+1];
754     sprintf(lenbuf, "%u;", msglen);
755     write(1, lenbuf, strlen(lenbuf));
756     write(1, errmsg, msglen);
757   } else {
758     /* Display the dialog box ourselves; there's no parent. */
759     simple_dialog(ESD_TYPE_WARN, NULL, errmsg);
760   }
761   if (pch != NULL)
762     pcap_close(pch);
763
764   return FALSE;
765 }
766
767 static float
768 pct(gint num, gint denom) {
769   if (denom) {
770     return (float) num * 100.0 / (float) denom;
771   } else {
772     return 0.0;
773   }
774 }
775
776 static void
777 capture_stop_cb(GtkWidget *w, gpointer data) {
778   loop_data *ld = (loop_data *) data;
779   
780   ld->go = FALSE;
781 }
782
783 static void
784 capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
785   const u_char *pd) {
786   struct wtap_pkthdr whdr;
787   loop_data *ld = (loop_data *) user;
788   int err;
789
790   if ((++ld->counts.total >= ld->max) && (ld->max > 0)) 
791   {
792      ld->go = FALSE;
793   }
794   if (ld->pdh) {
795      whdr.ts = phdr->ts;
796      whdr.caplen = phdr->caplen;
797      whdr.len = phdr->len;
798      whdr.pkt_encap = ld->linktype;
799
800      /* XXX - do something if this fails */
801      wtap_dump(ld->pdh, &whdr, pd, &err);
802   }
803     
804   switch (ld->linktype) {
805     case WTAP_ENCAP_ETHERNET:
806       capture_eth(pd, phdr->caplen, &ld->counts);
807       break;
808     case WTAP_ENCAP_FDDI:
809     case WTAP_ENCAP_FDDI_BITSWAPPED:
810       capture_fddi(pd, phdr->caplen, &ld->counts);
811       break;
812     case WTAP_ENCAP_TR:
813       capture_tr(pd, phdr->caplen, &ld->counts);
814       break;
815     case WTAP_ENCAP_NULL:
816       capture_null(pd, phdr->caplen, &ld->counts);
817       break;
818     case WTAP_ENCAP_PPP:
819       capture_ppp(pd, phdr->caplen, &ld->counts);
820       break;
821     case WTAP_ENCAP_RAW_IP:
822       capture_raw(pd, phdr->caplen, &ld->counts);
823       break;
824     /* XXX - FreeBSD may append 4-byte ATM pseudo-header to DLT_ATM_RFC1483,
825        with LLC header following; we should implement it at some
826        point. */
827   }
828 }
829
830 #endif /* HAVE_LIBPCAP */