aboutsummaryrefslogtreecommitdiffstats
path: root/dumpcap.c
diff options
context:
space:
mode:
authorBill Meier <wmeier@newsguy.com>2008-02-23 19:59:38 +0000
committerBill Meier <wmeier@newsguy.com>2008-02-23 19:59:38 +0000
commit8d4f01eea70c59acb0ef18acbc4f5254d4149e9f (patch)
treee87d1ef9d38dc5f7c31485b5f2c073d9f04188cc /dumpcap.c
parente6837f14d463998df7b8cb71d4408e60b8a73fb0 (diff)
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
Diffstat (limited to 'dumpcap.c')
-rw-r--r--dumpcap.c146
1 files changed, 108 insertions, 38 deletions
diff --git a/dumpcap.c b/dumpcap.c
index 9e2d15e5d9..88732b89e8 100644
--- a/dumpcap.c
+++ b/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);
}