few changes to http
[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   /* we are a capture parent */
539   g_assert(!capture_opts->capture_child);
540
541   if ((nread = read(source, buffer, BUFSIZE)) <= 0) {
542     /* The child has closed the sync pipe, meaning it's not going to be
543        capturing any more packets.  Pick up its exit status, and
544        complain if it did anything other than exit with status 0. */
545     sync_pipe_wait_for_child(capture_opts, FALSE);
546
547     /* Read what remains of the capture file, and finish the capture.
548        XXX - do something if this fails? */
549     switch (cf_finish_tail(capture_opts->cf, &err)) {
550
551     case CF_READ_OK:
552         if(cf_packet_count(capture_opts->cf) == 0) {
553           simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, 
554           "%sNo packets captured!%s\n\n"
555           "As no data was captured, closing the %scapture file!",
556           simple_dialog_primary_start(), simple_dialog_primary_end(),
557           cf_is_tempfile(capture_opts->cf) ? "temporary " : "");
558           cf_close(capture_opts->cf);
559         }
560         break;
561     case CF_READ_ERROR:
562       /* Just because we got an error, that doesn't mean we were unable
563          to read any of the file; we handle what we could get from the
564          file. */
565       break;
566
567     case CF_READ_ABORTED:
568       /* Exit by leaving the main loop, so that any quit functions
569          we registered get called. */
570       main_window_quit();
571       return FALSE;
572     }
573
574     /* We're not doing a capture any more, so we don't have a save
575        file. */
576     g_free(capture_opts->save_file);
577     capture_opts->save_file = NULL;
578
579     return FALSE;
580   }
581
582   buffer[nread] = '\0';
583
584   while (nread != 0) {
585     /* look for (possibly multiple) indications */
586     switch (*q) {
587     case SP_PACKET_COUNT :
588       to_read += atoi(p);
589       p = q + 1;
590       q++;
591       nread--;
592       break;
593     case SP_DROPS :
594       cf_set_drops_known(capture_opts->cf, TRUE);
595       cf_set_drops(capture_opts->cf, atoi(p));
596       p = q + 1;
597       q++;
598       nread--;
599       break;
600     case SP_ERROR_MSG :
601       msglen = atoi(p);
602       p = q + 1;
603       q++;
604       nread--;
605
606       /* Read the entire message.
607          XXX - if the child hasn't sent it all yet, this could cause us
608          to hang until they do. */
609       msg = g_malloc(msglen + 1);
610       r = msg;
611       while (msglen != 0) {
612         if (nread == 0) {
613           /* Read more. */
614           if ((nread = read(source, buffer, BUFSIZE)) <= 0)
615             break;
616           p = buffer;
617           q = buffer;
618         }
619         chars_to_copy = MIN(msglen, nread);
620         memcpy(r, q, chars_to_copy);
621         r += chars_to_copy;
622         q += chars_to_copy;
623         nread -= chars_to_copy;
624         msglen -= chars_to_copy;
625       }
626       *r = '\0';
627       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
628       g_free(msg);
629       break;
630     case SP_FILE :
631       msglen = atoi(p);
632       p = q + 1;
633       q++;
634       nread--;
635
636       /* Read the entire message.
637          XXX - if the child hasn't sent it all yet, this could cause us
638          to hang until they do. */
639       msg = g_malloc(msglen + 1);
640       r = msg;
641       while (msglen != 0) {
642         if (nread == 0) {
643           /* Read more. */
644           if ((nread = read(source, buffer, BUFSIZE)) <= 0)
645             break;
646           p = buffer;
647           q = buffer;
648         }
649         chars_to_copy = MIN(msglen, nread);
650         memcpy(r, q, chars_to_copy);
651         r += chars_to_copy;
652         q += chars_to_copy;
653         nread -= chars_to_copy;
654         msglen -= chars_to_copy;
655       }
656       *r = '\0';
657
658       /* currently, both filenames must be equal */
659       /* (this will change, when multiple files together with sync_mode are captured) */
660       g_assert(strcmp(capture_opts->save_file, msg) == 0);
661
662       /* save the new filename */
663       if(capture_opts->save_file != NULL) {
664         g_free(capture_opts->save_file);
665       }
666       capture_opts->save_file = g_strdup(msg);
667       g_free(msg);
668       break;
669     default :
670       q++;
671       nread--;
672       break;
673     }
674   }
675
676   /* Read from the capture file the number of records the child told us
677      it added.
678      XXX - do something if this fails? */
679   switch (cf_continue_tail(capture_opts->cf, to_read, &err)) {
680
681   case CF_READ_OK:
682   case CF_READ_ERROR:
683     /* Just because we got an error, that doesn't mean we were unable
684        to read any of the file; we handle what we could get from the
685        file.
686
687        XXX - abort on a read error? */
688     break;
689
690   case CF_READ_ABORTED:
691     /* Kill the child capture process; the user wants to exit, and we
692        shouldn't just leave it running. */
693     capture_kill_child(capture_opts);
694     break;
695   }
696
697   return TRUE;
698 }
699
700
701 /* the child process is going down, wait until it's completely terminated */
702 static void
703 sync_pipe_wait_for_child(capture_options *capture_opts, gboolean always_report)
704 {
705   int  wstatus;
706
707
708   g_assert(capture_opts->fork_child != -1);
709
710 #ifdef _WIN32
711   /* XXX - analyze the wait status and display more information
712      in the dialog box?
713      XXX - set "fork_child" to -1 if we find it exited? */
714   if (_cwait(&wstatus, capture_opts->fork_child, _WAIT_CHILD) == -1) {
715     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
716                 "Child capture process stopped unexpectedly");
717   }
718 #else
719   if (wait(&wstatus) != -1) {
720     if (WIFEXITED(wstatus)) {
721       /* The child exited; display its exit status, if it's not zero,
722          and even if it's zero if "always_report" is true. */
723       if (always_report || WEXITSTATUS(wstatus) != 0) {
724         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
725                       "Child capture process exited: exit status %d",
726                       WEXITSTATUS(wstatus));
727       }
728     } else if (WIFSTOPPED(wstatus)) {
729       /* It stopped, rather than exiting.  "Should not happen." */
730       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
731                     "Child capture process stopped: %s",
732                     sync_pipe_signame(WSTOPSIG(wstatus)));
733     } else if (WIFSIGNALED(wstatus)) {
734       /* It died with a signal. */
735       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
736                     "Child capture process died: %s%s",
737                     sync_pipe_signame(WTERMSIG(wstatus)),
738                     WCOREDUMP(wstatus) ? " - core dumped" : "");
739     } else {
740       /* What?  It had to either have exited, or stopped, or died with
741          a signal; what happened here? */
742       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
743                     "Child capture process died: wait status %#o", wstatus);
744     }
745   }
746
747   /* No more child process. */
748   capture_opts->fork_child = -1;
749 #endif
750 }
751
752
753 #ifndef _WIN32
754 static char *
755 sync_pipe_signame(int sig)
756 {
757   char *sigmsg;
758   static char sigmsg_buf[6+1+3+1];
759
760   switch (sig) {
761
762   case SIGHUP:
763     sigmsg = "Hangup";
764     break;
765
766   case SIGINT:
767     sigmsg = "Interrupted";
768     break;
769
770   case SIGQUIT:
771     sigmsg = "Quit";
772     break;
773
774   case SIGILL:
775     sigmsg = "Illegal instruction";
776     break;
777
778   case SIGTRAP:
779     sigmsg = "Trace trap";
780     break;
781
782   case SIGABRT:
783     sigmsg = "Abort";
784     break;
785
786   case SIGFPE:
787     sigmsg = "Arithmetic exception";
788     break;
789
790   case SIGKILL:
791     sigmsg = "Killed";
792     break;
793
794   case SIGBUS:
795     sigmsg = "Bus error";
796     break;
797
798   case SIGSEGV:
799     sigmsg = "Segmentation violation";
800     break;
801
802   /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
803      Linux is POSIX compliant.  These are not POSIX-defined signals ---
804      ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
805
806         ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
807         were omitted from POSIX.1 because their behavior is
808         implementation dependent and could not be adequately catego-
809         rized.  Conforming implementations may deliver these sig-
810         nals, but must document the circumstances under which they
811         are delivered and note any restrictions concerning their
812         delivery.''
813
814      So we only check for SIGSYS on those systems that happen to
815      implement them (a system can be POSIX-compliant and implement
816      them, it's just that POSIX doesn't *require* a POSIX-compliant
817      system to implement them).
818    */
819
820 #ifdef SIGSYS
821   case SIGSYS:
822     sigmsg = "Bad system call";
823     break;
824 #endif
825
826   case SIGPIPE:
827     sigmsg = "Broken pipe";
828     break;
829
830   case SIGALRM:
831     sigmsg = "Alarm clock";
832     break;
833
834   case SIGTERM:
835     sigmsg = "Terminated";
836     break;
837
838   default:
839     sprintf(sigmsg_buf, "Signal %d", sig);
840     sigmsg = sigmsg_buf;
841     break;
842   }
843   return sigmsg;
844 }
845 #endif
846
847
848 void
849 sync_pipe_stop(capture_options *capture_opts)
850 {
851   /* XXX - in which cases this will be 0? */
852   if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
853 #ifndef _WIN32
854       kill(capture_opts->fork_child, SIGUSR1);
855 #else
856       /* XXX: this is not the preferred method of closing a process!
857        * the clean way would be getting the process id of the child process,
858        * then getting window handle hWnd of that process (using EnumChildWindows),
859        * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0) 
860        *
861        * Unfortunately, I don't know how to get the process id from the
862        * handle.  OpenProcess will get an handle (not a window handle)
863        * from the process ID; it will not get a window handle from the
864        * process ID.  (How could it?  A process can have more than one
865        * window.)
866        *
867        * Hint: GenerateConsoleCtrlEvent() will only work if both processes are 
868        * running in the same console; that's not necessarily the case for
869        * us, as we might not be running in a console.
870        * And this also will require to have the process id.
871        */
872       TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
873 #endif
874   }
875 }
876
877
878 void
879 sync_pipe_kill(capture_options *capture_opts)
880 {
881   /* XXX - in which cases this will be 0? */
882   if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
883 #ifndef _WIN32
884       kill(capture_opts->fork_child, SIGTERM);  /* SIGTERM so it can clean up if necessary */
885 #else
886       /* XXX: this is not the preferred method of closing a process!
887        * the clean way would be getting the process id of the child process,
888        * then getting window handle hWnd of that process (using EnumChildWindows),
889        * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0) 
890        *
891        * Unfortunately, I don't know how to get the process id from the
892        * handle.  OpenProcess will get an handle (not a window handle)
893        * from the process ID; it will not get a window handle from the
894        * process ID.  (How could it?  A process can have more than one
895        * window.)
896        *
897        * Hint: GenerateConsoleCtrlEvent() will only work if both processes are 
898        * running in the same console; that's not necessarily the case for
899        * us, as we might not be running in a console.
900        * And this also will require to have the process id.
901        */
902       TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
903 #endif
904   }
905 }
906
907 #endif /* HAVE_LIBPCAP */