From ef5f757ac282528c0abc1a93df888e4c1350c467 Mon Sep 17 00:00:00 2001 From: "iggy@recycle.(none)" <> Date: Thu, 18 Jan 2007 11:38:05 -0500 Subject: [PATCH] Bug#22807 mysql_upgrade fails when called with a basedir-path containing spaces - Create space safe strings for system() calls in mysql_upgrade.exe --- client/mysql_upgrade.c | 77 +++++++++++++++++++++++++++++++----------- include/my_sys.h | 2 ++ mysys/string.c | 52 ++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 20 deletions(-) diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index cce4b440be0..01e544af972 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -461,7 +461,12 @@ int main(int argc, char **argv) load_defaults("my", load_default_groups, &argc, &argv); - if (handle_options(&argc, &argv, my_long_options, get_one_option)) + /* + Must init_dynamic_string before handle_options because string is freed + at error label. + */ + if (init_dynamic_string(&cmdline, NULL, 2 * FN_REFLEN + 128, FN_REFLEN) || + handle_options(&argc, &argv, my_long_options, get_one_option)) { ret= 1; goto error; @@ -469,11 +474,6 @@ int main(int argc, char **argv) if (tty_password) opt_password= get_tty_password(NullS); - if (init_dynamic_string(&cmdline, NULL, 2 * FN_REFLEN + 128, FN_REFLEN)) - { - ret= 1; - goto error; - } if (!basedir) { my_getwd(path, sizeof(path), MYF(0)); @@ -556,17 +556,34 @@ int main(int argc, char **argv) goto error; } else - dynstr_set(&cmdline, path); + { +#ifdef __WIN__ + /* Windows requires an extra pair of quotes around the entire string. */ + dynstr_set(&cmdline, "\""); +#else + dynstr_set(&cmdline, ""); +#endif /* __WIN__ */ + dynstr_append_os_quoted(&cmdline, path, NullS); + } if (defaults_to_use) { - dynstr_append(&cmdline, " --defaults-extra-file="); - dynstr_append(&cmdline, defaults_to_use); + dynstr_append(&cmdline, " "); + dynstr_append_os_quoted(&cmdline, "--defaults-extra-file=", + defaults_to_use, NullS); } - - dynstr_append(&cmdline, " --check-upgrade --all-databases" - " --auto-repair --user="); - dynstr_append(&cmdline, user); + + dynstr_append(&cmdline, " "); + dynstr_append_os_quoted(&cmdline, "--check-upgrade", NullS); + dynstr_append(&cmdline, " "); + dynstr_append_os_quoted(&cmdline, "--all-databases", NullS); + dynstr_append(&cmdline, " "); + dynstr_append_os_quoted(&cmdline, "--auto-repair", NullS); + dynstr_append(&cmdline, " "); + dynstr_append_os_quoted(&cmdline, "--user=", user, NullS); +#ifdef __WIN__ + dynstr_append(&cmdline, "\""); +#endif /* __WIN__ */ if (opt_verbose) printf("Running %s\n", cmdline.str); @@ -595,7 +612,15 @@ fix_priv_tables: goto error; } else - dynstr_set(&cmdline, path); + { +#ifdef __WIN__ + /* Windows requires an extra pair of quotes around the entire string. */ + dynstr_set(&cmdline, "\""); +#else + dynstr_set(&cmdline, ""); +#endif /* __WIN__ */ + dynstr_append_os_quoted(&cmdline, path, NullS); + } if (find_file(MYSQL_FIX_PRIV_TABLES_NAME, basedir, MYF(0), path, sizeof(path), @@ -617,13 +642,25 @@ fix_priv_tables: if (defaults_to_use) { - dynstr_append(&cmdline, " --defaults-extra-file="); - dynstr_append(&cmdline, defaults_to_use); + dynstr_append(&cmdline, " "); + dynstr_append_os_quoted(&cmdline, "--defaults-extra-file=", + defaults_to_use, NullS); } - dynstr_append(&cmdline, " --force --no-auto-rehash --batch --user="); - dynstr_append(&cmdline, user); - dynstr_append(&cmdline, " mysql < "); - dynstr_append(&cmdline, script_line); + dynstr_append(&cmdline, " "); + dynstr_append_os_quoted(&cmdline, "--force", NullS); + dynstr_append(&cmdline, " "); + dynstr_append_os_quoted(&cmdline, "--no-auto-rehash", NullS); + dynstr_append(&cmdline, " "); + dynstr_append_os_quoted(&cmdline, "--batch", NullS); + dynstr_append(&cmdline, " "); + dynstr_append_os_quoted(&cmdline, "--user=", user, NullS); + dynstr_append(&cmdline, " "); + dynstr_append_os_quoted(&cmdline, "--database=mysql", NullS); + dynstr_append(&cmdline, " < "); + dynstr_append_os_quoted(&cmdline, script_line, NullS); +#ifdef __WIN__ + dynstr_append(&cmdline, "\""); +#endif /* __WIN__ */ if (opt_verbose) printf("Running %s\n", cmdline.str); diff --git a/include/my_sys.h b/include/my_sys.h index d19091a85e8..cbcc6cf7486 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -781,6 +781,8 @@ extern my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str, extern my_bool dynstr_append(DYNAMIC_STRING *str, const char *append); my_bool dynstr_append_mem(DYNAMIC_STRING *str, const char *append, uint length); +extern my_bool dynstr_append_os_quoted(DYNAMIC_STRING *str, const char *append, + ...); extern my_bool dynstr_set(DYNAMIC_STRING *str, const char *init_str); extern my_bool dynstr_realloc(DYNAMIC_STRING *str, ulong additional_size); extern void dynstr_free(DYNAMIC_STRING *str); diff --git a/mysys/string.c b/mysys/string.c index dfd42d137dd..c5657cd430d 100644 --- a/mysys/string.c +++ b/mysys/string.c @@ -116,6 +116,58 @@ my_bool dynstr_append_mem(DYNAMIC_STRING *str, const char *append, } +/** Concatenates any number of strings, escapes any OS quote in the result then + * surround the whole affair in another set of quotes which is finally appended + * to specified DYNAMIC_STRING. This function is especially useful when + * building strings to be executed with the system() function. + * @param str Dynamic String which will have addtional strings appended. + * @param append String to be appended. + * @param ... Optional. Additional string(s) to be appended. + * + * @note The final argument in the list must be NullS even if no additional + * options are passed. + * + * @return True = Success. + */ +my_bool dynstr_append_os_quoted(DYNAMIC_STRING *str, const char *append, ...) +{ +#ifdef __WIN__ + char quote_str[]= "\""; +#else + char quote_str[]= "\'"; +#endif /* __WIN__ */ + my_bool ret= TRUE; + va_list dirty_text; + + ret&= dynstr_append(str, quote_str); /* Leading quote */ + va_start(dirty_text,append); + while (append != NullS) + { + char *cur_pos= append; + char *next_pos= cur_pos; + + /* Search for quote in each string and replace with escaped quote */ + while(*(next_pos= strcend(cur_pos, quote_str[0])) != '\0') + { + char *tmp_buff= my_malloc((next_pos - cur_pos) + 1, MYF(MY_ZEROFILL)); + strnmov(tmp_buff, cur_pos, (next_pos - cur_pos)); + ret&= dynstr_append(str, tmp_buff); + my_free((gptr)tmp_buff, MYF(0)); + + ret&= dynstr_append(str ,"\\"); + ret&= dynstr_append(str, quote_str); + cur_pos= next_pos + 1; + } + ret&= dynstr_append(str, cur_pos); + append= va_arg(dirty_text, char *); + } + va_end(dirty_text); + ret&= dynstr_append(str, quote_str); /* Trailing quote */ + + return ret; +} + + void dynstr_free(DYNAMIC_STRING *str) { if (str->str)