Ensure tshark/wireshark always get good err msgs from dumpcap:

1. Clean up dumpcap 'as a child' err msg handling so that:
   - all err msgs are properly formatted when being sent 
     back to the parent.
   - any log Critical, Warning, etc messages
     are sent back to parent and are properly formatted.
2. Change handling of -w <...> slightly in capture_opts.c
   so that wireshark provides a good error message if
   there is a 'write permissions' issue on the file.
   (Previously the error popup said only 
   "Child exited with status 2").
   This fixes bug #2288.

Add some conditionalized DEBUG_CHILD_DUMPCAP code for
   dumpcap debug logging to a file.

svn path=/trunk/; revision=24446
This commit is contained in:
Bill Meier 2008-02-23 19:59:38 +00:00
parent e6837f14d4
commit 8d4f01eea7
3 changed files with 114 additions and 42 deletions

View File

@ -911,10 +911,9 @@ static gboolean capture_opts_output_to_pipe(const char *save_file, gboolean *is_
*is_pipe = TRUE;
break;
default: /* couldn't stat it */
cmdarg_err("Error testing whether capture file is a pipe: %s",
strerror(errno));
return 2;
default: /* couldn't stat it */
break; /* ignore: later attempt to open */
/* will generate a nice msg */
}
}
}

View File

@ -291,6 +291,8 @@ sync_pipe_start(capture_options *capture_opts) {
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "We don't know where to find dumpcap.");
return FALSE;
}
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "argv[0]: %s", argv[0]);
argv = sync_pipe_add_arg(argv, &argc, "-i");
argv = sync_pipe_add_arg(argv, &argc, capture_opts->iface);
@ -1105,6 +1107,7 @@ pipe_read_block(int pipe, char *indicator, int len, char *msg) {
return -1;
}
/* XXX If message is "2part", the msg probably won't be sent to debug log correctly */
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
"read %d ok indicator: %c len: %u msg: %s", pipe, *indicator,
len, msg);

146
dumpcap.c
View File

@ -107,6 +107,13 @@
#include "wiretap/libpcap.h"
/*#define DEBUG_DUMPCAP*/
/*#define DEBUG_CHILD_DUMPCAP*/
#ifdef DEBUG_CHILD_DUMPCAP
FILE *debug_log; /* for logging debug messages to */
/* a file if DEBUG_CHILD_DUMPCAP */
/* is defined */
#endif
static gboolean capture_child = FALSE; /* FALSE: standalone call, TRUE: this is an Wireshark capture child */
#ifdef _WIN32
@ -353,9 +360,12 @@ cmdarg_err(const char *fmt, ...)
va_list ap;
if(capture_child) {
/* Print a bare error */
gchar *msg;
/* Generate a 'special format' message back to parent */
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
msg = g_strdup_vprintf(fmt, ap);
sync_pipe_errmsg_to_parent(2, msg, "");
g_free(msg);
va_end(ap);
} else {
va_start(ap, fmt);
@ -375,7 +385,12 @@ cmdarg_err_cont(const char *fmt, ...)
va_list ap;
if(capture_child) {
/* XXX - convert to g_log */
gchar *msg;
va_start(ap, fmt);
msg = g_strdup_vprintf(fmt, ap);
sync_pipe_errmsg_to_parent(2, msg, "");
g_free(msg);
va_end(ap);
} else {
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
@ -483,14 +498,14 @@ relinquish_privs_except_capture(void)
if (started_with_special_privs()) {
print_caps("Pre drop, pre set");
if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) {
perror("prctl()");
cmdarg_err("prctl() fail return: %s", strerror(errno));
}
cap_set_flag(caps, CAP_PERMITTED, cl_len, cap_list, CAP_SET);
cap_set_flag(caps, CAP_INHERITABLE, cl_len, cap_list, CAP_SET);
if (cap_set_proc(caps)) {
perror("capset()");
cmdarg_err("cap_set_proc() fail return: %s", strerror(errno));
}
print_caps("Pre drop, post set");
}
@ -500,7 +515,7 @@ relinquish_privs_except_capture(void)
print_caps("Post drop, pre set");
cap_set_flag(caps, CAP_EFFECTIVE, cl_len, cap_list, CAP_SET);
if (cap_set_proc(caps)) {
perror("capset()");
cmdarg_err("cap_set_proc() fail return: %s", strerror(errno));
}
print_caps("Post drop, post set");
cap_free(caps);
@ -2198,6 +2213,7 @@ main(int argc, char *argv[])
gboolean machine_readable = FALSE;
gboolean print_statistics = FALSE;
int status, run_once_args = 0;
gint i;
#ifdef HAVE_PCAP_REMOTE
#define OPTSTRING_INIT "a:A:b:c:Df:hi:Lm:MprSs:uvw:y:Z:"
@ -2214,6 +2230,61 @@ main(int argc, char *argv[])
char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_WIN32) - 1] =
OPTSTRING_INIT OPTSTRING_WIN32;
#ifdef DEBUG_CHILD_DUMPCAP
if ((debug_log = fopen("dumpcap_debug_log.tmp","w")) == NULL) {
fprintf (stderr, "Unable to open debug log file !\n");
exit (1);
}
#endif
/* Determine if dumpcap is running as a child process by going thru */
/* the command line args to see if a -Z option (which is the */
/* hidden option which indicates that dumpcap has been invoked */
/* from a parent process using a pipe). */
/* "Child" status needs to be determined immediately upon startup so */
/* that any messages generated by dumpcap (eg: during initialization)*/
/* will be formatted properly if being sent back to a parent via */
/* a pipe. */
for (i=1; i<argc; i++) {
if (g_ascii_strcasecmp("-Z", argv[i]) == 0) {
capture_child = TRUE;
#ifdef _WIN32
/* set output pipe to binary mode, to avoid ugly text conversions */
_setmode(2, O_BINARY);
#endif
}
}
/* The default_log_handler will use stdout, which makes trouble in */
/* capture child mode, as it uses stdout for it's sync_pipe. */
/* So: the filtering is done in the console_log_handler and not here.*/
/* We set the log handlers right up front to make sure that any log */
/* messages when running as child will be sent back to the parent */
/* with the correct format. */
log_flags =
G_LOG_LEVEL_ERROR|
G_LOG_LEVEL_CRITICAL|
G_LOG_LEVEL_WARNING|
G_LOG_LEVEL_MESSAGE|
G_LOG_LEVEL_INFO|
G_LOG_LEVEL_DEBUG|
G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
g_log_set_handler(NULL,
log_flags,
console_log_handler, NULL /* user_data */);
g_log_set_handler(LOG_DOMAIN_MAIN,
log_flags,
console_log_handler, NULL /* user_data */);
g_log_set_handler(LOG_DOMAIN_CAPTURE,
log_flags,
console_log_handler, NULL /* user_data */);
g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
log_flags,
console_log_handler, NULL /* user_data */);
#ifdef _WIN32
/* Load wpcap if possible. Do this before collecting the run-time version information */
load_wpcap();
@ -2245,31 +2316,6 @@ main(int argc, char *argv[])
relinquish_privs_except_capture();
#endif
/* the default_log_handler will use stdout, which makes trouble in */
/* capture child mode, as it uses stdout for it's sync_pipe */
/* so do the filtering in the console_log_handler and not here */
log_flags =
G_LOG_LEVEL_ERROR|
G_LOG_LEVEL_CRITICAL|
G_LOG_LEVEL_WARNING|
G_LOG_LEVEL_MESSAGE|
G_LOG_LEVEL_INFO|
G_LOG_LEVEL_DEBUG|
G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
g_log_set_handler(NULL,
log_flags,
console_log_handler, NULL /* user_data */);
g_log_set_handler(LOG_DOMAIN_MAIN,
log_flags,
console_log_handler, NULL /* user_data */);
g_log_set_handler(LOG_DOMAIN_CAPTURE,
log_flags,
console_log_handler, NULL /* user_data */);
g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
log_flags,
console_log_handler, NULL /* user_data */);
/* Set the initial values in the capture_opts. This might be overwritten
by the command line parameters. */
capture_opts_init(capture_opts, NULL);
@ -2475,13 +2521,13 @@ console_log_handler(const char *log_domain, GLogLevelFlags log_level,
const char *message, gpointer user_data _U_)
{
time_t curr;
struct tm *today;
struct tm *today;
const char *level;
gchar *msg;
/* ignore log message, if log_level isn't interesting */
if( !(log_level & G_LOG_LEVEL_MASK & ~(G_LOG_LEVEL_DEBUG|G_LOG_LEVEL_INFO))) {
#ifndef DEBUG_DUMPCAP
#if !defined(DEBUG_DUMPCAP) && !defined(DEBUG_CHILD_DUMPCAP)
return;
#endif
}
@ -2515,19 +2561,43 @@ console_log_handler(const char *log_domain, GLogLevelFlags log_level,
g_assert_not_reached();
}
/* don't use printf (stdout), in child mode we're using stdout for the sync_pipe */
/* Generate the output message */
if(log_level & G_LOG_LEVEL_MESSAGE) {
/* normal user messages without additional infos */
fprintf(stderr, "%s\n", message);
fflush(stderr);
msg = g_strdup_printf("%s\n", message);
} else {
/* info/debug messages with additional infos */
fprintf(stderr, "%02u:%02u:%02u %8s %s %s\n",
msg = g_strdup_printf("%02u:%02u:%02u %8s %s %s\n",
today->tm_hour, today->tm_min, today->tm_sec,
log_domain != NULL ? log_domain : "",
level, message);
}
/* DEBUG & INFO msgs (if we're debugging today) */
#if defined(DEBUG_DUMPCAP) || defined(DEBUG_CHILD_DUMPCAP)
if( !(log_level & G_LOG_LEVEL_MASK & ~(G_LOG_LEVEL_DEBUG|G_LOG_LEVEL_INFO))) {
#ifdef DEBUG_DUMPCAP
fprintf(stderr, "%s", msg);
fflush(stderr);
#endif
#ifdef DEBUG_CHILD_DUMPCAP
fprintf(debug_log, "%s", msg);
fflush(debug_log);
#endif
g_free(msg);
return;
}
#endif
/* ERROR, CRITICAL, WARNING, MESSAGE messages goto stderr or */
/* to parent especially formatted if dumpcap running as child. */
if (capture_child) {
sync_pipe_errmsg_to_parent(2, msg, "");
} else {
fprintf(stderr, "%s", msg);
fflush(stderr);
}
g_free(msg);
}