summaryrefslogtreecommitdiff
path: root/mysys/my_getopt.c
diff options
context:
space:
mode:
authorMarc Alff <marc.alff@oracle.com>2010-08-25 18:59:28 -0600
committerMarc Alff <marc.alff@oracle.com>2010-08-25 18:59:28 -0600
commit4c2de881de86cbb0d5d0abb0fadfb996048849a6 (patch)
treef649b6b130d90c3fdaa4e043bca118a69c38828f /mysys/my_getopt.c
parentd2210981e3051fa0d12d20b09dd6a6524f3232d0 (diff)
downloadmariadb-git-4c2de881de86cbb0d5d0abb0fadfb996048849a6.tar.gz
Bug#55873 short startup options do not work in 5.5
Before this fix, the server did not recognize 'short' (as in -a) options but only 'long' (as in --ansi) options in the startup command line, due to earlier changes in 5.5 introduced for the performance schema. The root cause is that handle_options() did not honor the my_getopt_skip_unknown flag when parsing 'short' options. The fix changes handle_options(), so that my_getopt_skip_unknown is honored in all cases. Note that there are limitations to this, see the added doxygen documentation in handle_options(). The current usage of handle_options() by the server to parse early performance schema options fits within the limitations. This has been enforced by an assert for PARSE_EARLY options, for safety.
Diffstat (limited to 'mysys/my_getopt.c')
-rw-r--r--mysys/my_getopt.c100
1 files changed, 93 insertions, 7 deletions
diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c
index 1c5bf0b6b1c..5689e0bafb5 100644
--- a/mysys/my_getopt.c
+++ b/mysys/my_getopt.c
@@ -98,6 +98,49 @@ void my_getopt_register_get_addr(my_getopt_value func_addr)
matches with one of the options in struct 'my_option'.
Check that option was given an argument if it requires one
Call the optional 'get_one_option()' function once for each option.
+
+ Note that handle_options() can be invoked multiple times to
+ parse a command line in several steps.
+ In this case, use the global flag @c my_getopt_skip_unknown to indicate
+ that options unknown in the current step should be preserved in the
+ command line for later parsing in subsequent steps.
+
+ For 'long' options (--a_long_option), @c my_getopt_skip_unknown is
+ fully supported. Command line parameters such as:
+ - "--a_long_option"
+ - "--a_long_option=value"
+ - "--a_long_option value"
+ will be preserved as is when the option is not known.
+
+ For 'short' options (-S), support for @c my_getopt_skip_unknown
+ comes with some limitation, because several short options
+ can also be specified together in the same command line argument,
+ as in "-XYZ".
+
+ The first use case supported is: all short options are declared.
+ handle_options() will be able to interpret "-XYZ" as one of:
+ - an unknown X option
+ - "-X -Y -Z", three short options with no arguments
+ - "-X -YZ", where Y is a short option with argument Z
+ - "-XYZ", where X is a short option with argument YZ
+ based on the full short options specifications.
+
+ The second use case supported is: no short option is declared.
+ handle_options() will reject "-XYZ" as unknown, to be parsed later.
+
+ The use case that is explicitly not supported is to provide
+ only a partial list of short options to handle_options().
+ This function can not be expected to extract some option Y
+ in the middle of the string "-XYZ" in these conditions,
+ without knowing if X will be declared an option later.
+
+ Note that this limitation only impacts parsing of several
+ short options from the same command line argument,
+ as in "mysqld -anW5".
+ When each short option is properly separated out in the command line
+ argument, for example in "mysqld -a -n -w5", the code would actually
+ work even with partial options specs given at each stage.
+
@param [in, out] argc command line options (count)
@param [in, out] argv command line options (values)
@param [in] longopts descriptor of all valid options
@@ -464,14 +507,57 @@ int handle_options(int *argc, char ***argv,
}
if (!opt_found)
{
- if (my_getopt_print_errors)
- my_getopt_error_reporter(ERROR_LEVEL,
- "%s: unknown option '-%c'",
- my_progname, *optend);
- return EXIT_UNKNOWN_OPTION;
+ if (my_getopt_skip_unknown)
+ {
+ /*
+ We are currently parsing a single argv[] argument
+ of the form "-XYZ", and parsing is done in multiple phases.
+ One or the argument found is not an option.
+ */
+ if (optend == cur_arg)
+ {
+ /*
+ The first argument, "-X", is not an option
+ In this case, the entire argument "-XYZ" is rejected
+ from this phase, and preserved as is for later parsing.
+ */
+ (*argv)[argvpos++]= *pos;
+ }
+ else
+ {
+ /*
+ We are in the middle of an "-XYZ" string already,
+ "-X" has already been parsed, and "Y" (pointed by optend)
+ is not an option.
+ Hack the string "-XYZ" to make a "-YZ" substring in it,
+ and push that to the next parsing phase.
+ */
+ DBUG_ASSERT(optend > *pos);
+ DBUG_ASSERT(optend > cur_arg);
+ DBUG_ASSERT(optend <= *pos + strlen(*pos));
+ DBUG_ASSERT(*optend);
+ optend--;
+ optend[0]= '-'; /* replace 'X' by '-' */
+ (*argv)[argvpos++]= optend;
+ }
+ /*
+ Do not continue to parse at the current "-XYZ" argument,
+ skip to the next argv[] argument instead.
+ */
+ optend= (char*) " ";
+ }
+ else
+ {
+ if (my_getopt_print_errors)
+ my_getopt_error_reporter(ERROR_LEVEL,
+ "%s: unknown option '-%c'",
+ my_progname, *optend);
+ return EXIT_UNKNOWN_OPTION;
+ }
}
}
- (*argc)--; /* option handled (short), decrease argument count */
+ if (opt_found)
+ (*argc)--; /* option handled (short), decrease argument count */
continue;
}
if ((error= setval(optp, value, argument, set_maximum_value)))
@@ -479,7 +565,7 @@ int handle_options(int *argc, char ***argv,
if (get_one_option && get_one_option(optp->id, optp, argument))
return EXIT_UNSPECIFIED_ERROR;
- (*argc)--; /* option handled (short or long), decrease argument count */
+ (*argc)--; /* option handled (long), decrease argument count */
}
else /* non-option found */
(*argv)[argvpos++]= cur_arg;