refactoring of the capture startup (while the capture parent waits for the child...
[obnox/wireshark/wip.git] / capture_sync.c
1 /* capture_sync.c
2  * Synchronisation between Ethereal capture parent and child instances
3  *
4  * $Id$
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 #include <pcap.h>
32
33 #include <glib.h>
34 #include <stdio.h>
35 #include <ctype.h>
36 #include <string.h>
37
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41
42 #include <signal.h>
43
44 #ifdef HAVE_SYS_WAIT_H
45 # include <sys/wait.h>
46 #endif
47
48 #ifndef _WIN32
49 /*
50  * Define various POSIX macros (and, in the case of WCOREDUMP, non-POSIX
51  * macros) on UNIX systems that don't have them.
52  */
53 #ifndef WIFEXITED
54 # define WIFEXITED(status)      (((status) & 0177) == 0)
55 #endif
56 #ifndef WIFSTOPPED
57 # define WIFSTOPPED(status)     (((status) & 0177) == 0177)
58 #endif
59 #ifndef WIFSIGNALED
60 # define WIFSIGNALED(status)    (!WIFSTOPPED(status) && !WIFEXITED(status))
61 #endif
62 #ifndef WEXITSTATUS
63 # define WEXITSTATUS(status)    ((status) >> 8)
64 #endif
65 #ifndef WTERMSIG
66 # define WTERMSIG(status)       ((status) & 0177)
67 #endif
68 #ifndef WCOREDUMP
69 # define WCOREDUMP(status)      ((status) & 0200)
70 #endif
71 #ifndef WSTOPSIG
72 # define WSTOPSIG(status)       ((status) >> 8)
73 #endif
74 #endif /* _WIN32 */
75
76 #include <epan/packet.h>
77 #include <epan/prefs.h>
78
79 #include "globals.h"
80 #include "file.h"
81
82 #include "capture.h"
83 #include "capture_sync.h"
84 #include "simple_dialog.h"
85
86 #ifdef _WIN32
87 #include "capture-wpcap.h"
88 #endif
89 #include "ui_util.h"
90
91 #ifdef HAVE_IO_H
92 # include <io.h>
93 #endif
94
95 #ifdef _WIN32
96 #include <process.h>    /* For spawning child process */
97 #endif
98
99 /* Win32 needs the O_BINARY flag for open() */
100 #ifndef O_BINARY
101 #define O_BINARY        0
102 #endif
103
104
105 #ifndef _WIN32
106 static char *sync_pipe_signame(int);
107 #endif
108
109
110 static gboolean sync_pipe_input_wait_for_start(capture_options *capture_opts, int sync_pipe_read);
111 static gboolean sync_pipe_input_cb(gint source, gpointer user_data);
112 static void sync_pipe_wait_for_child(capture_options *capture_opts, gboolean always_report);
113
114 /* Size of buffer to hold decimal representation of
115    signed/unsigned 64-bit int */
116 #define SP_DECISIZE 20
117
118 /*
119  * Indications sent out on the sync pipe.
120  */
121 #define SP_CAPSTART     ';'     /* capture start message */
122 #define SP_PACKET_COUNT '*'     /* followed by count of packets captured since last message */
123 #define SP_ERROR_MSG    '!'     /* followed by length of error message that follows */
124 #define SP_DROPS        '#'     /* followed by count of packets dropped in capture */
125 #define SP_FILE         ':'     /* followed by length of the name of the last opened file that follows */
126
127
128
129 void
130 sync_pipe_capstart_to_parent(void)
131 {
132     static const char capstart_msg = SP_CAPSTART;
133
134     write(1, &capstart_msg, 1);
135 }
136
137 void
138 sync_pipe_packet_count_to_parent(int packet_count)
139 {
140     char tmp[SP_DECISIZE+1+1];
141     sprintf(tmp, "%d%c", packet_count, SP_PACKET_COUNT);
142     write(1, tmp, strlen(tmp));
143 }
144
145 void
146 sync_pipe_filename_to_parent(const char *filename)
147 {
148     int msglen = strlen(filename);
149     char lenbuf[SP_DECISIZE+1+1];
150
151     sprintf(lenbuf, "%u%c", msglen, SP_FILE);
152     write(1, lenbuf, strlen(lenbuf));
153     write(1, filename, msglen);
154 }
155
156 void
157 sync_pipe_errmsg_to_parent(const char *errmsg)
158 {
159     int msglen = strlen(errmsg);
160     char lenbuf[SP_DECISIZE+1+1];
161
162     sprintf(lenbuf, "%u%c", msglen, SP_ERROR_MSG);
163     write(1, lenbuf, strlen(lenbuf));
164     write(1, errmsg, msglen);
165 }
166
167 void
168 sync_pipe_drops_to_parent(int drops)
169 {
170         char tmp[SP_DECISIZE+1+1];
171         sprintf(tmp, "%d%c", drops, SP_DROPS);
172         write(1, tmp, strlen(tmp));
173 }
174
175
176 /* Add a string pointer to a NULL-terminated array of string pointers. */
177 static char **
178 sync_pipe_add_arg(char **args, int *argc, char *arg)
179 {
180   /* Grow the array; "*argc" currently contains the number of string
181      pointers, *not* counting the NULL pointer at the end, so we have
182      to add 2 in order to get the new size of the array, including the
183      new pointer and the terminating NULL pointer. */
184   args = g_realloc(args, (*argc + 2) * sizeof (char *));
185
186   /* Stuff the pointer into the penultimate element of the array, which
187      is the one at the index specified by "*argc". */
188   args[*argc] = arg;
189
190   /* Now bump the count. */
191   (*argc)++;
192
193   /* We overwrite the NULL pointer; put it back right after the
194      element we added. */
195   args[*argc] = NULL;
196
197   return args;
198 }
199
200 #ifdef _WIN32
201 /* Given a string, return a pointer to a quote-encapsulated version of
202    the string, so we can pass it as an argument with "spawnvp" even
203    if it contains blanks. */
204 char *
205 sync_pipe_quote_encapsulate(const char *string)
206 {
207   char *encapsulated_string;
208
209   encapsulated_string = g_new(char, strlen(string) + 3);
210   sprintf(encapsulated_string, "\"%s\"", string);
211   return encapsulated_string;
212 }
213 #endif
214
215
216
217 #define ARGV_NUMBER_LEN 24
218
219 gboolean
220 sync_pipe_do_capture(capture_options *capture_opts, gboolean is_tempfile) {
221     char ssnap[ARGV_NUMBER_LEN];
222     char scount[ARGV_NUMBER_LEN];
223     char sfilesize[ARGV_NUMBER_LEN];
224     char sfile_duration[ARGV_NUMBER_LEN];
225     char sring_num_files[ARGV_NUMBER_LEN];
226     char sautostop_files[ARGV_NUMBER_LEN];
227     char sautostop_filesize[ARGV_NUMBER_LEN];
228     char sautostop_duration[ARGV_NUMBER_LEN];
229 #ifdef _WIN32
230     char sync_pipe_fd[ARGV_NUMBER_LEN];
231     char *fontstring;
232     char *filterstring;
233 #else
234     char errmsg[1024+1];
235 #endif
236     int argc;
237     char **argv;
238     enum PIPES { PIPE_READ, PIPE_WRITE };   /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
239     int sync_pipe[2];                       /* pipes used to sync between instances */
240
241
242     /*g_warning("sync_pipe_do_capture");
243     capture_opts_info(capture_opts);*/
244
245     capture_opts->fork_child = -1;
246
247     /* Allocate the string pointer array with enough space for the
248        terminating NULL pointer. */
249     argc = 0;
250     argv = g_malloc(sizeof (char *));
251     *argv = NULL;
252
253     /* Now add those arguments used on all platforms. */
254     argv = sync_pipe_add_arg(argv, &argc, CHILD_NAME);
255
256     argv = sync_pipe_add_arg(argv, &argc, "-i");
257     argv = sync_pipe_add_arg(argv, &argc, capture_opts->iface);
258
259     if(capture_opts->save_file) {
260       argv = sync_pipe_add_arg(argv, &argc, "-w");
261       argv = sync_pipe_add_arg(argv, &argc, capture_opts->save_file);
262     }
263
264     if (capture_opts->has_snaplen) {
265       argv = sync_pipe_add_arg(argv, &argc, "-s");
266       sprintf(ssnap,"%d",capture_opts->snaplen);
267       argv = sync_pipe_add_arg(argv, &argc, ssnap);
268     }
269
270     if (capture_opts->linktype != -1) {
271       argv = sync_pipe_add_arg(argv, &argc, "-y");
272 #ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME
273       sprintf(ssnap,"%s",pcap_datalink_val_to_name(capture_opts->linktype));
274 #else
275       /* XXX - just treat it as a number */
276       sprintf(ssnap,"%d",capture_opts->linktype);
277 #endif
278       argv = sync_pipe_add_arg(argv, &argc, ssnap);
279     }
280
281     if(capture_opts->multi_files_on) {
282       if (capture_opts->has_autostop_filesize) {
283         argv = sync_pipe_add_arg(argv, &argc, "-b");
284         sprintf(sfilesize,"filesize:%d",capture_opts->autostop_filesize);
285         argv = sync_pipe_add_arg(argv, &argc, sfilesize);
286       }
287
288       if (capture_opts->has_file_duration) {
289         argv = sync_pipe_add_arg(argv, &argc, "-b");
290         sprintf(sfile_duration,"duration:%d",capture_opts->file_duration);
291         argv = sync_pipe_add_arg(argv, &argc, sfile_duration);
292       }
293
294       if (capture_opts->has_ring_num_files) {
295         argv = sync_pipe_add_arg(argv, &argc, "-b");
296         sprintf(sring_num_files,"files:%d",capture_opts->ring_num_files);
297         argv = sync_pipe_add_arg(argv, &argc, sring_num_files);
298       }
299
300       if (capture_opts->has_autostop_files) {
301         argv = sync_pipe_add_arg(argv, &argc, "-a");
302         sprintf(sautostop_files,"files:%d",capture_opts->autostop_files);
303         argv = sync_pipe_add_arg(argv, &argc, sautostop_files);
304       }
305     } else {
306         if (capture_opts->has_autostop_filesize) {
307           argv = sync_pipe_add_arg(argv, &argc, "-a");
308           sprintf(sautostop_filesize,"filesize:%d",capture_opts->autostop_filesize);
309           argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
310         }
311     }
312
313     if (capture_opts->has_autostop_packets) {
314       argv = sync_pipe_add_arg(argv, &argc, "-c");
315       sprintf(scount,"%d",capture_opts->autostop_packets);
316       argv = sync_pipe_add_arg(argv, &argc, scount);
317     }
318
319     if (capture_opts->has_autostop_duration) {
320       argv = sync_pipe_add_arg(argv, &argc, "-a");
321       sprintf(sautostop_duration,"duration:%d",capture_opts->autostop_duration);
322       argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
323     }
324
325     if (!capture_opts->show_info) {
326       argv = sync_pipe_add_arg(argv, &argc, "-H");
327     }
328
329     if (!capture_opts->promisc_mode)
330       argv = sync_pipe_add_arg(argv, &argc, "-p");
331
332 #ifdef _WIN32
333     /* Create a pipe for the child process */
334     if(_pipe(sync_pipe, 512, O_BINARY) < 0) {
335       /* Couldn't create the pipe between parent and child. */
336       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
337                         strerror(errno));
338       return FALSE;
339     }
340
341     /* Convert font name to a quote-encapsulated string and pass to child */
342     argv = sync_pipe_add_arg(argv, &argc, "-m");
343     fontstring = sync_pipe_quote_encapsulate(prefs.PREFS_GUI_FONT_NAME);
344     argv = sync_pipe_add_arg(argv, &argc, fontstring);
345
346     /* Convert pipe write handle to a string and pass to child */
347     argv = sync_pipe_add_arg(argv, &argc, "-Z");
348     itoa(sync_pipe[PIPE_WRITE], sync_pipe_fd, 10);
349     argv = sync_pipe_add_arg(argv, &argc, sync_pipe_fd);
350
351     /* Convert filter string to a quote delimited string and pass to child */
352     filterstring = NULL;
353     if (capture_opts->cfilter != NULL && strlen(capture_opts->cfilter) != 0) {
354       argv = sync_pipe_add_arg(argv, &argc, "-f");
355       filterstring = sync_pipe_quote_encapsulate(capture_opts->cfilter);
356       argv = sync_pipe_add_arg(argv, &argc, filterstring);
357     }
358
359     /* Spawn process */
360     capture_opts->fork_child = spawnvp(_P_NOWAIT, ethereal_path, argv);
361     g_free(fontstring);
362     if (filterstring) {
363       g_free(filterstring);
364     }
365 #else
366     if (pipe(sync_pipe) < 0) {
367       /* Couldn't create the pipe between parent and child. */
368       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
369                         strerror(errno));
370       return FALSE;
371     }
372
373     argv = sync_pipe_add_arg(argv, &argc, "-m");
374     argv = sync_pipe_add_arg(argv, &argc, prefs.PREFS_GUI_FONT_NAME);
375
376     if (capture_opts->cfilter != NULL && capture_opts->cfilter != 0) {
377       argv = sync_pipe_add_arg(argv, &argc, "-f");
378       argv = sync_pipe_add_arg(argv, &argc, capture_opts->cfilter);
379     }
380
381     if ((capture_opts->fork_child = fork()) == 0) {
382       /*
383        * Child process - run Ethereal with the right arguments to make
384        * it just pop up the live capture dialog box and capture with
385        * the specified capture parameters, writing to the specified file.
386        *
387        * args: -i interface specification
388        * -w file to write
389        * -W file descriptor to write
390        * -c count to capture
391        * -s snaplen
392        * -m / -b fonts
393        * -f "filter expression"
394        */
395       close(1);
396       dup(sync_pipe[PIPE_WRITE]);
397       close(sync_pipe[PIPE_READ]);
398       execvp(ethereal_path, argv);
399       snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
400                 ethereal_path, strerror(errno));
401       sync_pipe_errmsg_to_parent(errmsg);
402
403       /* Exit with "_exit()", so that we don't close the connection
404          to the X server (and cause stuff buffered up by our parent but
405          not yet sent to be sent, as that stuff should only be sent by
406          our parent). */
407       _exit(2);
408     }
409 #endif
410
411     /* Parent process - read messages from the child process over the
412        sync pipe. */
413     g_free(argv);       /* free up arg array */
414
415     /* Close the write side of the pipe, so that only the child has it
416        open, and thus it completely closes, and thus returns to us
417        an EOF indication, if the child closes it (either deliberately
418        or by exiting abnormally). */
419     close(sync_pipe[PIPE_WRITE]);
420
421     if (capture_opts->fork_child == -1) {
422       /* We couldn't even create the child process. */
423       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
424                         "Couldn't create child process: %s", strerror(errno));
425       close(sync_pipe[PIPE_READ]);
426       return FALSE;
427     }
428
429     /* the child have to send us a capture start or error message now */
430     if(!sync_pipe_input_wait_for_start(capture_opts, sync_pipe[PIPE_READ])) {
431             /* Close the sync pipe. */
432             close(sync_pipe[PIPE_READ]);
433         return FALSE;
434     }
435
436     /* We were able to set up to read the capture file;
437        arrange that our callback be called whenever it's possible
438        to read from the sync pipe, so that it's called when
439        the child process wants to tell us something. */
440
441     /* we have a running capture, now wait for the real capture filename */
442     pipe_input_set_handler(sync_pipe[PIPE_READ], (gpointer) capture_opts, 
443         &capture_opts->fork_child, sync_pipe_input_cb);
444
445     return TRUE;
446 }
447
448
449 /* capture prepared, waiting for the child to signal us capture has indeed started */
450 static gboolean
451 sync_pipe_input_wait_for_start(capture_options *capture_opts, int sync_pipe_read) {
452     guint   byte_count;
453     int     i;
454     guchar  c;
455     char    *msg;
456
457
458     /* Read a byte count from "sync_pipe_read", terminated with a
459        colon; if the count is 0, the child process created the
460        capture file and we should start reading from it, otherwise
461        the capture couldn't start and the count is a count of bytes
462        of error message, and we should display the message. */
463     byte_count = 0;
464     for (;;) {
465         i = read(sync_pipe_read, &c, 1);
466         if (i == 0) {
467             /* EOF - the child process died, report the failure. */
468             sync_pipe_wait_for_child(capture_opts, TRUE);
469             return FALSE;
470         }
471
472         /* the first message should be the capture start or an error message */
473         if (c == SP_CAPSTART || c == SP_ERROR_MSG) {
474             return TRUE;
475         }
476
477         if (!isdigit(c)) {
478             /* Child process handed us crap, report the failure. */
479             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
480             "Capture child process sent us a bad message");
481             return FALSE;
482         }
483
484         byte_count = byte_count*10 + c - '0';
485
486         if (c != SP_CAPSTART) {
487         /* Failure - the child process sent us a message indicating
488         what the problem was. */
489         if (byte_count == 0) {
490             /* Zero-length message? */
491             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
492                 "Capture child process failed, but its error message was empty.");
493             return FALSE;
494         }
495
496         msg = g_malloc(byte_count + 1);
497         if (msg == NULL) {
498             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
499                 "Capture child process failed, but its error message was too big.");
500             return FALSE;
501         }
502
503         i = read(sync_pipe_read, msg, byte_count);
504         msg[byte_count] = '\0';
505         if (i < 0) {
506             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
507                 "Capture child process failed: Error %s reading its error message.",
508             strerror(errno));
509             g_free(msg);
510             return FALSE;
511         }
512         
513         if (i == 0) {
514             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
515             "Capture child process failed: EOF reading its error message.");
516             sync_pipe_wait_for_child(capture_opts, FALSE);
517             g_free(msg);
518             return FALSE;
519         }
520
521         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
522         g_free(msg);
523         return FALSE;
524         }
525     }
526
527     g_assert_not_reached();
528     return TRUE;
529 }
530
531
532 /* There's stuff to read from the sync pipe, meaning the child has sent
533    us a message, or the sync pipe has closed, meaning the child has
534    closed it (perhaps because it exited). */
535 static gboolean 
536 sync_pipe_input_cb(gint source, gpointer user_data)
537 {
538   capture_options *capture_opts = (capture_options *)user_data;
539 #define BUFSIZE 4096
540   char buffer[BUFSIZE+1], *p = buffer, *q = buffer, *msg, *r;
541   int  nread, msglen, chars_to_copy;
542   int  to_read = 0;
543
544
545   if ((nread = read(source, buffer, BUFSIZE)) <= 0) {
546     /* The child has closed the sync pipe, meaning it's not going to be
547        capturing any more packets.  Pick up its exit status, and
548        complain if it did anything other than exit with status 0. */
549     sync_pipe_wait_for_child(capture_opts, FALSE);
550     capture_input_closed(capture_opts);
551     return FALSE;
552   }
553
554   buffer[nread] = '\0';
555
556   while (nread != 0) {
557     /* look for (possibly multiple) indications */
558     switch (*q) {
559     case SP_PACKET_COUNT :
560       to_read += atoi(p);
561       p = q + 1;
562       q++;
563       nread--;
564       break;
565     case SP_DROPS :
566       cf_set_drops_known(capture_opts->cf, TRUE);
567       cf_set_drops(capture_opts->cf, atoi(p));
568       p = q + 1;
569       q++;
570       nread--;
571       break;
572     case SP_ERROR_MSG :
573       msglen = atoi(p);
574       p = q + 1;
575       q++;
576       nread--;
577
578       /* Read the entire message.
579          XXX - if the child hasn't sent it all yet, this could cause us
580          to hang until they do. */
581       msg = g_malloc(msglen + 1);
582       r = msg;
583       while (msglen != 0) {
584         if (nread == 0) {
585           /* Read more. */
586           if ((nread = read(source, buffer, BUFSIZE)) <= 0)
587             break;
588           p = buffer;
589           q = buffer;
590         }
591         chars_to_copy = MIN(msglen, nread);
592         memcpy(r, q, chars_to_copy);
593         r += chars_to_copy;
594         q += chars_to_copy;
595         nread -= chars_to_copy;
596         msglen -= chars_to_copy;
597       }
598       *r = '\0';
599       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
600       g_free(msg);
601       break;
602     case SP_FILE :
603       msglen = atoi(p);
604       p = q + 1;
605       q++;
606       nread--;
607
608       /* Read the entire file name.
609          XXX - if the child hasn't sent it all yet, this could cause us
610          to hang until they do. */
611       msg = g_malloc(msglen + 1);
612       r = msg;
613       while (msglen != 0) {
614         if (nread == 0) {
615           /* Read more. */
616           if ((nread = read(source, buffer, BUFSIZE)) <= 0)
617             break;
618           p = buffer;
619           q = buffer;
620         }
621         chars_to_copy = MIN(msglen, nread);
622         memcpy(r, q, chars_to_copy);
623         r += chars_to_copy;
624         q += chars_to_copy;
625         nread -= chars_to_copy;
626         msglen -= chars_to_copy;
627       }
628       *r = '\0';
629
630       if(!capture_input_new_file(capture_opts, msg)) {
631          /* We weren't able to open the new capture file; user has been
632             alerted. Close the sync pipe. */
633 /*            close(sync_pipe[PIPE_READ]);*/
634
635             /* XXX - how to kill things here ? */
636             /* XXX - is it safe to close the pipe inside this callback? */
637             close(source);
638       }
639
640       g_free(msg);
641
642       break;
643     default :
644       q++;
645       nread--;
646       break;
647     }
648   }
649
650   capture_input_new_packets(capture_opts, to_read);
651
652   return TRUE;
653 }
654
655
656 /* the child process is going down, wait until it's completely terminated */
657 static void
658 sync_pipe_wait_for_child(capture_options *capture_opts, gboolean always_report)
659 {
660   int  wstatus;
661
662
663   g_assert(capture_opts->fork_child != -1);
664
665 #ifdef _WIN32
666   /* XXX - analyze the wait status and display more information
667      in the dialog box?
668      XXX - set "fork_child" to -1 if we find it exited? */
669   if (_cwait(&wstatus, capture_opts->fork_child, _WAIT_CHILD) == -1) {
670     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
671                 "Child capture process stopped unexpectedly");
672   }
673 #else
674   if (wait(&wstatus) != -1) {
675     if (WIFEXITED(wstatus)) {
676       /* The child exited; display its exit status, if it's not zero,
677          and even if it's zero if "always_report" is true. */
678       if (always_report || WEXITSTATUS(wstatus) != 0) {
679         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
680                       "Child capture process exited: exit status %d",
681                       WEXITSTATUS(wstatus));
682       }
683     } else if (WIFSTOPPED(wstatus)) {
684       /* It stopped, rather than exiting.  "Should not happen." */
685       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
686                     "Child capture process stopped: %s",
687                     sync_pipe_signame(WSTOPSIG(wstatus)));
688     } else if (WIFSIGNALED(wstatus)) {
689       /* It died with a signal. */
690       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
691                     "Child capture process died: %s%s",
692                     sync_pipe_signame(WTERMSIG(wstatus)),
693                     WCOREDUMP(wstatus) ? " - core dumped" : "");
694     } else {
695       /* What?  It had to either have exited, or stopped, or died with
696          a signal; what happened here? */
697       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
698                     "Child capture process died: wait status %#o", wstatus);
699     }
700   }
701
702   /* No more child process. */
703   capture_opts->fork_child = -1;
704 #endif
705 }
706
707
708 #ifndef _WIN32
709 static char *
710 sync_pipe_signame(int sig)
711 {
712   char *sigmsg;
713   static char sigmsg_buf[6+1+3+1];
714
715   switch (sig) {
716
717   case SIGHUP:
718     sigmsg = "Hangup";
719     break;
720
721   case SIGINT:
722     sigmsg = "Interrupted";
723     break;
724
725   case SIGQUIT:
726     sigmsg = "Quit";
727     break;
728
729   case SIGILL:
730     sigmsg = "Illegal instruction";
731     break;
732
733   case SIGTRAP:
734     sigmsg = "Trace trap";
735     break;
736
737   case SIGABRT:
738     sigmsg = "Abort";
739     break;
740
741   case SIGFPE:
742     sigmsg = "Arithmetic exception";
743     break;
744
745   case SIGKILL:
746     sigmsg = "Killed";
747     break;
748
749   case SIGBUS:
750     sigmsg = "Bus error";
751     break;
752
753   case SIGSEGV:
754     sigmsg = "Segmentation violation";
755     break;
756
757   /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
758      Linux is POSIX compliant.  These are not POSIX-defined signals ---
759      ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
760
761         ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
762         were omitted from POSIX.1 because their behavior is
763         implementation dependent and could not be adequately catego-
764         rized.  Conforming implementations may deliver these sig-
765         nals, but must document the circumstances under which they
766         are delivered and note any restrictions concerning their
767         delivery.''
768
769      So we only check for SIGSYS on those systems that happen to
770      implement them (a system can be POSIX-compliant and implement
771      them, it's just that POSIX doesn't *require* a POSIX-compliant
772      system to implement them).
773    */
774
775 #ifdef SIGSYS
776   case SIGSYS:
777     sigmsg = "Bad system call";
778     break;
779 #endif
780
781   case SIGPIPE:
782     sigmsg = "Broken pipe";
783     break;
784
785   case SIGALRM:
786     sigmsg = "Alarm clock";
787     break;
788
789   case SIGTERM:
790     sigmsg = "Terminated";
791     break;
792
793   default:
794     sprintf(sigmsg_buf, "Signal %d", sig);
795     sigmsg = sigmsg_buf;
796     break;
797   }
798   return sigmsg;
799 }
800 #endif
801
802
803 void
804 sync_pipe_stop(capture_options *capture_opts)
805 {
806   /* XXX - in which cases this will be 0? */
807   if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
808 #ifndef _WIN32
809       kill(capture_opts->fork_child, SIGUSR1);
810 #else
811       /* XXX: this is not the preferred method of closing a process!
812        * the clean way would be getting the process id of the child process,
813        * then getting window handle hWnd of that process (using EnumChildWindows),
814        * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0) 
815        *
816        * Unfortunately, I don't know how to get the process id from the
817        * handle.  OpenProcess will get an handle (not a window handle)
818        * from the process ID; it will not get a window handle from the
819        * process ID.  (How could it?  A process can have more than one
820        * window.)
821        *
822        * Hint: GenerateConsoleCtrlEvent() will only work if both processes are 
823        * running in the same console; that's not necessarily the case for
824        * us, as we might not be running in a console.
825        * And this also will require to have the process id.
826        */
827       TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
828 #endif
829   }
830 }
831
832
833 void
834 sync_pipe_kill(capture_options *capture_opts)
835 {
836   /* XXX - in which cases this will be 0? */
837   if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
838 #ifndef _WIN32
839       kill(capture_opts->fork_child, SIGTERM);  /* SIGTERM so it can clean up if necessary */
840 #else
841       /* XXX: this is not the preferred method of closing a process!
842        * the clean way would be getting the process id of the child process,
843        * then getting window handle hWnd of that process (using EnumChildWindows),
844        * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0) 
845        *
846        * Unfortunately, I don't know how to get the process id from the
847        * handle.  OpenProcess will get an handle (not a window handle)
848        * from the process ID; it will not get a window handle from the
849        * process ID.  (How could it?  A process can have more than one
850        * window.)
851        *
852        * Hint: GenerateConsoleCtrlEvent() will only work if both processes are 
853        * running in the same console; that's not necessarily the case for
854        * us, as we might not be running in a console.
855        * And this also will require to have the process id.
856        */
857       TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
858 #endif
859   }
860 }
861
862 #endif /* HAVE_LIBPCAP */