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