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