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