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