Windows: Store "gui.console_open" in the Windows registry

This removes the last dependency of the logging subsystem on the
preferences module. The latter is started much later than the former
and this is an issue.

The Windows-only preference "gui.console_open" is stored in the
registry as HKEY_LOCAL_USER\Software\Wireshark\ConsoleOpen. The semantics
are exactly the same. The preference is read by the logging subsystem
for initialization and then again by the preferences (read/write) so
the user can configure it as before.

The code to store the preference also in the preferences file was
kept, for backward compatibility and because it is not incompatible
with using the Registry concurrently.

The elimination of the prefs dependency also allows moving the Windows
console logic to wsutil and add the functionality to wslog directly,
thereby eliminating the superfluous Wireshark/Logray custom log handler.

To be able to read the ws_log_console_open global variable from
libwireshark it becomes necessary to add a new export macro
symbol called WSUTIL_EXPORT.
This commit is contained in:
João Valverde 2022-10-06 06:43:30 +01:00
parent 44d1cc6d4a
commit a19834b98c
17 changed files with 207 additions and 141 deletions

View File

@ -1910,7 +1910,6 @@ feature_summary(WHAT ALL)
# Should this be part of libui?
if(WIN32)
set(PLATFORM_UI_SRC
ui/win32/console_win32.cpp
ui/win32/file_dlg_win32.cpp
)
set(PLATFORM_UI_RC_FILES

View File

@ -16,6 +16,9 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef _WIN32
#include <windows.h>
#endif
#include <glib.h>
@ -45,6 +48,9 @@
#include "epan/wmem_scopes.h"
#include <epan/stats_tree.h>
#define CURRENT_USER_KEY "Software\\Wireshark"
#define CONSOLE_OPEN_KEY "ConsoleOpen"
/*
* Module alias.
*/
@ -94,9 +100,9 @@ static int mgcp_udp_port_count;
e_prefs prefs;
static const enum_val_t gui_console_open_type[] = {
{"NEVER", "NEVER", console_open_never},
{"AUTOMATIC", "AUTOMATIC", console_open_auto},
{"ALWAYS", "ALWAYS", console_open_always},
{"NEVER", "NEVER", LOG_CONSOLE_OPEN_NEVER},
{"AUTOMATIC", "AUTOMATIC", LOG_CONSOLE_OPEN_AUTO},
{"ALWAYS", "ALWAYS", LOG_CONSOLE_OPEN_ALWAYS},
{NULL, NULL, -1}
};
@ -3030,13 +3036,15 @@ prefs_register_modules(void)
gui_module = prefs_register_module(NULL, "gui", "User Interface",
"User Interface", &gui_callback, FALSE);
/* gui.console_open is placed first in the list so that any problems encountered
* in the following prefs can be displayed in the console window.
/*
* gui.console_open is stored in the registry in addition to the
* preferences file. It is also read independently by ws_log_init()
* for early log initialization of the console.
*/
prefs_register_enum_preference(gui_module, "console_open",
"Open a console window",
"Open a console window (Windows only)",
(gint*)(void*)(&prefs.gui_console_open), gui_console_open_type, FALSE);
&ws_log_console_open, gui_console_open_type, FALSE);
prefs_register_obsolete_preference(gui_module, "scrollbar_on_right");
prefs_register_obsolete_preference(gui_module, "packet_list_sel_browse");
@ -4119,7 +4127,6 @@ pre_init_prefs(void)
prefs.gui_geometry_save_position = TRUE;
prefs.gui_geometry_save_size = TRUE;
prefs.gui_geometry_save_maximized= TRUE;
prefs.gui_console_open = console_open_never;
prefs.gui_fileopen_style = FO_STYLE_LAST_OPENED;
prefs.gui_recent_df_entries_max = 10;
prefs.gui_recent_files_count_max = 10;
@ -4353,6 +4360,35 @@ prefs_reset(void)
wmem_tree_foreach(prefs_modules, reset_module_prefs, NULL);
}
#ifdef _WIN32
static void
read_registry(void)
{
HKEY hTestKey;
DWORD data;
DWORD data_size = sizeof(DWORD);
DWORD ret;
ret = RegOpenKeyExA(HKEY_CURRENT_USER, CURRENT_USER_KEY, 0, KEY_READ, &hTestKey);
if (ret != ERROR_SUCCESS && ret != ERROR_FILE_NOT_FOUND) {
ws_noisy("Cannot open HKCU "CURRENT_USER_KEY": 0x%lx", ret);
return;
}
ret = RegQueryValueExA(hTestKey, CONSOLE_OPEN_KEY, NULL, NULL, (LPBYTE)&data, &data_size);
if (ret == ERROR_SUCCESS) {
ws_log_console_open = (enum ws_log_console_pref)data;
ws_noisy("Got "CONSOLE_OPEN_KEY" from Windows registry: %d", ws_log_console_open);
}
else if (ret != ERROR_FILE_NOT_FOUND) {
ws_noisy("Error reading registry key "CONSOLE_OPEN_KEY": 0x%lx", ret);
}
RegCloseKey(hTestKey);
}
#endif
/* Read the preferences file, fill in "prefs", and return a pointer to it.
If we got an error (other than "it doesn't exist") we report it through
@ -4369,6 +4405,10 @@ read_prefs(void)
init_prefs();
#ifdef _WIN32
read_registry();
#endif
/*
* If we don't already have the pathname of the global preferences
* file, construct it. Then, in either case, try to open the file.
@ -6726,6 +6766,37 @@ write_module_prefs(module_t *module, gpointer user_data)
return 0;
}
#ifdef _WIN32
static void
write_registry(void)
{
HKEY hTestKey;
DWORD data;
DWORD data_size;
DWORD ret;
ret = RegCreateKeyExA(HKEY_CURRENT_USER, CURRENT_USER_KEY, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
&hTestKey, NULL);
if (ret != ERROR_SUCCESS) {
ws_noisy("Cannot open HKCU "CURRENT_USER_KEY": 0x%lx", ret);
return;
}
data = ws_log_console_open;
data_size = sizeof(DWORD);
ret = RegSetValueExA(hTestKey, CONSOLE_OPEN_KEY, 0, REG_DWORD, (const BYTE *)&data, data_size);
if (ret == ERROR_SUCCESS) {
ws_noisy("Wrote "CONSOLE_OPEN_KEY" to Windows registry: 0x%lu", data);
}
else {
ws_noisy("Error writing registry key "CONSOLE_OPEN_KEY": 0x%lx", ret);
}
RegCloseKey(hTestKey);
}
#endif
/* Write out "prefs" to the user's preferences file, and return 0.
If the preferences file path is NULL, write to stdout.
@ -6742,6 +6813,10 @@ write_prefs(char **pf_path_return)
/* Needed for "-G defaultprefs" */
init_prefs();
#ifdef _WIN32
write_registry();
#endif
/* To do:
* - Split output lines longer than MAX_VAL_LEN
* - Create a function for the preference directory check/creation

View File

@ -102,15 +102,6 @@ typedef enum {
layout_pane_content_pdiagram,
} layout_pane_content_e;
/*
* open console behaviour (win32 only)
*/
typedef enum {
console_open_never,
console_open_auto,
console_open_always
} console_open_e;
/*
* Places version information will show up
*/
@ -166,7 +157,6 @@ typedef struct _e_prefs {
gboolean gui_geometry_save_position;
gboolean gui_geometry_save_size;
gboolean gui_geometry_save_maximized;
console_open_e gui_console_open;
guint gui_recent_df_entries_max;
guint gui_recent_files_count_max;
guint gui_fileopen_style;

View File

@ -186,6 +186,22 @@
*/
#define WS_DLL_PUBLIC WS_DLL_PUBLIC_DEF extern
/*
* This is necessary to export symbols from wsutil to another DLL
* (not an executable) using MSVC.
*/
#ifdef _MSC_VER
# ifdef BUILD_WSUTIL
# define WSUTIL_EXPORT __declspec(dllexport) extern
# else
# define WSUTIL_EXPORT __declspec(dllimport) extern
# endif
#else /* _MSC_VER */
# define WSUTIL_EXPORT WS_DLL_PUBLIC
#endif /* _MSC_VER */
#endif /* SYMBOL_EXPORT_H */
/*

View File

@ -16,6 +16,8 @@ local function test(name, ...)
end
end
local console_open
--------------------------
-- Note: This tests expects some specific default values
@ -32,7 +34,10 @@ test("get_preference-unknown-4",get_preference("ugi.ask_unsaved") == nil)
test("get_preference-uint-0",get_preference("gui.fileopen.preview") == 3)
test("get_preference-bool-0",get_preference("gui.ask_unsaved") == true)
test("get_preference-bool-1",get_preference("gui.interfaces_show_hidden") == false)
test("get_preference-enum-1",get_preference("gui.console_open") == "NEVER")
-- gui.console_open is persistent (in the Windows registry) and for that
-- reason does not have a default value.
console_open = get_preference("gui.console_open")
test("get_preference-enum-0",console_open == "NEVER" or console_open == "AUTOMATIC" or console_open == "ALWAYS")
test("get_preference-string-0",get_preference("gui.window_title") == "")
test("get_preference-range-0",get_preference("http.tls.port") == "443")
success = pcall(get_preference, "user_dlt.encaps_table")
@ -71,12 +76,8 @@ success = pcall(set_preference,"gui.console_open")
test("set_preference-enum-0", not success)
success = pcall(set_preference,"gui.console_open",true)
test("set_preference-enum-1", not success)
test("set_preference-enum-2",set_preference("gui.console_open","NEVER") == false)
test("set_preference-enum-3",set_preference("gui.console_open","AUTOMATIC") == true)
test("set_preference-enum-3-get",get_preference("gui.console_open") == "AUTOMATIC")
test("set_preference-enum-4",set_preference("gui.console_open","ALWAYS") == true)
test("set_preference-enum-5",set_preference("gui.console_open","unknown") == false)
test("set_preference-enum-6",set_preference("gui.console_open",42) == false)
-- false means unchanged
test("set_preference-enum-2",set_preference("gui.console_open",console_open) == false)
success = pcall(set_preference,"gui.window_title")
test("set_preference-string-0", not success)
success = pcall(set_preference,"gui.window_title",true)
@ -112,8 +113,6 @@ test("reset_preference-uint-0",reset_preference("gui.fileopen.preview") == true)
test("reset_preference-uint-0-get",get_preference("gui.fileopen.preview") == 3)
test("reset_preference-bool-0",reset_preference("gui.ask_unsaved") == true)
test("reset_preference-bool-0-get",get_preference("gui.ask_unsaved") == true)
test("reset_preference-enum-0",reset_preference("gui.console_open") == true)
test("reset_preference-enum-0-get",get_preference("gui.console_open") == "NEVER")
test("reset_preference-string-0",reset_preference("gui.window_title") == true)
test("reset_preference-string-0-get",get_preference("gui.window_title") == "")
test("reset_preference-range-0",reset_preference("http.tls.port") == true)

View File

@ -14,7 +14,6 @@ set(NONGENERATED_UI_SRC
clopts_common.c
cmdarg_err.c
commandline.c
console.c
decode_as_utils.c
dissect_opts.c
export_pdu_ui_utils.c

View File

@ -25,6 +25,9 @@
#include <ui/exit_codes.h>
#include <wsutil/filesystem.h>
#include <wsutil/ws_assert.h>
#ifdef _WIN32
#include <wsutil/console_win32.h>
#endif
#include <epan/ex-opt.h>
#include <epan/packet.h>
@ -36,7 +39,6 @@
#include "capture_opts.h"
#include "persfilepath_opt.h"
#include "preference_utils.h"
#include "console.h"
#include "recent.h"
#include "decode_as_utils.h"

View File

@ -1,51 +0,0 @@
/* console.c
* Console log handler routines
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#include <stdio.h>
#include "epan/prefs.h"
#include "wsutil/time_util.h"
#include <wsutil/ws_assert.h>
#include "console.h"
void
console_log_writer(const char *domain, enum ws_log_level level,
struct timespec timestamp,
const char *file, long line, const char *func,
const char *user_format, va_list user_ap,
void *user_data _U_)
{
gboolean fatal = level == LOG_LEVEL_ERROR;
#ifdef _WIN32
if (prefs.gui_console_open != console_open_never || fatal) {
/* the user wants a console or the application will terminate immediately */
create_console();
}
#else
(void)fatal;
#endif /* _WIN32 */
ws_log_console_writer(domain, level, timestamp, file, line, func,
user_format, user_ap);
#ifdef _WIN32
if (fatal) {
/* wait for a key press before the following error handler will terminate the program
this way the user at least can read the error message */
printf("\n\nPress any key to exit\n");
_getch();
}
#endif /* _WIN32 */
}

View File

@ -1,40 +0,0 @@
/** @file
*
* Console log handler routines
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef __CONSOLE_H__
#define __CONSOLE_H__
#ifdef _WIN32 /* Needed for console I/O */
#include <fcntl.h>
#include <conio.h>
#include <ui/win32/console_win32.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include <wsutil/wslog.h>
/** The GUI log writer.
*/
void
console_log_writer(const char *domain, enum ws_log_level level,
struct timespec timestamp,
const char *file, long line, const char *func,
const char *user_format, va_list user_ap,
void *user_data);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __CONSOLE_H__ */

View File

@ -19,7 +19,7 @@
#include <tchar.h>
#include <wchar.h>
#include <shellapi.h>
#include "ui/win32/console_win32.h"
#include <wsutil/console_win32.h>
#endif
#include <ui/clopts_common.h>
@ -64,7 +64,6 @@
#include "epan/srt_table.h"
#include "ui/alert_box.h"
#include "ui/console.h"
#include "ui/iface_lists.h"
#include "ui/language.h"
#include "ui/persfilepath_opt.h"
@ -484,7 +483,7 @@ int main(int argc, char *qt_argv[])
cmdarg_err_init(logray_cmdarg_err, logray_cmdarg_err_cont);
/* Initialize log handler early so we can have proper logging during startup. */
ws_log_init_with_writer("logray", console_log_writer, vcmdarg_err);
ws_log_init("logray", vcmdarg_err);
/* For backward compatibility with GLib logging and Wireshark 3.4. */
ws_log_console_writer_set_use_stdout(TRUE);

View File

@ -19,7 +19,7 @@
#include <tchar.h>
#include <wchar.h>
#include <shellapi.h>
#include "ui/win32/console_win32.h"
#include <wsutil/console_win32.h>
#endif
#include <ui/clopts_common.h>
@ -64,7 +64,6 @@
#include "epan/srt_table.h"
#include "ui/alert_box.h"
#include "ui/console.h"
#include "ui/iface_lists.h"
#include "ui/language.h"
#include "ui/persfilepath_opt.h"
@ -486,7 +485,7 @@ int main(int argc, char *qt_argv[])
cmdarg_err_init(wireshark_cmdarg_err, wireshark_cmdarg_err_cont);
/* Initialize log handler early so we can have proper logging during startup. */
ws_log_init_with_writer("wireshark", console_log_writer, vcmdarg_err);
ws_log_init("wireshark", vcmdarg_err);
/* For backward compatibility with GLib logging and Wireshark 3.4. */
ws_log_console_writer_set_use_stdout(TRUE);

View File

@ -63,7 +63,6 @@
#include "wsutil/utf8_entities.h"
#ifdef _WIN32
# include "ui/win32/console_win32.h"
# include "wsutil/file_util.h"
# include <QMessageBox>
# include <QSettings>
@ -1073,13 +1072,6 @@ _e_prefs *MainApplication::readConfigurationFiles(bool reset)
/* Load libwireshark settings from the current profile. */
prefs_p = epan_load_settings();
#ifdef _WIN32
/* if the user wants a console to be always there, well, we should open one for him */
if (prefs_p->gui_console_open == console_open_always) {
create_console();
}
#endif
/* Read the capture filter file. */
read_filter_list(CFILTER_LIST);

View File

@ -142,6 +142,12 @@ set(WSUTIL_COMMON_FILES
xtea.c
)
if(WIN32)
list(APPEND WSUTIL_COMMON_FILES
console_win32.c
)
endif()
if(ENABLE_PLUGINS)
list(APPEND WSUTIL_COMMON_FILES
plugins.c
@ -259,9 +265,13 @@ add_library(wsutil
${CMAKE_BINARY_DIR}/resources/libwsutil.rc
)
target_compile_definitions(wsutil PRIVATE
WS_BUILD_DLL
BUILD_WSUTIL
)
set_target_properties(wsutil PROPERTIES
PREFIX "lib"
COMPILE_DEFINITIONS "WS_BUILD_DLL"
LINK_FLAGS "${WS_LINK_FLAGS}"
VERSION "0.0.0" SOVERSION 0
FOLDER "DLLs"

View File

@ -12,6 +12,8 @@
#ifndef __CONSOLE_WIN32_H__
#define __CONSOLE_WIN32_H__
#include <wireshark.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
@ -25,35 +27,42 @@ extern "C" {
/** Create Windows console.
*
*/
WS_DLL_PUBLIC
void create_console(void);
/** Connect to stdio if available.
*
*/
WS_DLL_PUBLIC
void restore_pipes(void);
/** Destroy Windows console.
*
*/
WS_DLL_PUBLIC
void destroy_console(void);
/** Set console wait. GTK+ only.
* @param console_wait set/no set console wait
*/
WS_DLL_PUBLIC
void set_console_wait(gboolean console_wait);
/** get console wait
* @return set/no set console wait
*/
WS_DLL_PUBLIC
gboolean get_console_wait(void);
/** Set stdin capture.
* @param console_wait set/no stdin_capture
*/
WS_DLL_PUBLIC
void set_stdin_capture(gboolean set_stdin_capture);
/** get stdin caputre
* @return set/no set stdin_capture
*/
WS_DLL_PUBLIC
gboolean get_stdin_capture(void);
#endif/* _WIN32 */

View File

@ -29,12 +29,16 @@
#ifdef _WIN32
#include <process.h>
#include <windows.h>
#include <conio.h>
#endif
#include "file_util.h"
#include "time_util.h"
#include "to_str.h"
#include "strtoi.h"
#ifdef _WIN32
#include "console_win32.h"
#endif
#ifndef WS_DISABLE_ASSERT
@ -126,6 +130,8 @@ static enum ws_log_level fatal_log_level = LOG_LEVEL_ERROR;
static bool init_complete = false;
int ws_log_console_open = LOG_CONSOLE_OPEN_NEVER;
static void print_err(void (*vcmdarg_err)(const char *, va_list ap),
int exit_failure,
@ -783,6 +789,30 @@ static void glib_log_handler(const char *domain, GLogLevelFlags flags,
}
#ifdef _WIN32
static void load_registry()
{
LONG lResult;
DWORD ptype;
DWORD data;
DWORD data_size = sizeof(DWORD);
lResult = RegGetValueA(HKEY_CURRENT_USER,
"Software\\Wireshark",
"OpenConsole",
RRF_RT_REG_DWORD,
&ptype,
&data,
&data_size);
if (lResult != ERROR_SUCCESS || ptype != REG_DWORD) {
return;
}
ws_log_console_open = (enum ws_log_console_pref)data;
}
#endif
/*
* We can't write to stderr in ws_log_init() because dumpcap uses stderr
* to communicate with the parent and it will block. We have to use
@ -811,6 +841,15 @@ void ws_log_init(const char *progname,
g_log_set_handler("GLib", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL,
glib_log_handler, NULL);
#ifdef _WIN32
load_registry(vcmdarg_err);
/* if the user wants a console to be always there, well, we should open one for him */
if (ws_log_console_open == LOG_CONSOLE_OPEN_ALWAYS) {
create_console();
}
#endif
atexit(ws_log_cleanup);
/* Configure from environment. */
@ -1013,9 +1052,26 @@ static void log_write_dispatch(const char *domain, enum ws_log_level level,
{
struct timespec tstamp;
struct tm *cookie = NULL;
bool fatal_event = false;
if (level >= fatal_log_level && level != LOG_LEVEL_ECHO) {
fatal_event = true;
}
else if (fatal_filter != NULL) {
if (filter_contains(fatal_filter, domain) && fatal_filter->positive) {
fatal_event = true;
}
}
ws_clock_get_realtime(&tstamp);
#ifdef _WIN32
if (fatal_event || ws_log_console_open != LOG_CONSOLE_OPEN_NEVER) {
/* the user wants a console or the application will terminate immediately */
create_console();
}
#endif /* _WIN32 */
if (custom_log) {
va_list user_ap_copy;
@ -1040,14 +1096,17 @@ static void log_write_dispatch(const char *domain, enum ws_log_level level,
user_format, user_ap);
}
if (level >= fatal_log_level && level != LOG_LEVEL_ECHO) {
abort();
#ifdef _WIN32
if (fatal_event) {
/* wait for a key press before the following error handler will terminate the program
this way the user at least can read the error message */
printf("\n\nPress any key to exit\n");
_getch();
}
#endif /* _WIN32 */
if (fatal_filter != NULL) {
if (filter_contains(fatal_filter, domain) && fatal_filter->positive) {
abort();
}
if (fatal_event) {
abort();
}
}

View File

@ -46,6 +46,15 @@
extern "C" {
#endif /* __cplusplus */
enum ws_log_console_pref {
LOG_CONSOLE_OPEN_NEVER,
LOG_CONSOLE_OPEN_AUTO, /* On demand. */
LOG_CONSOLE_OPEN_ALWAYS, /* Open during startup. */
};
WSUTIL_EXPORT
int ws_log_console_open;
/** Callback for registering a log writer. */
typedef void (ws_log_writer_cb)(const char *domain, enum ws_log_level level,