2 * Synchronisation between Ethereal capture parent and child instances
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
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.
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.
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.
44 #ifdef HAVE_SYS_WAIT_H
45 # include <sys/wait.h>
50 * Define various POSIX macros (and, in the case of WCOREDUMP, non-POSIX
51 * macros) on UNIX systems that don't have them.
54 # define WIFEXITED(status) (((status) & 0177) == 0)
57 # define WIFSTOPPED(status) (((status) & 0177) == 0177)
60 # define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status))
63 # define WEXITSTATUS(status) ((status) >> 8)
66 # define WTERMSIG(status) ((status) & 0177)
69 # define WCOREDUMP(status) ((status) & 0200)
72 # define WSTOPSIG(status) ((status) >> 8)
76 #include <epan/packet.h>
77 #include <epan/prefs.h>
83 #include "capture_sync.h"
84 #include "simple_dialog.h"
87 #include "capture-wpcap.h"
96 #include <process.h> /* For spawning child process */
99 /* Win32 needs the O_BINARY flag for open() */
106 static char *sync_pipe_signame(int);
110 static gboolean sync_pipe_input_cb(gint source, gpointer user_data);
111 static void sync_pipe_wait_for_child(capture_options *capture_opts, gboolean always_report);
113 /* Size of buffer to hold decimal representation of
114 signed/unsigned 64-bit int */
115 #define SP_DECISIZE 20
118 * Indications sent out on the sync pipe.
120 #define SP_CAPSTART ';' /* capture start message */
121 #define SP_PACKET_COUNT '*' /* followed by count of packets captured since last message */
122 #define SP_ERROR_MSG '!' /* followed by length of error message that follows */
123 #define SP_DROPS '#' /* followed by count of packets dropped in capture */
124 #define SP_FILE ':' /* followed by length of the name of the last opened file that follows */
129 sync_pipe_capstart_to_parent(void)
131 static const char capstart_msg = SP_CAPSTART;
133 write(1, &capstart_msg, 1);
137 sync_pipe_packet_count_to_parent(int packet_count)
139 char tmp[SP_DECISIZE+1+1];
140 sprintf(tmp, "%d%c", packet_count, SP_PACKET_COUNT);
141 write(1, tmp, strlen(tmp));
145 sync_pipe_filename_to_parent(const char *filename)
147 int msglen = strlen(filename);
148 char lenbuf[SP_DECISIZE+1+1];
150 sprintf(lenbuf, "%u%c", msglen, SP_FILE);
151 write(1, lenbuf, strlen(lenbuf));
152 write(1, filename, msglen);
156 sync_pipe_errmsg_to_parent(const char *errmsg)
158 int msglen = strlen(errmsg);
159 char lenbuf[SP_DECISIZE+1+1];
161 sprintf(lenbuf, "%u%c", msglen, SP_ERROR_MSG);
162 write(1, lenbuf, strlen(lenbuf));
163 write(1, errmsg, msglen);
167 sync_pipe_drops_to_parent(int drops)
169 char tmp[SP_DECISIZE+1+1];
170 sprintf(tmp, "%d%c", drops, SP_DROPS);
171 write(1, tmp, strlen(tmp));
175 /* Add a string pointer to a NULL-terminated array of string pointers. */
177 sync_pipe_add_arg(char **args, int *argc, char *arg)
179 /* Grow the array; "*argc" currently contains the number of string
180 pointers, *not* counting the NULL pointer at the end, so we have
181 to add 2 in order to get the new size of the array, including the
182 new pointer and the terminating NULL pointer. */
183 args = g_realloc(args, (*argc + 2) * sizeof (char *));
185 /* Stuff the pointer into the penultimate element of the array, which
186 is the one at the index specified by "*argc". */
189 /* Now bump the count. */
192 /* We overwrite the NULL pointer; put it back right after the
200 /* Given a string, return a pointer to a quote-encapsulated version of
201 the string, so we can pass it as an argument with "spawnvp" even
202 if it contains blanks. */
204 sync_pipe_quote_encapsulate(const char *string)
206 char *encapsulated_string;
208 encapsulated_string = g_new(char, strlen(string) + 3);
209 sprintf(encapsulated_string, "\"%s\"", string);
210 return encapsulated_string;
217 sync_pipe_do_capture(capture_options *capture_opts, gboolean is_tempfile) {
224 char scount[24]; /* need a constant for len of numbers */
225 char sautostop_filesize[24]; /* need a constant for len of numbers */
226 char sautostop_duration[24]; /* need a constant for len of numbers */
227 char save_file_fd_str[24];
235 char sync_pipe_fd[24];
239 enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
240 int sync_pipe[2]; /* pipes used to sync between instances */
242 capture_opts->fork_child = -1;
244 /* Allocate the string pointer array with enough space for the
245 terminating NULL pointer. */
247 argv = g_malloc(sizeof (char *));
250 /* Now add those arguments used on all platforms. */
251 argv = sync_pipe_add_arg(argv, &argc, CHILD_NAME);
253 argv = sync_pipe_add_arg(argv, &argc, "-i");
254 argv = sync_pipe_add_arg(argv, &argc, capture_opts->iface);
256 argv = sync_pipe_add_arg(argv, &argc, "-w");
257 argv = sync_pipe_add_arg(argv, &argc, capture_opts->save_file);
259 argv = sync_pipe_add_arg(argv, &argc, "-W");
260 sprintf(save_file_fd_str,"%d",capture_opts->save_file_fd); /* in lieu of itoa */
261 argv = sync_pipe_add_arg(argv, &argc, save_file_fd_str);
263 if (capture_opts->has_autostop_packets) {
264 argv = sync_pipe_add_arg(argv, &argc, "-c");
265 sprintf(scount,"%d",capture_opts->autostop_packets);
266 argv = sync_pipe_add_arg(argv, &argc, scount);
269 if (capture_opts->has_snaplen) {
270 argv = sync_pipe_add_arg(argv, &argc, "-s");
271 sprintf(ssnap,"%d",capture_opts->snaplen);
272 argv = sync_pipe_add_arg(argv, &argc, ssnap);
275 if (capture_opts->linktype != -1) {
276 argv = sync_pipe_add_arg(argv, &argc, "-y");
277 #ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME
278 sprintf(ssnap,"%s",pcap_datalink_val_to_name(capture_opts->linktype));
280 /* XXX - just treat it as a number */
281 sprintf(ssnap,"%d",capture_opts->linktype);
283 argv = sync_pipe_add_arg(argv, &argc, ssnap);
286 if (capture_opts->has_autostop_filesize) {
287 argv = sync_pipe_add_arg(argv, &argc, "-a");
288 sprintf(sautostop_filesize,"filesize:%d",capture_opts->autostop_filesize);
289 argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
292 if (capture_opts->has_autostop_duration) {
293 argv = sync_pipe_add_arg(argv, &argc, "-a");
294 sprintf(sautostop_duration,"duration:%d",capture_opts->autostop_duration);
295 argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
298 if (!capture_opts->show_info) {
299 argv = sync_pipe_add_arg(argv, &argc, "-H");
302 if (!capture_opts->promisc_mode)
303 argv = sync_pipe_add_arg(argv, &argc, "-p");
306 /* Create a pipe for the child process */
308 if(_pipe(sync_pipe, 512, O_BINARY) < 0) {
309 /* Couldn't create the pipe between parent and child. */
311 unlink(capture_opts->save_file);
312 g_free(capture_opts->save_file);
313 capture_opts->save_file = NULL;
314 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
319 /* Convert font name to a quote-encapsulated string and pass to child */
320 argv = sync_pipe_add_arg(argv, &argc, "-m");
321 fontstring = sync_pipe_quote_encapsulate(prefs.PREFS_GUI_FONT_NAME);
322 argv = sync_pipe_add_arg(argv, &argc, fontstring);
324 /* Convert pipe write handle to a string and pass to child */
325 argv = sync_pipe_add_arg(argv, &argc, "-Z");
326 itoa(sync_pipe[PIPE_WRITE], sync_pipe_fd, 10);
327 argv = sync_pipe_add_arg(argv, &argc, sync_pipe_fd);
329 /* Convert filter string to a quote delimited string and pass to child */
331 if (capture_opts->cfilter != NULL && strlen(capture_opts->cfilter) != 0) {
332 argv = sync_pipe_add_arg(argv, &argc, "-f");
333 filterstring = sync_pipe_quote_encapsulate(capture_opts->cfilter);
334 argv = sync_pipe_add_arg(argv, &argc, filterstring);
338 capture_opts->fork_child = spawnvp(_P_NOWAIT, ethereal_path, argv);
341 g_free(filterstring);
344 if (pipe(sync_pipe) < 0) {
345 /* Couldn't create the pipe between parent and child. */
347 unlink(capture_opts->save_file);
348 g_free(capture_opts->save_file);
349 capture_opts->save_file = NULL;
350 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
355 argv = sync_pipe_add_arg(argv, &argc, "-m");
356 argv = sync_pipe_add_arg(argv, &argc, prefs.PREFS_GUI_FONT_NAME);
358 if (capture_opts->cfilter != NULL && capture_opts->cfilter != 0) {
359 argv = sync_pipe_add_arg(argv, &argc, "-f");
360 argv = sync_pipe_add_arg(argv, &argc, capture_opts->cfilter);
363 if ((capture_opts->fork_child = fork()) == 0) {
365 * Child process - run Ethereal with the right arguments to make
366 * it just pop up the live capture dialog box and capture with
367 * the specified capture parameters, writing to the specified file.
369 * args: -i interface specification
371 * -W file descriptor to write
372 * -c count to capture
375 * -f "filter expression"
378 dup(sync_pipe[PIPE_WRITE]);
379 close(sync_pipe[PIPE_READ]);
380 execvp(ethereal_path, argv);
381 snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
382 ethereal_path, strerror(errno));
383 sync_pipe_errmsg_to_parent(errmsg);
385 /* Exit with "_exit()", so that we don't close the connection
386 to the X server (and cause stuff buffered up by our parent but
387 not yet sent to be sent, as that stuff should only be sent by
393 /* Parent process - read messages from the child process over the
395 g_free(argv); /* free up arg array */
397 /* Close the write side of the pipe, so that only the child has it
398 open, and thus it completely closes, and thus returns to us
399 an EOF indication, if the child closes it (either deliberately
400 or by exiting abnormally). */
401 close(sync_pipe[PIPE_WRITE]);
403 /* Close the save file FD, as we won't be using it - we'll be opening
404 it and reading the save file through Wiretap. */
405 close(capture_opts->save_file_fd);
407 if (capture_opts->fork_child == -1) {
408 /* We couldn't even create the child process. */
410 close(sync_pipe[PIPE_READ]);
411 unlink(capture_opts->save_file);
412 g_free(capture_opts->save_file);
413 capture_opts->save_file = NULL;
414 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
415 "Couldn't create child process: %s", strerror(error));
419 /* Read a byte count from "sync_pipe[PIPE_READ]", terminated with a
420 colon; if the count is 0, the child process created the
421 capture file and we should start reading from it, otherwise
422 the capture couldn't start and the count is a count of bytes
423 of error message, and we should display the message. */
426 i = read(sync_pipe[PIPE_READ], &c, 1);
428 /* EOF - the child process died.
429 Close the read side of the sync pipe, remove the capture file,
430 and report the failure. */
431 close(sync_pipe[PIPE_READ]);
432 unlink(capture_opts->save_file);
433 g_free(capture_opts->save_file);
434 capture_opts->save_file = NULL;
435 sync_pipe_wait_for_child(capture_opts, TRUE);
438 if (c == SP_CAPSTART || c == SP_ERROR_MSG)
441 /* Child process handed us crap.
442 Close the read side of the sync pipe, remove the capture file,
443 and report the failure. */
444 close(sync_pipe[PIPE_READ]);
445 unlink(capture_opts->save_file);
446 g_free(capture_opts->save_file);
447 capture_opts->save_file = NULL;
448 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
449 "Capture child process sent us a bad message");
452 byte_count = byte_count*10 + c - '0';
454 if (c != SP_CAPSTART) {
455 /* Failure - the child process sent us a message indicating
456 what the problem was. */
457 if (byte_count == 0) {
458 /* Zero-length message? */
459 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
460 "Capture child process failed, but its error message was empty.");
462 msg = g_malloc(byte_count + 1);
464 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
465 "Capture child process failed, but its error message was too big.");
467 i = read(sync_pipe[PIPE_READ], msg, byte_count);
468 msg[byte_count] = '\0';
470 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
471 "Capture child process failed: Error %s reading its error message.",
474 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
475 "Capture child process failed: EOF reading its error message.");
476 sync_pipe_wait_for_child(capture_opts, FALSE);
478 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
482 /* Close the sync pipe. */
483 close(sync_pipe[PIPE_READ]);
485 /* Get rid of the save file - the capture never started. */
486 unlink(capture_opts->save_file);
487 g_free(capture_opts->save_file);
488 capture_opts->save_file = NULL;
493 /* The child process started a capture.
494 Attempt to open the capture file and set up to read it. */
495 switch(cf_start_tail(capture_opts->cf, capture_opts->save_file, is_tempfile, &err)) {
497 /* We were able to open and set up to read the capture file;
498 arrange that our callback be called whenever it's possible
499 to read from the sync pipe, so that it's called when
500 the child process wants to tell us something. */
501 pipe_input_set_handler(sync_pipe[PIPE_READ], (gpointer) capture_opts, &capture_opts->fork_child, sync_pipe_input_cb);
506 /* We weren't able to open the capture file; user has been
507 alerted. Close the sync pipe. */
509 close(sync_pipe[PIPE_READ]);
511 /* Don't unlink the save file - leave it around, for debugging
513 g_free(capture_opts->save_file);
514 capture_opts->save_file = NULL;
519 g_assert_not_reached();
524 /* There's stuff to read from the sync pipe, meaning the child has sent
525 us a message, or the sync pipe has closed, meaning the child has
526 closed it (perhaps because it exited). */
528 sync_pipe_input_cb(gint source, gpointer user_data)
530 capture_options *capture_opts = (capture_options *)user_data;
532 char buffer[BUFSIZE+1], *p = buffer, *q = buffer, *msg, *r;
533 int nread, msglen, chars_to_copy;
538 /* we are a capture parent */
539 g_assert(!capture_opts->capture_child);
541 if ((nread = read(source, buffer, BUFSIZE)) <= 0) {
542 /* The child has closed the sync pipe, meaning it's not going to be
543 capturing any more packets. Pick up its exit status, and
544 complain if it did anything other than exit with status 0. */
545 sync_pipe_wait_for_child(capture_opts, FALSE);
547 /* Read what remains of the capture file, and finish the capture.
548 XXX - do something if this fails? */
549 switch (cf_finish_tail(capture_opts->cf, &err)) {
552 if(cf_packet_count(capture_opts->cf) == 0) {
553 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
554 "%sNo packets captured!%s\n\n"
555 "As no data was captured, closing the %scapture file!",
556 simple_dialog_primary_start(), simple_dialog_primary_end(),
557 cf_is_tempfile(capture_opts->cf) ? "temporary " : "");
558 cf_close(capture_opts->cf);
562 /* Just because we got an error, that doesn't mean we were unable
563 to read any of the file; we handle what we could get from the
567 case CF_READ_ABORTED:
568 /* Exit by leaving the main loop, so that any quit functions
569 we registered get called. */
574 /* We're not doing a capture any more, so we don't have a save
576 g_free(capture_opts->save_file);
577 capture_opts->save_file = NULL;
582 buffer[nread] = '\0';
585 /* look for (possibly multiple) indications */
587 case SP_PACKET_COUNT :
594 cf_set_drops_known(capture_opts->cf, TRUE);
595 cf_set_drops(capture_opts->cf, atoi(p));
606 /* Read the entire message.
607 XXX - if the child hasn't sent it all yet, this could cause us
608 to hang until they do. */
609 msg = g_malloc(msglen + 1);
611 while (msglen != 0) {
614 if ((nread = read(source, buffer, BUFSIZE)) <= 0)
619 chars_to_copy = MIN(msglen, nread);
620 memcpy(r, q, chars_to_copy);
623 nread -= chars_to_copy;
624 msglen -= chars_to_copy;
627 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
636 /* Read the entire message.
637 XXX - if the child hasn't sent it all yet, this could cause us
638 to hang until they do. */
639 msg = g_malloc(msglen + 1);
641 while (msglen != 0) {
644 if ((nread = read(source, buffer, BUFSIZE)) <= 0)
649 chars_to_copy = MIN(msglen, nread);
650 memcpy(r, q, chars_to_copy);
653 nread -= chars_to_copy;
654 msglen -= chars_to_copy;
658 /* currently, both filenames must be equal */
659 /* (this will change, when multiple files together with sync_mode are captured) */
660 g_assert(strcmp(capture_opts->save_file, msg) == 0);
662 /* save the new filename */
663 if(capture_opts->save_file != NULL) {
664 g_free(capture_opts->save_file);
666 capture_opts->save_file = g_strdup(msg);
676 /* Read from the capture file the number of records the child told us
678 XXX - do something if this fails? */
679 switch (cf_continue_tail(capture_opts->cf, to_read, &err)) {
683 /* Just because we got an error, that doesn't mean we were unable
684 to read any of the file; we handle what we could get from the
687 XXX - abort on a read error? */
690 case CF_READ_ABORTED:
691 /* Kill the child capture process; the user wants to exit, and we
692 shouldn't just leave it running. */
693 capture_kill_child(capture_opts);
701 /* the child process is going down, wait until it's completely terminated */
703 sync_pipe_wait_for_child(capture_options *capture_opts, gboolean always_report)
708 g_assert(capture_opts->fork_child != -1);
711 /* XXX - analyze the wait status and display more information
713 XXX - set "fork_child" to -1 if we find it exited? */
714 if (_cwait(&wstatus, capture_opts->fork_child, _WAIT_CHILD) == -1) {
715 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
716 "Child capture process stopped unexpectedly");
719 if (wait(&wstatus) != -1) {
720 if (WIFEXITED(wstatus)) {
721 /* The child exited; display its exit status, if it's not zero,
722 and even if it's zero if "always_report" is true. */
723 if (always_report || WEXITSTATUS(wstatus) != 0) {
724 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
725 "Child capture process exited: exit status %d",
726 WEXITSTATUS(wstatus));
728 } else if (WIFSTOPPED(wstatus)) {
729 /* It stopped, rather than exiting. "Should not happen." */
730 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
731 "Child capture process stopped: %s",
732 sync_pipe_signame(WSTOPSIG(wstatus)));
733 } else if (WIFSIGNALED(wstatus)) {
734 /* It died with a signal. */
735 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
736 "Child capture process died: %s%s",
737 sync_pipe_signame(WTERMSIG(wstatus)),
738 WCOREDUMP(wstatus) ? " - core dumped" : "");
740 /* What? It had to either have exited, or stopped, or died with
741 a signal; what happened here? */
742 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
743 "Child capture process died: wait status %#o", wstatus);
747 /* No more child process. */
748 capture_opts->fork_child = -1;
755 sync_pipe_signame(int sig)
758 static char sigmsg_buf[6+1+3+1];
767 sigmsg = "Interrupted";
775 sigmsg = "Illegal instruction";
779 sigmsg = "Trace trap";
787 sigmsg = "Arithmetic exception";
795 sigmsg = "Bus error";
799 sigmsg = "Segmentation violation";
802 /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
803 Linux is POSIX compliant. These are not POSIX-defined signals ---
804 ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
806 ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
807 were omitted from POSIX.1 because their behavior is
808 implementation dependent and could not be adequately catego-
809 rized. Conforming implementations may deliver these sig-
810 nals, but must document the circumstances under which they
811 are delivered and note any restrictions concerning their
814 So we only check for SIGSYS on those systems that happen to
815 implement them (a system can be POSIX-compliant and implement
816 them, it's just that POSIX doesn't *require* a POSIX-compliant
817 system to implement them).
822 sigmsg = "Bad system call";
827 sigmsg = "Broken pipe";
831 sigmsg = "Alarm clock";
835 sigmsg = "Terminated";
839 sprintf(sigmsg_buf, "Signal %d", sig);
849 sync_pipe_stop(capture_options *capture_opts)
851 /* XXX - in which cases this will be 0? */
852 if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
854 kill(capture_opts->fork_child, SIGUSR1);
856 /* XXX: this is not the preferred method of closing a process!
857 * the clean way would be getting the process id of the child process,
858 * then getting window handle hWnd of that process (using EnumChildWindows),
859 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
861 * Unfortunately, I don't know how to get the process id from the
862 * handle. OpenProcess will get an handle (not a window handle)
863 * from the process ID; it will not get a window handle from the
864 * process ID. (How could it? A process can have more than one
867 * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
868 * running in the same console; that's not necessarily the case for
869 * us, as we might not be running in a console.
870 * And this also will require to have the process id.
872 TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
879 sync_pipe_kill(capture_options *capture_opts)
881 /* XXX - in which cases this will be 0? */
882 if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
884 kill(capture_opts->fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */
886 /* XXX: this is not the preferred method of closing a process!
887 * the clean way would be getting the process id of the child process,
888 * then getting window handle hWnd of that process (using EnumChildWindows),
889 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
891 * Unfortunately, I don't know how to get the process id from the
892 * handle. OpenProcess will get an handle (not a window handle)
893 * from the process ID; it will not get a window handle from the
894 * process ID. (How could it? A process can have more than one
897 * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
898 * running in the same console; that's not necessarily the case for
899 * us, as we might not be running in a console.
900 * And this also will require to have the process id.
902 TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
907 #endif /* HAVE_LIBPCAP */