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