2004-10-30 11:44:06 +00:00
|
|
|
/* capture_sync.c
|
|
|
|
* Synchronisation between Ethereal capture parent and child instances
|
|
|
|
*
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* Ethereal - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@ethereal.com>
|
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBPCAP
|
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
#include <stdio.h>
|
2004-10-30 23:26:47 +00:00
|
|
|
#include <ctype.h>
|
2004-10-30 11:44:06 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
2004-10-30 23:26:47 +00:00
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
2006-02-17 02:18:48 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
#include <fcntl.h>
|
|
|
|
#endif
|
|
|
|
|
2004-10-30 23:26:47 +00:00
|
|
|
#ifdef HAVE_SYS_WAIT_H
|
|
|
|
# include <sys/wait.h>
|
|
|
|
#endif
|
|
|
|
|
2006-02-17 02:18:48 +00:00
|
|
|
#include "capture-pcap-util.h"
|
|
|
|
|
2004-10-30 23:26:47 +00:00
|
|
|
#ifndef _WIN32
|
|
|
|
/*
|
|
|
|
* Define various POSIX macros (and, in the case of WCOREDUMP, non-POSIX
|
|
|
|
* macros) on UNIX systems that don't have them.
|
|
|
|
*/
|
|
|
|
#ifndef WIFEXITED
|
|
|
|
# define WIFEXITED(status) (((status) & 0177) == 0)
|
|
|
|
#endif
|
|
|
|
#ifndef WIFSTOPPED
|
|
|
|
# define WIFSTOPPED(status) (((status) & 0177) == 0177)
|
|
|
|
#endif
|
|
|
|
#ifndef WIFSIGNALED
|
|
|
|
# define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status))
|
|
|
|
#endif
|
|
|
|
#ifndef WEXITSTATUS
|
|
|
|
# define WEXITSTATUS(status) ((status) >> 8)
|
|
|
|
#endif
|
|
|
|
#ifndef WTERMSIG
|
|
|
|
# define WTERMSIG(status) ((status) & 0177)
|
|
|
|
#endif
|
|
|
|
#ifndef WCOREDUMP
|
|
|
|
# define WCOREDUMP(status) ((status) & 0200)
|
|
|
|
#endif
|
|
|
|
#ifndef WSTOPSIG
|
|
|
|
# define WSTOPSIG(status) ((status) >> 8)
|
|
|
|
#endif
|
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
2004-10-30 11:44:06 +00:00
|
|
|
#include <epan/packet.h>
|
|
|
|
#include <epan/prefs.h>
|
|
|
|
|
|
|
|
#include "globals.h"
|
2005-02-04 08:52:38 +00:00
|
|
|
#include "file.h"
|
2005-12-15 00:48:59 +00:00
|
|
|
#include <epan/filesystem.h>
|
2004-10-30 11:44:06 +00:00
|
|
|
|
|
|
|
#include "capture.h"
|
|
|
|
#include "capture_sync.h"
|
|
|
|
#include "simple_dialog.h"
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
#include "capture-wpcap.h"
|
|
|
|
#endif
|
|
|
|
#include "ui_util.h"
|
2005-11-06 22:43:25 +00:00
|
|
|
#include "file_util.h"
|
2005-05-26 17:50:27 +00:00
|
|
|
#include "log.h"
|
2004-10-30 11:44:06 +00:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
#include <process.h> /* For spawning child process */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2006-02-17 22:39:32 +00:00
|
|
|
/*#define DEBUG_DUMPCAP*/
|
|
|
|
|
2004-10-30 11:44:06 +00:00
|
|
|
#ifndef _WIN32
|
2005-08-06 14:03:14 +00:00
|
|
|
static const char *sync_pipe_signame(int);
|
2004-10-30 11:44:06 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean sync_pipe_input_cb(gint source, gpointer user_data);
|
2005-05-26 19:06:01 +00:00
|
|
|
static void sync_pipe_wait_for_child(capture_options *capture_opts);
|
2004-10-30 11:44:06 +00:00
|
|
|
|
2005-11-18 00:34:11 +00:00
|
|
|
/*
|
|
|
|
* Maximum length of sync pipe message data. Must be < 2^24, as the
|
|
|
|
* message length is 3 bytes.
|
|
|
|
* XXX - this must be large enough to handle a Really Big Filter
|
|
|
|
* Expression, as the error message for an incorrect filter expression
|
|
|
|
* is a bit larger than the filter expression.
|
|
|
|
*/
|
|
|
|
#define SP_MAX_MSG_LEN 4096
|
|
|
|
|
2004-10-30 11:44:06 +00:00
|
|
|
|
2005-12-04 02:04:18 +00:00
|
|
|
/* write a message to the recipient pipe in the standard format
|
2005-04-12 00:54:52 +00:00
|
|
|
(3 digit message length (excluding length and indicator field),
|
|
|
|
1 byte message indicator and the rest is the message) */
|
|
|
|
static void
|
|
|
|
pipe_write_block(int pipe, char indicator, int len, const char *msg)
|
|
|
|
{
|
2005-11-18 00:34:11 +00:00
|
|
|
guchar header[3+1]; /* indicator + 3-byte len */
|
2005-04-12 00:54:52 +00:00
|
|
|
int ret;
|
|
|
|
|
2006-02-12 20:35:15 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "write %d enter", pipe);
|
2005-04-12 00:54:52 +00:00
|
|
|
|
|
|
|
g_assert(indicator < '0' || indicator > '9');
|
2005-11-18 00:34:11 +00:00
|
|
|
g_assert(len <= SP_MAX_MSG_LEN);
|
2005-04-12 00:54:52 +00:00
|
|
|
|
2005-11-18 00:34:11 +00:00
|
|
|
/* write header (indicator + 3-byte len) */
|
|
|
|
header[0] = indicator;
|
|
|
|
header[1] = (len >> 16) & 0xFF;
|
|
|
|
header[2] = (len >> 8) & 0xFF;
|
|
|
|
header[3] = (len >> 0) & 0xFF;
|
2005-04-12 00:54:52 +00:00
|
|
|
|
2005-11-18 00:34:11 +00:00
|
|
|
ret = write(pipe, header, sizeof header);
|
2005-04-12 21:44:55 +00:00
|
|
|
if(ret == -1) {
|
2006-02-12 20:35:15 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_WARNING,
|
|
|
|
"write %d header: error %s", pipe, strerror(errno));
|
2005-04-12 21:44:55 +00:00
|
|
|
return;
|
|
|
|
}
|
2005-04-12 00:54:52 +00:00
|
|
|
|
|
|
|
/* write value (if we have one) */
|
|
|
|
if(len) {
|
2006-02-12 20:35:15 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
|
|
|
|
"write %d indicator: %c value len: %u msg: %s", pipe, indicator,
|
|
|
|
len, msg);
|
2005-04-12 00:54:52 +00:00
|
|
|
ret = write(pipe, msg, len);
|
2005-04-12 21:44:55 +00:00
|
|
|
if(ret == -1) {
|
2006-02-12 20:35:15 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_WARNING,
|
|
|
|
"write %d value: error %s", pipe, strerror(errno));
|
2005-04-12 21:44:55 +00:00
|
|
|
return;
|
|
|
|
}
|
2005-04-12 00:54:52 +00:00
|
|
|
} else {
|
2006-02-12 20:35:15 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
|
|
|
|
"write %d indicator: %c no value", pipe, indicator);
|
2005-04-12 00:54:52 +00:00
|
|
|
}
|
|
|
|
|
2006-02-12 20:35:15 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "write %d leave", pipe);
|
2005-04-12 00:54:52 +00:00
|
|
|
}
|
|
|
|
|
2006-02-12 00:03:10 +00:00
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
void
|
|
|
|
sync_pipe_errmsg_to_parent(const char *errmsg)
|
|
|
|
{
|
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_errmsg_to_parent: %s", errmsg);
|
|
|
|
|
|
|
|
pipe_write_block(1, SP_ERROR_MSG, strlen(errmsg)+1, errmsg);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2006-02-11 23:25:11 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
static void
|
|
|
|
signal_pipe_capquit_to_child(capture_options *capture_opts)
|
|
|
|
{
|
|
|
|
|
|
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "signal_pipe_capquit_to_child");
|
|
|
|
|
|
|
|
pipe_write_block(capture_opts->signal_pipe_write_fd, SP_QUIT, 0, NULL);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2005-04-12 00:54:52 +00:00
|
|
|
|
|
|
|
/* read a message from the sending pipe in the standard format
|
2005-11-18 00:34:11 +00:00
|
|
|
(1-byte message indicator, 3-byte message length (excluding length
|
|
|
|
and indicator field), and the rest is the message) */
|
2005-08-14 23:25:20 +00:00
|
|
|
static int
|
2005-04-12 00:54:52 +00:00
|
|
|
pipe_read_block(int pipe, char *indicator, int len, char *msg) {
|
|
|
|
int required;
|
|
|
|
int newly;
|
2005-11-18 00:34:11 +00:00
|
|
|
guchar header[4];
|
2005-04-12 00:54:52 +00:00
|
|
|
int offset;
|
|
|
|
|
|
|
|
|
2005-11-18 00:34:11 +00:00
|
|
|
/* read header (indicator and 3-byte length) */
|
2005-04-12 00:54:52 +00:00
|
|
|
required = 4;
|
|
|
|
offset = 0;
|
|
|
|
while(required) {
|
|
|
|
newly = read(pipe, &header[offset], required);
|
|
|
|
if (newly == 0) {
|
|
|
|
/* EOF */
|
2006-02-12 20:35:15 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
|
|
|
|
"read %d header empty (capture closed)", pipe);
|
2005-04-12 00:54:52 +00:00
|
|
|
return newly;
|
|
|
|
}
|
|
|
|
if (newly < 0) {
|
|
|
|
/* error */
|
2006-02-12 20:35:15 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
|
|
|
|
"read %d header error: %s", pipe, strerror(errno));
|
2005-04-12 00:54:52 +00:00
|
|
|
return newly;
|
|
|
|
}
|
|
|
|
|
|
|
|
required -= newly;
|
|
|
|
offset += newly;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* convert header values */
|
2005-11-18 00:34:11 +00:00
|
|
|
*indicator = header[0];
|
|
|
|
required = header[1]<<16 | header[2]<<8 | header[3];
|
2005-04-12 00:54:52 +00:00
|
|
|
|
|
|
|
/* only indicator with no value? */
|
|
|
|
if(required == 0) {
|
2006-02-12 20:35:15 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
|
|
|
|
"read %d indicator: %c empty value", pipe, *indicator);
|
2005-04-12 00:54:52 +00:00
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
|
2006-02-11 23:25:11 +00:00
|
|
|
if(required > len) {
|
2006-02-12 20:35:15 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
|
|
|
|
"read %d length error, required %d > len %d, indicator: %u",
|
|
|
|
pipe, required, len, *indicator);
|
2006-02-11 23:25:11 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2005-04-12 00:54:52 +00:00
|
|
|
len = required;
|
|
|
|
|
|
|
|
/* read value */
|
|
|
|
offset = 0;
|
|
|
|
while(required) {
|
|
|
|
newly = read(pipe, &msg[offset], required);
|
|
|
|
if (newly == -1) {
|
|
|
|
/* error */
|
2006-02-12 20:35:15 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
|
|
|
|
"read %d value error: %s, indicator: %u", pipe,
|
|
|
|
strerror(errno), *indicator);
|
2005-04-12 00:54:52 +00:00
|
|
|
return newly;
|
|
|
|
}
|
|
|
|
|
|
|
|
required -= newly;
|
|
|
|
offset += newly;
|
|
|
|
}
|
|
|
|
|
2006-02-12 20:35:15 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
|
|
|
|
"read %d ok indicator: %c len: %u msg: %s", pipe, *indicator,
|
|
|
|
len, msg);
|
2005-04-12 00:54:52 +00:00
|
|
|
return len + 4;
|
|
|
|
}
|
2004-10-30 11:44:06 +00:00
|
|
|
|
2005-04-10 16:43:22 +00:00
|
|
|
|
|
|
|
|
2004-10-30 11:44:06 +00:00
|
|
|
/* Add a string pointer to a NULL-terminated array of string pointers. */
|
2005-08-06 14:03:14 +00:00
|
|
|
static const char **
|
|
|
|
sync_pipe_add_arg(const char **args, int *argc, const char *arg)
|
2004-10-30 11:44:06 +00:00
|
|
|
{
|
|
|
|
/* Grow the array; "*argc" currently contains the number of string
|
|
|
|
pointers, *not* counting the NULL pointer at the end, so we have
|
|
|
|
to add 2 in order to get the new size of the array, including the
|
|
|
|
new pointer and the terminating NULL pointer. */
|
2005-08-20 22:16:12 +00:00
|
|
|
args = g_realloc( (gpointer) args, (*argc + 2) * sizeof (char *));
|
2004-10-30 11:44:06 +00:00
|
|
|
|
|
|
|
/* Stuff the pointer into the penultimate element of the array, which
|
|
|
|
is the one at the index specified by "*argc". */
|
|
|
|
args[*argc] = arg;
|
|
|
|
|
|
|
|
/* Now bump the count. */
|
|
|
|
(*argc)++;
|
|
|
|
|
|
|
|
/* We overwrite the NULL pointer; put it back right after the
|
|
|
|
element we added. */
|
|
|
|
args[*argc] = NULL;
|
|
|
|
|
|
|
|
return args;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2006-02-17 09:45:52 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
/* Quote the argument element if necessary, so that it will get
|
|
|
|
* reconstructed correctly in the C runtime startup code. Note that
|
|
|
|
* the unquoting algorithm in the C runtime is really weird, and
|
|
|
|
* rather different than what Unix shells do. See stdargv.c in the C
|
|
|
|
* runtime sources (in the Platform SDK, in src/crt).
|
|
|
|
*
|
|
|
|
* Stolen from GLib's protect_argv(), an internal routine that quotes
|
|
|
|
* string in an argument list so that they arguments will be handled
|
|
|
|
* correctly in the command-line string passed to CreateProcess()
|
|
|
|
* if that string is constructed by gluing those strings together.
|
|
|
|
*/
|
|
|
|
static gchar *
|
2006-02-17 22:39:32 +00:00
|
|
|
protect_arg (const gchar *argv)
|
2006-02-17 09:45:52 +00:00
|
|
|
{
|
|
|
|
gchar *new_arg;
|
2006-02-17 22:39:32 +00:00
|
|
|
const gchar *p = argv;
|
2006-02-17 09:45:52 +00:00
|
|
|
gchar *q;
|
|
|
|
gint len = 0;
|
|
|
|
gboolean need_dblquotes = FALSE;
|
|
|
|
|
|
|
|
while (*p) {
|
|
|
|
if (*p == ' ' || *p == '\t')
|
|
|
|
need_dblquotes = TRUE;
|
|
|
|
else if (*p == '"')
|
|
|
|
len++;
|
|
|
|
else if (*p == '\\') {
|
2006-02-17 22:39:32 +00:00
|
|
|
const gchar *pp = p;
|
2006-02-17 09:45:52 +00:00
|
|
|
|
|
|
|
while (*pp && *pp == '\\')
|
|
|
|
pp++;
|
|
|
|
if (*pp == '"')
|
|
|
|
len++;
|
|
|
|
}
|
|
|
|
len++;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
q = new_arg = g_malloc (len + need_dblquotes*2 + 1);
|
|
|
|
p = argv;
|
|
|
|
|
|
|
|
if (need_dblquotes)
|
|
|
|
*q++ = '"';
|
|
|
|
|
|
|
|
while (*p) {
|
|
|
|
if (*p == '"')
|
|
|
|
*q++ = '\\';
|
|
|
|
else if (*p == '\\') {
|
2006-02-17 22:39:32 +00:00
|
|
|
const gchar *pp = p;
|
2006-02-17 09:45:52 +00:00
|
|
|
|
|
|
|
while (*pp && *pp == '\\')
|
|
|
|
pp++;
|
|
|
|
if (*pp == '"')
|
|
|
|
*q++ = '\\';
|
|
|
|
}
|
|
|
|
*q++ = *p;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (need_dblquotes)
|
|
|
|
*q++ = '"';
|
|
|
|
*q++ = '\0';
|
|
|
|
|
|
|
|
return new_arg;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
2005-04-10 14:29:12 +00:00
|
|
|
#define ARGV_NUMBER_LEN 24
|
|
|
|
|
2004-10-30 11:44:06 +00:00
|
|
|
gboolean
|
2005-04-30 15:39:40 +00:00
|
|
|
sync_pipe_start(capture_options *capture_opts) {
|
2005-04-10 14:29:12 +00:00
|
|
|
char ssnap[ARGV_NUMBER_LEN];
|
|
|
|
char scount[ARGV_NUMBER_LEN];
|
|
|
|
char sfilesize[ARGV_NUMBER_LEN];
|
|
|
|
char sfile_duration[ARGV_NUMBER_LEN];
|
|
|
|
char sring_num_files[ARGV_NUMBER_LEN];
|
|
|
|
char sautostop_files[ARGV_NUMBER_LEN];
|
|
|
|
char sautostop_filesize[ARGV_NUMBER_LEN];
|
|
|
|
char sautostop_duration[ARGV_NUMBER_LEN];
|
2004-10-30 11:44:06 +00:00
|
|
|
#ifdef _WIN32
|
2005-05-30 04:46:25 +00:00
|
|
|
char buffer_size[ARGV_NUMBER_LEN];
|
2006-02-11 23:25:11 +00:00
|
|
|
HANDLE sync_pipe_read; /* pipe used to send messages from child to parent */
|
|
|
|
HANDLE sync_pipe_write; /* pipe used to send messages from child to parent */
|
|
|
|
HANDLE signal_pipe_read; /* pipe used to send messages from parent to child (currently only stop) */
|
|
|
|
HANDLE signal_pipe_write; /* pipe used to send messages from parent to child (currently only stop) */
|
|
|
|
GString *args = g_string_sized_new(200);
|
2006-02-17 09:45:52 +00:00
|
|
|
gchar *quoted_arg;
|
2006-02-11 23:25:11 +00:00
|
|
|
SECURITY_ATTRIBUTES sa;
|
|
|
|
STARTUPINFO si;
|
|
|
|
PROCESS_INFORMATION pi;
|
|
|
|
int i;
|
2005-04-10 14:29:12 +00:00
|
|
|
#else
|
|
|
|
char errmsg[1024+1];
|
2006-02-11 23:25:11 +00:00
|
|
|
int sync_pipe[2]; /* pipe used to send messages from child to parent */
|
|
|
|
enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
|
2004-10-30 11:44:06 +00:00
|
|
|
#endif
|
2006-02-11 23:25:11 +00:00
|
|
|
int sync_pipe_read_fd;
|
|
|
|
char *exename;
|
2005-04-10 14:29:12 +00:00
|
|
|
int argc;
|
2005-08-06 14:03:14 +00:00
|
|
|
const char **argv;
|
2004-10-30 11:44:06 +00:00
|
|
|
|
2005-03-28 00:19:02 +00:00
|
|
|
|
2005-05-26 17:50:27 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_start");
|
|
|
|
capture_opts_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, capture_opts);
|
2005-03-28 00:19:02 +00:00
|
|
|
|
2005-02-04 01:29:29 +00:00
|
|
|
capture_opts->fork_child = -1;
|
2004-10-30 11:44:06 +00:00
|
|
|
|
|
|
|
/* Allocate the string pointer array with enough space for the
|
|
|
|
terminating NULL pointer. */
|
|
|
|
argc = 0;
|
|
|
|
argv = g_malloc(sizeof (char *));
|
|
|
|
*argv = NULL;
|
|
|
|
|
2006-02-12 20:55:11 +00:00
|
|
|
/* take ethereal's absolute program path and replace ethereal with dumpcap */
|
|
|
|
exename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "dumpcap",
|
|
|
|
get_progfile_dir());
|
|
|
|
|
|
|
|
/* Make that the first argument in the argument list (argv[0]). */
|
|
|
|
argv = sync_pipe_add_arg(argv, &argc, exename);
|
|
|
|
|
2004-10-30 11:44:06 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, "-i");
|
2005-02-06 21:20:35 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, capture_opts->iface);
|
2004-10-30 11:44:06 +00:00
|
|
|
|
2004-12-29 09:09:35 +00:00
|
|
|
if (capture_opts->has_snaplen) {
|
2004-10-30 11:44:06 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, "-s");
|
2005-08-08 18:50:39 +00:00
|
|
|
g_snprintf(ssnap, ARGV_NUMBER_LEN, "%d",capture_opts->snaplen);
|
2004-10-30 11:44:06 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, ssnap);
|
|
|
|
}
|
|
|
|
|
2004-12-29 09:09:35 +00:00
|
|
|
if (capture_opts->linktype != -1) {
|
2004-10-30 11:44:06 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, "-y");
|
|
|
|
#ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME
|
2006-02-17 02:18:48 +00:00
|
|
|
g_snprintf(ssnap, ARGV_NUMBER_LEN, "%s",linktype_val_to_name(capture_opts->linktype));
|
2004-10-30 11:44:06 +00:00
|
|
|
#else
|
|
|
|
/* XXX - just treat it as a number */
|
2005-08-08 18:50:39 +00:00
|
|
|
g_snprintf(ssnap, ARGV_NUMBER_LEN, "%d",capture_opts->linktype);
|
2004-10-30 11:44:06 +00:00
|
|
|
#endif
|
|
|
|
argv = sync_pipe_add_arg(argv, &argc, ssnap);
|
|
|
|
}
|
|
|
|
|
2005-03-28 00:19:02 +00:00
|
|
|
if(capture_opts->multi_files_on) {
|
|
|
|
if (capture_opts->has_autostop_filesize) {
|
|
|
|
argv = sync_pipe_add_arg(argv, &argc, "-b");
|
2005-08-08 18:50:39 +00:00
|
|
|
g_snprintf(sfilesize, ARGV_NUMBER_LEN, "filesize:%d",capture_opts->autostop_filesize);
|
2005-03-28 00:19:02 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, sfilesize);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (capture_opts->has_file_duration) {
|
|
|
|
argv = sync_pipe_add_arg(argv, &argc, "-b");
|
2005-08-08 18:50:39 +00:00
|
|
|
g_snprintf(sfile_duration, ARGV_NUMBER_LEN, "duration:%d",capture_opts->file_duration);
|
2005-03-28 00:19:02 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, sfile_duration);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (capture_opts->has_ring_num_files) {
|
|
|
|
argv = sync_pipe_add_arg(argv, &argc, "-b");
|
2005-08-08 18:50:39 +00:00
|
|
|
g_snprintf(sring_num_files, ARGV_NUMBER_LEN, "files:%d",capture_opts->ring_num_files);
|
2005-03-28 00:19:02 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, sring_num_files);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (capture_opts->has_autostop_files) {
|
|
|
|
argv = sync_pipe_add_arg(argv, &argc, "-a");
|
2005-08-08 18:50:39 +00:00
|
|
|
g_snprintf(sautostop_files, ARGV_NUMBER_LEN, "files:%d",capture_opts->autostop_files);
|
2005-03-28 00:19:02 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, sautostop_files);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (capture_opts->has_autostop_filesize) {
|
|
|
|
argv = sync_pipe_add_arg(argv, &argc, "-a");
|
2005-08-08 18:50:39 +00:00
|
|
|
g_snprintf(sautostop_filesize, ARGV_NUMBER_LEN, "filesize:%d",capture_opts->autostop_filesize);
|
2005-03-28 00:19:02 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (capture_opts->has_autostop_packets) {
|
|
|
|
argv = sync_pipe_add_arg(argv, &argc, "-c");
|
2005-08-08 18:50:39 +00:00
|
|
|
g_snprintf(scount, ARGV_NUMBER_LEN, "%d",capture_opts->autostop_packets);
|
2005-03-28 00:19:02 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, scount);
|
2004-10-30 11:44:06 +00:00
|
|
|
}
|
|
|
|
|
2004-12-29 09:09:35 +00:00
|
|
|
if (capture_opts->has_autostop_duration) {
|
2004-10-30 11:44:06 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, "-a");
|
2005-08-08 18:50:39 +00:00
|
|
|
g_snprintf(sautostop_duration, ARGV_NUMBER_LEN, "duration:%d",capture_opts->autostop_duration);
|
2004-10-30 11:44:06 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
|
|
|
|
}
|
|
|
|
|
2004-12-29 09:09:35 +00:00
|
|
|
if (!capture_opts->promisc_mode)
|
2004-10-30 11:44:06 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, "-p");
|
|
|
|
|
2006-02-11 23:25:11 +00:00
|
|
|
/* dumpcap should be running in capture child mode (hidden feature) */
|
|
|
|
#ifndef DEBUG_CHILD
|
|
|
|
argv = sync_pipe_add_arg(argv, &argc, "-Z");
|
|
|
|
#endif
|
2004-10-30 11:44:06 +00:00
|
|
|
|
2006-02-11 23:25:11 +00:00
|
|
|
#ifdef _WIN32
|
2005-05-30 04:46:25 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, "-B");
|
2005-08-08 18:50:39 +00:00
|
|
|
g_snprintf(buffer_size, ARGV_NUMBER_LEN, "%d",capture_opts->buffer_size);
|
2005-05-30 04:46:25 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, buffer_size);
|
2006-02-17 11:53:11 +00:00
|
|
|
#endif
|
2005-05-30 04:46:25 +00:00
|
|
|
|
2006-02-17 22:39:32 +00:00
|
|
|
if (capture_opts->cfilter != NULL && strlen(capture_opts->cfilter) != 0) {
|
2004-10-30 11:44:06 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, "-f");
|
2006-02-17 11:53:11 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, capture_opts->cfilter);
|
2004-10-30 11:44:06 +00:00
|
|
|
}
|
|
|
|
|
2005-05-25 17:46:04 +00:00
|
|
|
if(capture_opts->save_file) {
|
|
|
|
argv = sync_pipe_add_arg(argv, &argc, "-w");
|
2006-02-17 11:53:11 +00:00
|
|
|
argv = sync_pipe_add_arg(argv, &argc, capture_opts->save_file);
|
2005-05-25 17:46:04 +00:00
|
|
|
}
|
|
|
|
|
2006-02-17 11:53:11 +00:00
|
|
|
#ifdef _WIN32
|
2006-02-11 23:25:11 +00:00
|
|
|
/* init SECURITY_ATTRIBUTES */
|
|
|
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
|
|
sa.bInheritHandle = TRUE;
|
|
|
|
sa.lpSecurityDescriptor = NULL;
|
2006-02-10 01:27:23 +00:00
|
|
|
|
2006-02-11 23:25:11 +00:00
|
|
|
/* Create a pipe for the child process */
|
|
|
|
/* (inrease this value if you have trouble while fast capture file switches) */
|
|
|
|
if (! CreatePipe(&sync_pipe_read, &sync_pipe_write, &sa, 5120)) {
|
|
|
|
/* Couldn't create the pipe between parent and child. */
|
|
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
|
|
|
|
strerror(errno));
|
|
|
|
g_free( (gpointer) argv);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2006-02-10 01:27:23 +00:00
|
|
|
|
2006-02-11 23:25:11 +00:00
|
|
|
/* Create a pipe for the parent process */
|
|
|
|
if (! CreatePipe(&signal_pipe_read, &signal_pipe_write, &sa, 512)) {
|
|
|
|
/* Couldn't create the signal pipe between parent and child. */
|
|
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create signal pipe: %s",
|
|
|
|
strerror(errno));
|
|
|
|
CloseHandle(sync_pipe_read);
|
|
|
|
CloseHandle(sync_pipe_write);
|
|
|
|
g_free( (gpointer) argv);
|
|
|
|
return FALSE;
|
2006-02-10 01:27:23 +00:00
|
|
|
}
|
2006-02-11 23:25:11 +00:00
|
|
|
|
|
|
|
/* init STARTUPINFO */
|
|
|
|
memset(&si, 0, sizeof(si));
|
|
|
|
si.cb = sizeof(si);
|
|
|
|
#ifdef DEBUG_CHILD
|
|
|
|
si.dwFlags = STARTF_USESHOWWINDOW;
|
|
|
|
si.wShowWindow = SW_SHOW;
|
|
|
|
#else
|
|
|
|
si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
|
|
|
|
si.wShowWindow = SW_HIDE; /* this hides the console window */
|
|
|
|
si.hStdInput = signal_pipe_read;
|
|
|
|
si.hStdOutput = sync_pipe_write;
|
|
|
|
si.hStdError = sync_pipe_write;
|
2006-02-17 02:18:48 +00:00
|
|
|
/*si.hStdError = (HANDLE) _get_osfhandle(2);*/
|
2006-02-10 01:27:23 +00:00
|
|
|
#endif
|
2006-02-11 23:25:11 +00:00
|
|
|
|
|
|
|
/* convert args array into a single string */
|
|
|
|
/* XXX - could change sync_pipe_add_arg() instead */
|
|
|
|
/* there is a drawback here: the length is internally limited to 1024 bytes */
|
|
|
|
for(i=0; argv[i] != 0; i++) {
|
2006-02-17 22:39:32 +00:00
|
|
|
if(i != 0) g_string_append_c(args, ' '); /* don't prepend a space before the path!!! */
|
2006-02-17 09:45:52 +00:00
|
|
|
quoted_arg = protect_arg(argv[i]);
|
|
|
|
g_string_append(args, quoted_arg);
|
|
|
|
g_free(quoted_arg);
|
2005-12-15 00:48:59 +00:00
|
|
|
}
|
2006-02-11 23:25:11 +00:00
|
|
|
|
|
|
|
/* call dumpcap */
|
2006-02-12 00:59:34 +00:00
|
|
|
if(!CreateProcess(NULL, args->str, NULL, NULL, TRUE,
|
|
|
|
CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
|
2006-02-17 22:39:32 +00:00
|
|
|
g_warning("Couldn't open dumpcap (Error: %u): %s", GetLastError(), args->str);
|
|
|
|
capture_opts->fork_child = -1;
|
|
|
|
} else {
|
|
|
|
capture_opts->fork_child = (int) pi.hProcess;
|
2006-02-11 23:25:11 +00:00
|
|
|
}
|
|
|
|
g_string_free(args, TRUE);
|
|
|
|
|
|
|
|
/* associate the operating system filehandle to a C run-time file handle */
|
2006-02-12 12:04:17 +00:00
|
|
|
/* (good file handle infos at: http://www.flounder.com/handles.htm) */
|
2006-02-11 23:25:11 +00:00
|
|
|
sync_pipe_read_fd = _open_osfhandle( (long) sync_pipe_read, _O_BINARY);
|
|
|
|
|
|
|
|
/* associate the operating system filehandle to a C run-time file handle */
|
|
|
|
capture_opts->signal_pipe_write_fd = _open_osfhandle( (long) signal_pipe_write, _O_BINARY);
|
|
|
|
|
2005-04-10 16:43:22 +00:00
|
|
|
/* child own's the read side now, close our handle */
|
2006-02-11 23:25:11 +00:00
|
|
|
CloseHandle(signal_pipe_read);
|
|
|
|
#else /* _WIN32 */
|
2004-10-30 11:44:06 +00:00
|
|
|
if (pipe(sync_pipe) < 0) {
|
|
|
|
/* Couldn't create the pipe between parent and child. */
|
|
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
|
2005-03-28 14:39:31 +00:00
|
|
|
strerror(errno));
|
2005-04-10 16:43:22 +00:00
|
|
|
g_free(argv);
|
2004-10-30 11:44:06 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2005-02-04 04:31:59 +00:00
|
|
|
if ((capture_opts->fork_child = fork()) == 0) {
|
2004-10-30 11:44:06 +00:00
|
|
|
/*
|
|
|
|
* Child process - run Ethereal with the right arguments to make
|
|
|
|
* it just pop up the live capture dialog box and capture with
|
|
|
|
* the specified capture parameters, writing to the specified file.
|
|
|
|
*
|
|
|
|
* args: -i interface specification
|
|
|
|
* -w file to write
|
|
|
|
* -c count to capture
|
|
|
|
* -s snaplen
|
|
|
|
* -m / -b fonts
|
|
|
|
* -f "filter expression"
|
|
|
|
*/
|
2005-11-06 22:43:25 +00:00
|
|
|
eth_close(1);
|
2004-10-30 11:44:06 +00:00
|
|
|
dup(sync_pipe[PIPE_WRITE]);
|
2005-11-06 22:43:25 +00:00
|
|
|
eth_close(sync_pipe[PIPE_READ]);
|
2006-02-17 09:45:52 +00:00
|
|
|
execv(exename, argv);
|
2005-08-08 18:50:39 +00:00
|
|
|
g_snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
|
2006-02-11 23:25:11 +00:00
|
|
|
exename, strerror(errno));
|
2004-10-30 11:44:06 +00:00
|
|
|
sync_pipe_errmsg_to_parent(errmsg);
|
|
|
|
|
|
|
|
/* Exit with "_exit()", so that we don't close the connection
|
|
|
|
to the X server (and cause stuff buffered up by our parent but
|
|
|
|
not yet sent to be sent, as that stuff should only be sent by
|
|
|
|
our parent). */
|
|
|
|
_exit(2);
|
|
|
|
}
|
2006-02-11 23:25:11 +00:00
|
|
|
|
|
|
|
sync_pipe_read_fd = sync_pipe[PIPE_READ];
|
2004-10-30 11:44:06 +00:00
|
|
|
#endif
|
|
|
|
|
2006-02-11 23:25:11 +00:00
|
|
|
g_free(exename);
|
|
|
|
|
2004-10-30 11:44:06 +00:00
|
|
|
/* Parent process - read messages from the child process over the
|
|
|
|
sync pipe. */
|
2005-08-20 22:16:12 +00:00
|
|
|
g_free( (gpointer) argv); /* free up arg array */
|
2004-10-30 11:44:06 +00:00
|
|
|
|
|
|
|
/* Close the write side of the pipe, so that only the child has it
|
|
|
|
open, and thus it completely closes, and thus returns to us
|
|
|
|
an EOF indication, if the child closes it (either deliberately
|
|
|
|
or by exiting abnormally). */
|
2006-02-11 23:25:11 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
CloseHandle(sync_pipe_write);
|
|
|
|
#else
|
2005-11-06 22:43:25 +00:00
|
|
|
eth_close(sync_pipe[PIPE_WRITE]);
|
2006-02-11 23:25:11 +00:00
|
|
|
#endif
|
2004-10-30 11:44:06 +00:00
|
|
|
|
2005-02-04 01:29:29 +00:00
|
|
|
if (capture_opts->fork_child == -1) {
|
2004-10-30 11:44:06 +00:00
|
|
|
/* We couldn't even create the child process. */
|
|
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
|
2005-03-28 14:39:31 +00:00
|
|
|
"Couldn't create child process: %s", strerror(errno));
|
2006-02-11 23:25:11 +00:00
|
|
|
eth_close(sync_pipe_read_fd);
|
2005-04-10 16:43:22 +00:00
|
|
|
#ifdef _WIN32
|
2006-02-11 23:25:11 +00:00
|
|
|
eth_close(capture_opts->signal_pipe_write_fd);
|
2005-04-10 16:43:22 +00:00
|
|
|
#endif
|
2004-10-30 11:44:06 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2005-04-10 16:43:22 +00:00
|
|
|
/* we might wait for a moment till child is ready, so update screen now */
|
|
|
|
main_window_update();
|
|
|
|
|
2005-03-28 14:39:31 +00:00
|
|
|
/* We were able to set up to read the capture file;
|
|
|
|
arrange that our callback be called whenever it's possible
|
|
|
|
to read from the sync pipe, so that it's called when
|
|
|
|
the child process wants to tell us something. */
|
2004-10-30 11:44:06 +00:00
|
|
|
|
2005-03-28 14:39:31 +00:00
|
|
|
/* we have a running capture, now wait for the real capture filename */
|
2006-02-11 23:25:11 +00:00
|
|
|
pipe_input_set_handler(sync_pipe_read_fd, (gpointer) capture_opts,
|
2005-03-28 14:39:31 +00:00
|
|
|
&capture_opts->fork_child, sync_pipe_input_cb);
|
2005-02-28 22:46:49 +00:00
|
|
|
|
2005-03-28 14:39:31 +00:00
|
|
|
return TRUE;
|
2004-10-30 11:44:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* There's stuff to read from the sync pipe, meaning the child has sent
|
|
|
|
us a message, or the sync pipe has closed, meaning the child has
|
|
|
|
closed it (perhaps because it exited). */
|
|
|
|
static gboolean
|
|
|
|
sync_pipe_input_cb(gint source, gpointer user_data)
|
|
|
|
{
|
2005-02-04 01:29:29 +00:00
|
|
|
capture_options *capture_opts = (capture_options *)user_data;
|
2005-11-18 00:34:11 +00:00
|
|
|
char buffer[SP_MAX_MSG_LEN+1];
|
2005-04-12 00:54:52 +00:00
|
|
|
int nread;
|
|
|
|
char indicator;
|
2004-10-30 11:44:06 +00:00
|
|
|
|
|
|
|
|
2005-11-18 00:34:11 +00:00
|
|
|
nread = pipe_read_block(source, &indicator, SP_MAX_MSG_LEN, buffer);
|
2005-04-12 00:54:52 +00:00
|
|
|
if(nread <= 0) {
|
2006-02-12 20:41:28 +00:00
|
|
|
if (nread == 0)
|
|
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
|
|
|
|
"sync_pipe_input_cb: child has closed sync_pipe");
|
|
|
|
else
|
|
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
|
|
|
|
"sync_pipe_input_cb: error reading from sync pipe");
|
2005-05-26 17:50:27 +00:00
|
|
|
|
2004-10-30 11:44:06 +00:00
|
|
|
/* The child has closed the sync pipe, meaning it's not going to be
|
|
|
|
capturing any more packets. Pick up its exit status, and
|
2006-02-12 20:41:28 +00:00
|
|
|
complain if it did anything other than exit with status 0.
|
|
|
|
|
|
|
|
XXX - what if we got an error from the sync pipe? Do we have
|
|
|
|
to kill the child? */
|
2005-05-26 19:06:01 +00:00
|
|
|
sync_pipe_wait_for_child(capture_opts);
|
2005-05-26 17:50:27 +00:00
|
|
|
|
2005-04-10 16:43:22 +00:00
|
|
|
#ifdef _WIN32
|
2006-02-11 23:25:11 +00:00
|
|
|
eth_close(capture_opts->signal_pipe_write_fd);
|
2005-04-10 16:43:22 +00:00
|
|
|
#endif
|
2005-03-28 14:39:31 +00:00
|
|
|
capture_input_closed(capture_opts);
|
2004-10-30 11:44:06 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2005-04-12 00:54:52 +00:00
|
|
|
switch(indicator) {
|
2005-04-12 21:44:55 +00:00
|
|
|
case SP_FILE:
|
|
|
|
if(!capture_input_new_file(capture_opts, buffer)) {
|
2005-05-26 17:50:27 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: file failed, closing capture");
|
|
|
|
|
2005-04-12 21:44:55 +00:00
|
|
|
/* We weren't able to open the new capture file; user has been
|
|
|
|
alerted. Close the sync pipe. */
|
2005-11-06 22:43:25 +00:00
|
|
|
eth_close(source);
|
2005-04-12 21:44:55 +00:00
|
|
|
|
|
|
|
/* the child has send us a filename which we couldn't open.
|
|
|
|
this probably means, the child is creating files faster than we can handle it.
|
|
|
|
this should only be the case for very fast file switches
|
|
|
|
we can't do much more than telling the child to stop
|
2005-12-03 18:15:02 +00:00
|
|
|
(this is the "emergency brake" if user e.g. wants to switch files every second) */
|
2005-04-12 21:44:55 +00:00
|
|
|
sync_pipe_stop(capture_opts);
|
|
|
|
}
|
|
|
|
break;
|
2005-04-12 00:54:52 +00:00
|
|
|
case SP_PACKET_COUNT:
|
|
|
|
nread = atoi(buffer);
|
2005-05-26 17:50:27 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: new packets %u", nread);
|
2005-04-12 00:54:52 +00:00
|
|
|
capture_input_new_packets(capture_opts, nread);
|
|
|
|
break;
|
2005-04-12 21:44:55 +00:00
|
|
|
case SP_ERROR_MSG:
|
2005-12-03 18:15:02 +00:00
|
|
|
capture_input_error_message(capture_opts, buffer);
|
2005-05-26 17:50:27 +00:00
|
|
|
/* the capture child will close the sync_pipe, nothing to do for now */
|
2005-04-12 21:44:55 +00:00
|
|
|
break;
|
2005-04-12 00:54:52 +00:00
|
|
|
case SP_DROPS:
|
2005-12-03 18:15:02 +00:00
|
|
|
capture_input_drops(capture_opts, atoi(buffer));
|
2005-04-12 00:54:52 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
2004-10-30 11:44:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2004-12-29 09:09:35 +00:00
|
|
|
|
2005-04-12 00:54:52 +00:00
|
|
|
|
2004-12-29 09:09:35 +00:00
|
|
|
/* the child process is going down, wait until it's completely terminated */
|
2004-10-30 11:44:06 +00:00
|
|
|
static void
|
2005-05-26 19:06:01 +00:00
|
|
|
sync_pipe_wait_for_child(capture_options *capture_opts)
|
2004-10-30 11:44:06 +00:00
|
|
|
{
|
|
|
|
int wstatus;
|
|
|
|
|
2005-02-23 22:04:31 +00:00
|
|
|
|
2005-05-26 17:50:27 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_wait_for_child: wait till child closed");
|
2005-02-23 22:04:31 +00:00
|
|
|
g_assert(capture_opts->fork_child != -1);
|
|
|
|
|
2004-10-30 11:44:06 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
/* XXX - analyze the wait status and display more information
|
|
|
|
in the dialog box?
|
|
|
|
XXX - set "fork_child" to -1 if we find it exited? */
|
2005-02-23 22:04:31 +00:00
|
|
|
if (_cwait(&wstatus, capture_opts->fork_child, _WAIT_CHILD) == -1) {
|
2004-10-30 11:44:06 +00:00
|
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
|
|
|
|
"Child capture process stopped unexpectedly");
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (wait(&wstatus) != -1) {
|
|
|
|
if (WIFEXITED(wstatus)) {
|
2005-05-26 19:06:01 +00:00
|
|
|
/* The child exited; display its exit status, if it seems uncommon (0=ok, 1=error) */
|
|
|
|
/* the child will inform us about errors through the sync_pipe, which will popup */
|
|
|
|
/* an error message, so don't popup another one */
|
|
|
|
|
|
|
|
/* XXX - if there are situations where the child won't send us such an error message, */
|
|
|
|
/* this should be fixed in the child and not here! */
|
|
|
|
if (WEXITSTATUS(wstatus) != 0 && WEXITSTATUS(wstatus) != 1) {
|
2004-10-30 11:44:06 +00:00
|
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
|
|
|
|
"Child capture process exited: exit status %d",
|
|
|
|
WEXITSTATUS(wstatus));
|
|
|
|
}
|
|
|
|
} else if (WIFSTOPPED(wstatus)) {
|
|
|
|
/* It stopped, rather than exiting. "Should not happen." */
|
|
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
|
|
|
|
"Child capture process stopped: %s",
|
|
|
|
sync_pipe_signame(WSTOPSIG(wstatus)));
|
|
|
|
} else if (WIFSIGNALED(wstatus)) {
|
|
|
|
/* It died with a signal. */
|
|
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
|
|
|
|
"Child capture process died: %s%s",
|
|
|
|
sync_pipe_signame(WTERMSIG(wstatus)),
|
|
|
|
WCOREDUMP(wstatus) ? " - core dumped" : "");
|
|
|
|
} else {
|
|
|
|
/* What? It had to either have exited, or stopped, or died with
|
|
|
|
a signal; what happened here? */
|
|
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
|
|
|
|
"Child capture process died: wait status %#o", wstatus);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No more child process. */
|
2005-02-23 22:04:31 +00:00
|
|
|
capture_opts->fork_child = -1;
|
2004-10-30 11:44:06 +00:00
|
|
|
#endif
|
2005-05-26 17:50:27 +00:00
|
|
|
|
|
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_wait_for_child: capture child closed");
|
2004-10-30 11:44:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
2005-04-11 18:57:19 +00:00
|
|
|
/* convert signal to corresponding name */
|
2005-08-06 14:03:14 +00:00
|
|
|
static const char *
|
2004-10-30 11:44:06 +00:00
|
|
|
sync_pipe_signame(int sig)
|
|
|
|
{
|
2005-08-06 14:03:14 +00:00
|
|
|
const char *sigmsg;
|
2004-10-30 11:44:06 +00:00
|
|
|
static char sigmsg_buf[6+1+3+1];
|
|
|
|
|
|
|
|
switch (sig) {
|
|
|
|
|
|
|
|
case SIGHUP:
|
|
|
|
sigmsg = "Hangup";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIGINT:
|
|
|
|
sigmsg = "Interrupted";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIGQUIT:
|
|
|
|
sigmsg = "Quit";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIGILL:
|
|
|
|
sigmsg = "Illegal instruction";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIGTRAP:
|
|
|
|
sigmsg = "Trace trap";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIGABRT:
|
|
|
|
sigmsg = "Abort";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIGFPE:
|
|
|
|
sigmsg = "Arithmetic exception";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIGKILL:
|
|
|
|
sigmsg = "Killed";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIGBUS:
|
|
|
|
sigmsg = "Bus error";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIGSEGV:
|
|
|
|
sigmsg = "Segmentation violation";
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
|
|
|
|
Linux is POSIX compliant. These are not POSIX-defined signals ---
|
|
|
|
ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
|
|
|
|
|
|
|
|
``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
|
|
|
|
were omitted from POSIX.1 because their behavior is
|
|
|
|
implementation dependent and could not be adequately catego-
|
|
|
|
rized. Conforming implementations may deliver these sig-
|
|
|
|
nals, but must document the circumstances under which they
|
|
|
|
are delivered and note any restrictions concerning their
|
|
|
|
delivery.''
|
|
|
|
|
|
|
|
So we only check for SIGSYS on those systems that happen to
|
|
|
|
implement them (a system can be POSIX-compliant and implement
|
|
|
|
them, it's just that POSIX doesn't *require* a POSIX-compliant
|
|
|
|
system to implement them).
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef SIGSYS
|
|
|
|
case SIGSYS:
|
|
|
|
sigmsg = "Bad system call";
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
case SIGPIPE:
|
|
|
|
sigmsg = "Broken pipe";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIGALRM:
|
|
|
|
sigmsg = "Alarm clock";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIGTERM:
|
|
|
|
sigmsg = "Terminated";
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2005-08-08 18:50:39 +00:00
|
|
|
/* XXX - returning a static buffer is ok in the context we use it here */
|
|
|
|
g_snprintf(sigmsg_buf, sizeof sigmsg_buf, "Signal %d", sig);
|
2004-10-30 11:44:06 +00:00
|
|
|
sigmsg = sigmsg_buf;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return sigmsg;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2005-04-11 18:57:19 +00:00
|
|
|
/* user wants to stop the capture run */
|
2004-10-30 11:44:06 +00:00
|
|
|
void
|
2005-02-04 01:29:29 +00:00
|
|
|
sync_pipe_stop(capture_options *capture_opts)
|
2004-10-30 11:44:06 +00:00
|
|
|
{
|
2005-02-23 22:04:31 +00:00
|
|
|
/* XXX - in which cases this will be 0? */
|
2005-02-07 03:13:51 +00:00
|
|
|
if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
|
2004-10-30 11:44:06 +00:00
|
|
|
#ifndef _WIN32
|
2005-04-11 18:57:19 +00:00
|
|
|
/* send the SIGUSR1 signal to close the capture child gracefully. */
|
2005-04-10 16:43:22 +00:00
|
|
|
kill(capture_opts->fork_child, SIGUSR1);
|
2004-10-30 11:44:06 +00:00
|
|
|
#else
|
2005-04-11 18:57:19 +00:00
|
|
|
/* Win32 doesn't have the kill() system call, use the special signal pipe
|
|
|
|
instead to close the capture child gracefully. */
|
2005-04-12 21:44:55 +00:00
|
|
|
signal_pipe_capquit_to_child(capture_opts);
|
2004-10-30 11:44:06 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-04-11 18:57:19 +00:00
|
|
|
/* Ethereal has to exit, force the capture child to close */
|
2004-10-30 11:44:06 +00:00
|
|
|
void
|
2005-02-04 01:29:29 +00:00
|
|
|
sync_pipe_kill(capture_options *capture_opts)
|
2004-10-30 11:44:06 +00:00
|
|
|
{
|
2005-02-23 22:04:31 +00:00
|
|
|
/* XXX - in which cases this will be 0? */
|
2005-02-07 03:13:51 +00:00
|
|
|
if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
|
2004-10-30 11:44:06 +00:00
|
|
|
#ifndef _WIN32
|
2005-02-04 01:29:29 +00:00
|
|
|
kill(capture_opts->fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */
|
2004-10-30 11:44:06 +00:00
|
|
|
#else
|
|
|
|
/* XXX: this is not the preferred method of closing a process!
|
|
|
|
* the clean way would be getting the process id of the child process,
|
|
|
|
* then getting window handle hWnd of that process (using EnumChildWindows),
|
|
|
|
* and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
|
|
|
|
*
|
2005-02-07 03:13:51 +00:00
|
|
|
* Unfortunately, I don't know how to get the process id from the
|
|
|
|
* handle. OpenProcess will get an handle (not a window handle)
|
|
|
|
* from the process ID; it will not get a window handle from the
|
|
|
|
* process ID. (How could it? A process can have more than one
|
|
|
|
* window.)
|
2004-10-30 11:44:06 +00:00
|
|
|
*
|
2005-02-07 03:13:51 +00:00
|
|
|
* Hint: GenerateConsoleCtrlEvent() will only work if both processes are
|
|
|
|
* running in the same console; that's not necessarily the case for
|
|
|
|
* us, as we might not be running in a console.
|
|
|
|
* And this also will require to have the process id.
|
2004-10-30 11:44:06 +00:00
|
|
|
*/
|
2005-02-04 01:29:29 +00:00
|
|
|
TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
|
2004-10-30 11:44:06 +00:00
|
|
|
#endif
|
2005-02-07 03:13:51 +00:00
|
|
|
}
|
2004-10-30 11:44:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* HAVE_LIBPCAP */
|