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