Fix overriding capture option prefs at the command line

Some capture options can be overridden with command line arguments.
We want those options, like -p, -n/-P, -H, -S, and --update-interval,
to take precedence over preferences, at least until the user saves
preferences or switches profiles (at which point the new settings
will be applied.) That means we have to apply preferences to capture
options before we read most command line arguments.

However, preferences can be altered at the command line, including
the preferences that affect the capture options. So we have to
read the command line arguments that alter preferences after
reading preferences (which has to be after reading command line
arguments that control what preferences are read, like the
configuration profile), but before applying preferences to the
capture options.

Add a new "process some command line options" function that only
gets the command line options that override preferences. Final
interleaved command line / preference / capture options sequence:

1. Read command line arguments that affect what preferences to read
2. Initialize capture options to default value
3. Read preferences
4. Read command line arguments that affect value of already read
   preferences
5. Apply preferences to capture options
6. Read other command line arguments, set capture options final values
7. Apply other preferences

Fix #14549
This commit is contained in:
John Thacker 2023-11-15 21:12:47 -05:00
parent 9a28224e93
commit c25e0f9084
4 changed files with 115 additions and 54 deletions

View File

@ -396,6 +396,86 @@ void commandline_early_options(int argc, char *argv[])
#endif
}
void commandline_override_prefs(int argc, char *argv[], gboolean opt_reset)
{
int opt;
/*
* To reset the options parser, set ws_optreset to 1 and set ws_optind to 1.
*
* Ignore errors and keep ws_opterr as 0; error messages will be printed
* later by command_other_options()
*/
if (opt_reset) {
ws_optreset = 1;
ws_optind = 1;
ws_opterr = 0;
}
/* Initialize with default values */
global_commandline_info.user_opts = NULL;
while ((opt = ws_getopt_long(argc, argv, optstring, long_options, NULL)) != -1) {
switch (opt) {
case 'o': /* Override preference from command line */
{
char *errmsg = NULL;
switch (prefs_set_pref(ws_optarg, &errmsg)) {
case PREFS_SET_OK:
global_commandline_info.user_opts =
g_slist_prepend(global_commandline_info.user_opts,
g_strdup(ws_optarg));
break;
case PREFS_SET_SYNTAX_ERR:
cmdarg_err("Invalid -o flag \"%s\"%s%s", ws_optarg,
errmsg ? ": " : "", errmsg ? errmsg : "");
g_free(errmsg);
exit_application(1);
break;
case PREFS_SET_NO_SUCH_PREF:
/* not a preference, might be a recent setting */
switch (recent_set_arg(ws_optarg)) {
case PREFS_SET_OK:
break;
case PREFS_SET_SYNTAX_ERR:
/* shouldn't happen, checked already above */
cmdarg_err("Invalid -o flag \"%s\"", ws_optarg);
exit_application(1);
break;
case PREFS_SET_NO_SUCH_PREF:
case PREFS_SET_OBSOLETE:
cmdarg_err("-o flag \"%s\" specifies unknown preference/recent value",
ws_optarg);
exit_application(1);
break;
default:
ws_assert_not_reached();
}
break;
case PREFS_SET_OBSOLETE:
cmdarg_err("-o flag \"%s\" specifies obsolete preference",
ws_optarg);
exit_application(1);
break;
default:
ws_assert_not_reached();
}
break;
}
default:
case '?': /* Ignore errors - the "real" scan will catch them. */
break;
}
}
/* Since we prepended each option when processing `-o`, reverse the list
* in case the order of options becomes meaningful.
*/
global_commandline_info.user_opts = g_slist_reverse(global_commandline_info.user_opts);
}
void commandline_other_options(int argc, char *argv[], gboolean opt_reset)
{
int opt;
@ -446,7 +526,6 @@ void commandline_other_options(int argc, char *argv[], gboolean opt_reset)
global_commandline_info.capture_comments = NULL;
#endif
global_commandline_info.full_screen = FALSE;
global_commandline_info.user_opts = NULL;
while ((opt = ws_getopt_long(argc, argv, optstring, long_options, NULL)) != -1) {
switch (opt) {
@ -533,51 +612,8 @@ void commandline_other_options(int argc, char *argv[], gboolean opt_reset)
#endif
break;
case 'o': /* Override preference from command line */
{
char *errmsg = NULL;
switch (prefs_set_pref(ws_optarg, &errmsg)) {
case PREFS_SET_OK:
global_commandline_info.user_opts =
g_slist_prepend(global_commandline_info.user_opts,
g_strdup(ws_optarg));
break;
case PREFS_SET_SYNTAX_ERR:
cmdarg_err("Invalid -o flag \"%s\"%s%s", ws_optarg,
errmsg ? ": " : "", errmsg ? errmsg : "");
g_free(errmsg);
exit_application(1);
break;
case PREFS_SET_NO_SUCH_PREF:
/* not a preference, might be a recent setting */
switch (recent_set_arg(ws_optarg)) {
case PREFS_SET_OK:
break;
case PREFS_SET_SYNTAX_ERR:
/* shouldn't happen, checked already above */
cmdarg_err("Invalid -o flag \"%s\"", ws_optarg);
exit_application(1);
break;
case PREFS_SET_NO_SUCH_PREF:
case PREFS_SET_OBSOLETE:
cmdarg_err("-o flag \"%s\" specifies unknown preference/recent value",
ws_optarg);
exit_application(1);
break;
default:
ws_assert_not_reached();
}
break;
case PREFS_SET_OBSOLETE:
cmdarg_err("-o flag \"%s\" specifies obsolete preference",
ws_optarg);
exit_application(1);
break;
default:
ws_assert_not_reached();
}
/* Pref overrides were already processed just ignore them this time*/
break;
}
case 'P':
/* Path settings were already processed just ignore them this time*/
break;
@ -650,11 +686,6 @@ void commandline_other_options(int argc, char *argv[], gboolean opt_reset)
}
}
/* Since we prepended each option when processing `-o`, reverse the list
* in case the order of options becomes meaningful.
*/
global_commandline_info.user_opts = g_slist_reverse(global_commandline_info.user_opts);
if (!arg_error) {
argc -= ws_optind;
argv += ws_optind;

View File

@ -48,6 +48,8 @@ typedef struct commandline_param_info
} commandline_param_info_t;
extern void commandline_override_prefs(int argc, char *argv[], gboolean opt_reset);
extern void commandline_other_options(int argc, char *argv[], gboolean opt_reset);
extern void commandline_options_drop(const char *module_name, const char *pref_name);

View File

@ -806,9 +806,24 @@ int main(int argc, char *qt_argv[])
ws_log(LOG_DOMAIN_MAIN, LOG_LEVEL_INFO, "Calling module preferences, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
#endif
/* Read the preferences, but don't apply them yet. */
global_commandline_info.prefs_p = ls_app.readConfigurationFiles(false);
/* Now get our args */
/* Now let's see if any of preferences were overridden at the command
* line, and store them. We have to do this before applying the
* preferences to the capture options.
*/
commandline_override_prefs(argc, argv, TRUE);
/* Some of the preferences affect the capture options. Apply those
* before getting the other command line arguments, which can also
* affect the capture options. The command line arguments should be
* applied last to take precedence (at least until the user saves
* preferences, or switches profiles.)
*/
prefs_to_capture_opts();
/* Now get our remaining args */
commandline_other_options(argc, argv, TRUE);
/* Convert some command-line parameters to QStrings */
@ -910,7 +925,6 @@ int main(int argc, char *qt_argv[])
ws_log(LOG_DOMAIN_MAIN, LOG_LEVEL_INFO, "Calling prefs_apply_all, elapsed time %" G_GUINT64_FORMAT " us \n", g_get_monotonic_time() - start_time);
#endif
prefs_apply_all();
prefs_to_capture_opts();
lwApp->emitAppSignal(LograyApplication::PreferencesChanged);
#ifdef HAVE_LIBPCAP

View File

@ -857,9 +857,24 @@ int main(int argc, char *qt_argv[])
ws_log(LOG_DOMAIN_MAIN, LOG_LEVEL_INFO, "Calling module preferences, elapsed time %" PRIu64 " us \n", g_get_monotonic_time() - start_time);
#endif
/* Read the preferences, but don't apply them yet. */
global_commandline_info.prefs_p = ws_app.readConfigurationFiles(false);
/* Now get our args */
/* Now let's see if any of preferences were overridden at the command
* line, and store them. We have to do this before applying the
* preferences to the capture options.
*/
commandline_override_prefs(argc, argv, TRUE);
/* Some of the preferences affect the capture options. Apply those
* before getting the other command line arguments, which can also
* affect the capture options. The command line arguments should be
* applied last to take precedence (at least until the user saves
* preferences, or switches profiles.)
*/
prefs_to_capture_opts();
/* Now get our remaining args */
commandline_other_options(argc, argv, TRUE);
/* Convert some command-line parameters to QStrings */
@ -957,7 +972,6 @@ int main(int argc, char *qt_argv[])
#endif
splash_update(RA_PREFERENCES_APPLY, NULL, NULL);
prefs_apply_all();
prefs_to_capture_opts();
wsApp->emitAppSignal(WiresharkApplication::PreferencesChanged);
#ifdef HAVE_LIBPCAP