forked from osmocom/wireshark
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:
parent
e6837f14d4
commit
8d4f01eea7
|
@ -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 */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
146
dumpcap.c
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue