Commit 2c4ba79e authored by He Zhenxing's avatar He Zhenxing

Backport BUG#25192 Using relay-log and relay-log-index without values produces unexpected results.

Options loaded from config files were added before command line
arguments, and they were parsed together, which could interprete
the following:
option-a
option-b
as --option-a=--option-b if 'option-a' requires a value, and 
caused confusing.

Because all options that requires a value are always given in
the form '--option=value', so it's an error if there is no 
'=value' part for such an option read from config file.

This patch added a separator to separate the arguments from 
config files and that from command line, so that they can be
handled differently. And report an error for options loaded
from config files that requires a value and is not given in the
form '--option=value'.
parent 96b1e590
...@@ -192,7 +192,8 @@ int main(int argc, char **argv) ...@@ -192,7 +192,8 @@ int main(int argc, char **argv)
} }
for (argument= arguments+1 ; *argument ; argument++) for (argument= arguments+1 ; *argument ; argument++)
puts(*argument); if (*argument != args_separator) /* skip arguments separator */
puts(*argument);
my_free((char*) load_default_groups,MYF(0)); my_free((char*) load_default_groups,MYF(0));
free_defaults(arguments); free_defaults(arguments);
......
...@@ -843,6 +843,7 @@ extern void *memdup_root(MEM_ROOT *root,const void *str, size_t len); ...@@ -843,6 +843,7 @@ extern void *memdup_root(MEM_ROOT *root,const void *str, size_t len);
extern int get_defaults_options(int argc, char **argv, extern int get_defaults_options(int argc, char **argv,
char **defaults, char **extra_defaults, char **defaults, char **extra_defaults,
char **group_suffix); char **group_suffix);
extern const char *args_separator;
extern int my_load_defaults(const char *conf_file, const char **groups, extern int my_load_defaults(const char *conf_file, const char **groups,
int *argc, char ***argv, const char ***); int *argc, char ***argv, const char ***);
extern int load_defaults(const char *conf_file, const char **groups, extern int load_defaults(const char *conf_file, const char **groups,
......
...@@ -41,6 +41,29 @@ ...@@ -41,6 +41,29 @@
#include <winbase.h> #include <winbase.h>
#endif #endif
/**
arguments separator
load_defaults() loads arguments from config file and put them
before the arguments from command line, this separator is used to
separate the arguments loaded from config file and arguments user
provided on command line.
Options with value loaded from config file are always in the form
'--option=value', while for command line options, the value can be
given as the next argument. Thus we used a separator so that
handle_options() can distinguish them.
Note: any other places that does not need to distinguish them
should skip the separator.
The content of arguments separator does not matter, one should only
check the pointer, use "----args-separator----" here to ease debug
if someone misused it.
See BUG#25192
*/
const char *args_separator= "----args-separator----";
const char *my_defaults_file=0; const char *my_defaults_file=0;
const char *my_defaults_group_suffix=0; const char *my_defaults_group_suffix=0;
char *my_defaults_extra_file=0; char *my_defaults_extra_file=0;
...@@ -454,10 +477,11 @@ int my_load_defaults(const char *conf_file, const char **groups, ...@@ -454,10 +477,11 @@ int my_load_defaults(const char *conf_file, const char **groups,
goto err; goto err;
res= (char**) (ptr+sizeof(alloc)); res= (char**) (ptr+sizeof(alloc));
res[0]= **argv; /* Copy program name */ res[0]= **argv; /* Copy program name */
/* set arguments separator */
res[1]= args_separator;
for (i=2 ; i < (uint) *argc ; i++) for (i=2 ; i < (uint) *argc ; i++)
res[i-1]=argv[0][i]; res[i]=argv[0][i];
res[i-1]=0; /* End pointer */ res[i]=0; /* End pointer */
(*argc)--;
*argv=res; *argv=res;
*(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */ *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
if (default_directories) if (default_directories)
...@@ -487,7 +511,7 @@ int my_load_defaults(const char *conf_file, const char **groups, ...@@ -487,7 +511,7 @@ int my_load_defaults(const char *conf_file, const char **groups,
or a forced default file or a forced default file
*/ */
if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+ if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
(args.elements + *argc +1) *sizeof(char*)))) (args.elements + *argc + 1 + 1) *sizeof(char*))))
goto err; goto err;
res= (char**) (ptr+sizeof(alloc)); res= (char**) (ptr+sizeof(alloc));
...@@ -508,12 +532,16 @@ int my_load_defaults(const char *conf_file, const char **groups, ...@@ -508,12 +532,16 @@ int my_load_defaults(const char *conf_file, const char **groups,
--*argc; ++*argv; /* skip argument */ --*argc; ++*argv; /* skip argument */
} }
/* set arguments separator for arguments from config file and
command line */
res[args.elements+1]= args_separator;
if (*argc) if (*argc)
memcpy((uchar*) (res+1+args.elements), (char*) ((*argv)+1), memcpy((uchar*) (res+1+args.elements+1), (char*) ((*argv)+1),
(*argc-1)*sizeof(char*)); (*argc-1)*sizeof(char*));
res[args.elements+ *argc]=0; /* last null */ res[args.elements+ *argc+1]=0; /* last null */
(*argc)+=args.elements; (*argc)+=args.elements+1;
*argv= (char**) res; *argv= (char**) res;
*(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */ *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
delete_dynamic(&args); delete_dynamic(&args);
...@@ -523,7 +551,8 @@ int my_load_defaults(const char *conf_file, const char **groups, ...@@ -523,7 +551,8 @@ int my_load_defaults(const char *conf_file, const char **groups,
printf("%s would have been started with the following arguments:\n", printf("%s would have been started with the following arguments:\n",
**argv); **argv);
for (i=1 ; i < *argc ; i++) for (i=1 ; i < *argc ; i++)
printf("%s ", (*argv)[i]); if ((*argv)[i] != args_separator) /* skip arguments separator */
printf("%s ", (*argv)[i]);
puts(""); puts("");
exit(0); exit(0);
} }
......
...@@ -121,6 +121,7 @@ int handle_options(int *argc, char ***argv, ...@@ -121,6 +121,7 @@ int handle_options(int *argc, char ***argv,
const struct my_option *optp; const struct my_option *optp;
uchar* *value; uchar* *value;
int error, i; int error, i;
my_bool is_cmdline_arg= 1;
LINT_INIT(opt_found); LINT_INIT(opt_found);
/* handle_options() assumes arg0 (program name) always exists */ /* handle_options() assumes arg0 (program name) always exists */
...@@ -130,10 +131,34 @@ int handle_options(int *argc, char ***argv, ...@@ -130,10 +131,34 @@ int handle_options(int *argc, char ***argv,
(*argv)++; /* --- || ---- */ (*argv)++; /* --- || ---- */
init_variables(longopts, init_one_value); init_variables(longopts, init_one_value);
/*
Search for args_separator, if found, then the first part of the
arguments are loaded from configs
*/
for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++)
{
if (*pos == args_separator)
{
is_cmdline_arg= 0;
break;
}
}
for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++) for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++)
{ {
char **first= pos; char **first= pos;
char *cur_arg= *pos; char *cur_arg= *pos;
if (!is_cmdline_arg && (cur_arg == args_separator))
{
is_cmdline_arg= 1;
/* save the separator too if skip unkown options */
if (my_getopt_skip_unknown)
(*argv)[argvpos++]= cur_arg;
else
(*argc)--;
continue;
}
if (cur_arg[0] == '-' && cur_arg[1] && !end_of_options) /* must be opt */ if (cur_arg[0] == '-' && cur_arg[1] && !end_of_options) /* must be opt */
{ {
char *argument= 0; char *argument= 0;
...@@ -426,8 +451,12 @@ invalid value '%s'", ...@@ -426,8 +451,12 @@ invalid value '%s'",
} }
else if (optp->arg_type == REQUIRED_ARG && !optend) else if (optp->arg_type == REQUIRED_ARG && !optend)
{ {
/* Check if there are more arguments after this one */ /* Check if there are more arguments after this one,
if (!*++pos)
Note: options loaded from config file that requires value
should always be in the form '--option=value'.
*/
if (!is_cmdline_arg || !*++pos)
{ {
if (my_getopt_print_errors) if (my_getopt_print_errors)
my_getopt_error_reporter(ERROR_LEVEL, my_getopt_error_reporter(ERROR_LEVEL,
......
...@@ -1053,6 +1053,8 @@ void mysql_read_default_options(struct st_mysql_options *options, ...@@ -1053,6 +1053,8 @@ void mysql_read_default_options(struct st_mysql_options *options,
char **option=argv; char **option=argv;
while (*++option) while (*++option)
{ {
if (option[0] == args_separator) /* skip arguments separator */
continue;
/* DBUG_PRINT("info",("option: %s",option[0])); */ /* DBUG_PRINT("info",("option: %s",option[0])); */
if (option[0][0] == '-' && option[0][1] == '-') if (option[0][0] == '-' && option[0][1] == '-')
{ {
......
...@@ -105,6 +105,8 @@ setup_config(atrt_config& config) ...@@ -105,6 +105,8 @@ setup_config(atrt_config& config)
*/ */
for (j = 0; j<(size_t)argc; j++) for (j = 0; j<(size_t)argc; j++)
{ {
if (tmp[j] == args_separator) /* skip arguments separator */
continue;
for (k = 0; proc_args[k].name; k++) for (k = 0; proc_args[k].name; k++)
{ {
if (!strncmp(tmp[j], proc_args[k].name, strlen(proc_args[k].name))) if (!strncmp(tmp[j], proc_args[k].name, strlen(proc_args[k].name)))
...@@ -369,6 +371,12 @@ load_options(int argc, char** argv, int type, atrt_options& opts) ...@@ -369,6 +371,12 @@ load_options(int argc, char** argv, int type, atrt_options& opts)
{ {
for (size_t i = 0; i<(size_t)argc; i++) for (size_t i = 0; i<(size_t)argc; i++)
{ {
/**
* Skip the separator for arguments from config file and command
* line
*/
if (argv[i] == args_separator)
continue;
for (size_t j = 0; f_options[j].name; j++) for (size_t j = 0; f_options[j].name; j++)
{ {
const char * name = f_options[j].name; const char * name = f_options[j].name;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment