diff --git a/.gitignore b/.gitignore index 5b63c83b3b6..07516b9d2a2 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ Docs/INFO_BIN Docs/INFO_SRC Makefile TAGS +all_plugins/ mariadb-plugin-columnstore.install.generated Testing/ tmp/ @@ -59,8 +60,10 @@ extra/comp_err extra/innochecksum extra/jemalloc/build/ extra/jemalloc/tmp/ +extra/generate_option_list extra/mariabackup/mariabackup extra/mariabackup/mbstream +extra/mariadb-migrate-config-file extra/my_print_defaults extra/mysql_waitpid extra/mysqld_safe_helper @@ -72,6 +75,7 @@ extra/wolfssl/user_settings.h import_executables.cmake include/*.h.tmp include/config.h +include/mariadbd_options.h include/my_config.h include/mysql_version.h include/mysqld_ername.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d17b61d1c02..a1a6c4692fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -496,7 +496,6 @@ ADD_SUBDIRECTORY(vio) ADD_SUBDIRECTORY(mysys) ADD_SUBDIRECTORY(mysys_ssl) ADD_SUBDIRECTORY(client) -ADD_SUBDIRECTORY(extra) ADD_SUBDIRECTORY(libservices) ADD_SUBDIRECTORY(sql/share) @@ -522,6 +521,8 @@ IF(NOT WITHOUT_SERVER) ENDIF() ENDIF() +ADD_SUBDIRECTORY(extra) + IF(UNIX) ADD_SUBDIRECTORY(man) ENDIF() diff --git a/client/mysqltest.cc b/client/mysqltest.cc index f485b16df52..c1e73ba4181 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -2157,15 +2157,16 @@ void log_msg(const char *fmt, ...) SYNOPSIS cat_file ds - pointer to dynamic string where to add the files content - filename - name of the file to read - + filename - name of the file to read + max_lines - number of lines to print. 0 == all */ -int cat_file(DYNAMIC_STRING* ds, const char* filename) +int cat_file(DYNAMIC_STRING* ds, const char* filename, uint max_lines) { int fd; size_t len; char *buff; + uint line= 0; // Enough for mtr if ((fd= my_open(filename, O_RDONLY, MYF(0))) < 0) return 1; @@ -2182,28 +2183,35 @@ int cat_file(DYNAMIC_STRING* ds, const char* filename) len= my_read(fd, (uchar*)buff, len, MYF(0)); my_close(fd, MYF(0)); + if (!max_lines) + max_lines= 10000; // Enough for mtr + + char *p= buff, *start= buff, *end=buff+len; + while (p < end && line <= max_lines) { - char *p= buff, *start= buff,*end=buff+len; - while (p < end) + /* Convert cr/lf to lf */ + if (*p == '\r' && p+1 < end && *(p+1)== '\n') { - /* Convert cr/lf to lf */ - if (*p == '\r' && p+1 < end && *(p+1)== '\n') - { - /* Add fake newline instead of cr and output the line */ - *p= '\n'; - p++; /* Step past the "fake" newline */ - *p= 0; - replace_dynstr_append_mem(ds, start, p-start); - p++; /* Step past the "fake" newline */ - start= p; - } - else - p++; + /* Add fake newline instead of cr and output the line */ + *p= '\n'; + p++; /* Step past the "fake" newline */ + *p= 0; + replace_dynstr_append_mem(ds, start, p-start); + p++; /* Step past the "fake" newline */ + start= p; + line++; + } + else + { + if (*p == '\n') + line++; + p++; } - /* Output any chars that migh be left */ - *p= 0; - replace_dynstr_append_mem(ds, start, p-start); } + /* Output any chars that migh be left */ + *p= 0; + replace_dynstr_append_mem(ds, start, p-start); + my_free(buff); return 0; } @@ -2450,11 +2458,11 @@ void show_diff(DYNAMIC_STRING* ds, dynstr_append_mem(&ds_tmp, STRING_WITH_LEN(" --- ")); dynstr_append_mem(&ds_tmp, filename1, strlen(filename1)); dynstr_append_mem(&ds_tmp, STRING_WITH_LEN(" >>>\n")); - cat_file(&ds_tmp, filename1); + cat_file(&ds_tmp, filename1, 0); dynstr_append_mem(&ds_tmp, STRING_WITH_LEN("<<<\n --- ")); dynstr_append_mem(&ds_tmp, filename1, strlen(filename1)); dynstr_append_mem(&ds_tmp, STRING_WITH_LEN(" >>>\n")); - cat_file(&ds_tmp, filename2); + cat_file(&ds_tmp, filename2, 0); dynstr_append_mem(&ds_tmp, STRING_WITH_LEN("<<<<\n")); } @@ -4851,9 +4859,11 @@ void do_append_file(struct st_command *command) void do_cat_file(struct st_command *command) { int error; - static DYNAMIC_STRING ds_filename; + static DYNAMIC_STRING ds_filename, ds_lines; + uint lines= 0; const struct command_arg cat_file_args[] = { - { "filename", ARG_STRING, TRUE, &ds_filename, "File to read from" } + { "filename", ARG_STRING, TRUE, &ds_filename, "File to read from" }, + { "lines", ARG_STRING, FALSE, &ds_lines, "Number of lines to print"} }; DBUG_ENTER("do_cat_file"); @@ -4865,9 +4875,13 @@ void do_cat_file(struct st_command *command) DBUG_PRINT("info", ("Reading from, file: %s", ds_filename.str)); - error= cat_file(&ds_res, ds_filename.str); + if (ds_lines.length) + lines= atoi(ds_lines.str); + + error= cat_file(&ds_res, ds_filename.str, lines); handle_command_error(command, error, my_errno); dynstr_free(&ds_filename); + dynstr_free(&ds_lines); DBUG_VOID_RETURN; } @@ -13281,7 +13295,7 @@ int main(int argc, char **argv) case Q_DIFF_FILES: do_diff_files(command); break; case Q_SEND_QUIT: do_send_quit(command); break; case Q_CHANGE_USER: do_change_user(command); break; - case Q_CAT_FILE: do_cat_file(command); break; + case Q_CAT_FILE: do_cat_file(command); command_executed++; break; case Q_COPY_FILE: do_copy_file(command); break; case Q_MOVE_FILE: do_move_file(command); break; case Q_CHMOD_FILE: do_chmod_file(command); break; diff --git a/cmake/plugin.cmake b/cmake/plugin.cmake index 32e662d72c4..6c628d38a9a 100644 --- a/cmake/plugin.cmake +++ b/cmake/plugin.cmake @@ -300,6 +300,11 @@ MACRO(MYSQL_ADD_PLUGIN) IF(ARG_CONFIG AND INSTALL_SYSCONF2DIR) INSTALL(FILES ${ARG_CONFIG} COMPONENT ${ARG_COMPONENT} DESTINATION ${INSTALL_SYSCONF2DIR}) ENDIF() + IF(NOT ARG_CLIENT) + GET_PROPERTY(my_list GLOBAL PROPERTY SERVER_DYNAMIC_PLUGINS) + LIST(APPEND my_list ${target}) + SET_PROPERTY(GLOBAL PROPERTY SERVER_DYNAMIC_PLUGINS "${my_list}") + ENDIF() ENDIF() GET_FILENAME_COMPONENT(subpath ${CMAKE_CURRENT_SOURCE_DIR} NAME) diff --git a/debian/mariadb-client-core.install b/debian/mariadb-client-core.install index ddb8015e1cb..8b111810d4d 100644 --- a/debian/mariadb-client-core.install +++ b/debian/mariadb-client-core.install @@ -1,6 +1,7 @@ usr/bin/mariadb usr/bin/mariadb-check usr/bin/my_print_defaults +usr/bin/mariadb-migrate-config-file usr/share/man/man1/mariadb-check.1 usr/share/man/man1/mariadb.1 usr/share/man/man1/my_print_defaults.1 diff --git a/extra/CMakeLists.txt b/extra/CMakeLists.txt index e6db43fec62..83fa9d7e9e9 100644 --- a/extra/CMakeLists.txt +++ b/extra/CMakeLists.txt @@ -13,7 +13,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA -INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${ZLIB_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${ZLIB_INCLUDE_DIRS} ${PCRE_INCLUDE_DIRS}) # Default install component for the files is Server here SET(MYSQL_INSTALL_COMPONENT Server) @@ -46,6 +46,67 @@ ADD_CUSTOM_TARGET(GenError DEPENDS ${CMAKE_BINARY_DIR}/include/mysqld_error.h.tmp) +IF(NOT CMAKE_CROSSCOMPILING AND TARGET mariadbd) + ADD_EXECUTABLE(generate_option_list generate_option_list.cc) + TARGET_LINK_LIBRARIES(generate_option_list mysys pcre2-8) + TARGET_INCLUDE_DIRECTORIES(generate_option_list PRIVATE ${PCRE_INCLUDE_DIRS}) + GET_PROPERTY(dynamic_plugins GLOBAL PROPERTY SERVER_DYNAMIC_PLUGINS) + GET_PROPERTY(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + IF(is_multi_config) + SET(my_plugin_dir "${CMAKE_BINARY_DIR}/all_plugins/$") + ELSE() + SET(my_plugin_dir "${CMAKE_BINARY_DIR}/all_plugins") + ENDIF() + + SET(populate_plugin_dir) + SET(plugin_load) + LIST(APPEND populate_plugin_dir + COMMAND ${CMAKE_COMMAND} -E rm -rf "${my_plugin_dir}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${my_plugin_dir}" + ) + FOREACH(target ${dynamic_plugins}) + LIST(APPEND plugin_load "$") + IF(WIN32) + SET(maybe_create_hardlink || ${CMAKE_COMMAND} -E create_hardlink + $ + "${my_plugin_dir}/$") + ENDIF() + LIST(APPEND populate_plugin_dir + COMMAND ${CMAKE_COMMAND} -E create_symlink + $ + "${my_plugin_dir}/$" + ${maybe_create_hardlink}) + ENDFOREACH() + + IF(NOT plugin_load) + SET(plugin_load " ") + ENDIF() + + STRING(REPLACE ";" ":" escaped_plugin_load "${plugin_load}") + SET(genhdr ${CMAKE_BINARY_DIR}/include/mariadbd_options.h) + ADD_CUSTOM_COMMAND(OUTPUT ${genhdr} + # COMMAND ${CMAKE_COMMAND} -E echo "Executing ${populate_plugin_dir}" + ${populate_plugin_dir} + #COMMAND ${CMAKE_COMMAND} -E echo "Executing generate_option_list $ ${my_plugin_dir} ${escaped_plugin_load} ${genhdr}" + COMMAND generate_option_list "$" "${my_plugin_dir}" "${escaped_plugin_load}" "${genhdr}" + COMMAND_EXPAND_LISTS + ) + + ADD_CUSTOM_TARGET(gen_mariadbd_options_h + DEPENDS ${genhdr} + + ) + + MYSQL_ADD_EXECUTABLE(mariadb-migrate-config-file + mariadb_migrate_config_file.c + ${genhdr} + COMPONENT Client) + + # Make sure consumers cannot compile before the header exists: + SET_SOURCE_FILES_PROPERTIES("${genhdr}" PROPERTIES GENERATED TRUE) + TARGET_LINK_LIBRARIES(mariadb-migrate-config-file PRIVATE mysys) +ENDIF() + MYSQL_ADD_EXECUTABLE(my_print_defaults my_print_defaults.c COMPONENT Client) TARGET_LINK_LIBRARIES(my_print_defaults mysys) diff --git a/extra/generate_option_list.cc b/extra/generate_option_list.cc new file mode 100644 index 00000000000..809fdaee5e7 --- /dev/null +++ b/extra/generate_option_list.cc @@ -0,0 +1,346 @@ +/* Copyright (c) 2024, Väinö Mäkelä + With some small changes by Michael Widenius + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 + USA */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define PCRE2_STATIC 1 /* Important on Windows */ +#include "pcre2.h" + +struct parsed +{ + std::set options; + std::map> enums; + std::map> sets; +}; + +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) + __attribute__((no_sanitize("memory"))) /* we may run with uninstrumented std::string */ +# endif +#endif + +std::string read_output(FILE *f) +{ + char buf[4096]; + size_t read_bytes; + std::string output; + do + { + read_bytes= std::fread(buf, 1, sizeof buf, f); + output.append(buf, read_bytes); + } while (read_bytes > 0); + return output; +} + + +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) + __attribute__((no_sanitize("memory"))) /* we may run with uninstrumented std::string */ +# endif +#endif + + +std::string call_mariadbd(const char *mariadbd_path, const char *plugin_dir, const char *plugin_load) +{ + std::string output; + std::ostringstream command; +#ifdef _WIN32 + command << "\""; +#endif + command << "\"" << mariadbd_path << "\""; + command << " --no-defaults" + " --silent-startup" + " --plugin-maturity=unknown" + " --plugin-dir="; + command << plugin_dir << ""; + if (plugin_load[0] != ' ' || !plugin_load[0]) + { + command << " \"--plugin-load="; + command << plugin_load; + command << "\""; + } + command << " --verbose" + " --help"; +#ifdef _WIN32 + command << "\""; +#endif + std::cout << "Executing command: " << command.str() << '\n'; + FILE *f= my_popen(command.str().c_str(), "r"); + if (!f) + { + perror("failed to read mariadbd output"); + my_pclose(f); + exit(1); + } + output= read_output(f); + my_pclose(f); + return output; +} + +std::string remove_paretheses(std::string &str) +{ + std::string result; + bool in_parens= false; + for (auto it= str.begin(); it != str.end(); ++it) + { + if (*it == '(') + { + in_parens= true; + } + else if (in_parens && *it == ')') + { + in_parens= false; + } + else if (!in_parens) + { + result.push_back(*it); + } + } + return result; +} + +std::vector split_list(std::string &str) +{ + std::vector result; + std::string current; + std::string parens_removed= remove_paretheses(str); + bool seen_dot= false; + + for (auto it= parens_removed.begin(); it != parens_removed.end(); ++it) + { + switch (*it) { + case ' ': + case '\t': + case '\n': + case '\r': + case ',': + seen_dot= false; + if (!current.empty()) + result.push_back(current); + current.clear(); + break; + case '.': + seen_dot= true; + break; + default: + if (seen_dot) + current.push_back('.'); + current.push_back(*it); + } + } + if (!current.empty()) + result.push_back(current); + return result; +} + +std::string capture_group(std::string &str, PCRE2_SIZE *ovector, int group) +{ + return str.substr(ovector[2 * group], + ovector[2 * group + 1] - ovector[2 * group]); +} + + +/* + Ignore some special mariadb options from using enum/set +*/ + +bool ignore_option(std::string *option) +{ + /* + wsrep_provider must not be threated as an enum as in mariadbd --help is both + a string and an enum. + */ + if (!strcmp(option->c_str(), "wsrep_provider")) + return 1; // Ignore + return 0; +} + + +struct parsed parse_output(std::string &output) +{ + struct parsed result= {}; + const char *pattern= + "# Consider all lines that start with ' --' or ' -x, --'as options.\n" + "^\\ \\ (?:-.,\\ )?--([^\\ =\\[]+)\n" + "(?:\n" + " # Check for possible enum or set values until we hit\n" + " # ' -' at the start of a line. This won't work for\n" + " # the last option but should work for most ones.\n" + " (?:(? enum_options; + std::vector set_options; + int rc= pcre2_match(re, (PCRE2_SPTR8) output.c_str(), output.length(), + offset, 0, match_data, nullptr); + if (rc == PCRE2_ERROR_NOMATCH) + { + break; + } + if (rc < 0) + { + std::cerr << "Matching error " << rc << '\n'; + exit(1); + } + + offset= ovector[1]; + option= capture_group(output, ovector, 1); + std::replace(option.begin(), option.end(), '-', '_'); + if (rc > 2 && ovector[2 * 2] != PCRE2_UNSET) + { + enum_part= capture_group(output, ovector, 2); + enum_options= split_list(enum_part); + } + if (rc > 3 && ovector[2 * 3] != PCRE2_UNSET) + { + set_part= capture_group(output, ovector, 3); + set_options= split_list(set_part); + } + + result.options.insert(option); + if (ignore_option(&option)) + continue; + + if (!enum_options.empty()) + { + result.enums.emplace(option, enum_options); + } + if (!set_options.empty()) + { + result.sets.emplace(option, set_options); + } + } + + pcre2_match_data_free(match_data); + pcre2_code_free(re); + return result; +} + +void write_typelibs(std::ostream &out, + std::map> &map) +{ + for (auto option= map.begin(); option != map.end(); ++option) + { + const std::string &option_name= (*option).first; + const std::vector &values= (*option).second; + out << "\nstatic const char *valid_" << option_name << "_values[] = {\n"; + for (auto value= values.begin(); value != values.end(); ++value) + { + out << "\"" << *value << "\",\n"; + } + out << "0\n};\n"; + out << "static TYPELIB valid_" << option_name << "_values_typelib = {\n" + << "array_elements(valid_" << option_name << "_values)-1,\n" + << "\"\", valid_" << option_name << "_values, 0, 0};\n"; + } +} + +void write_typelib_map(std::ostream &out, std::string name, + std::map> &map) +{ + out << "\nstatic const char *mariadbd_" << name << "_options[] = {\n"; + for (auto option= map.begin(); option != map.end(); ++option) + { + out << "\"" << (*option).first << "\",\n"; + } + out << "};\n" + << "\nstatic TYPELIB *mariadbd_" << name << "_typelibs[] = {\n"; + for (auto option= map.begin(); option != map.end(); ++option) + { + out << "&valid_" << (*option).first << "_values_typelib,\n"; + } + out << "};\n"; +} + +void write_output(const char *path, struct parsed &parsed_output) +{ + std::ofstream out(path); + out << "/* Automatically generated by generate_option_list */\n\n"; + out << "#ifndef _mariadbd_options_h\n"; + out << "#define _mariadbd_options_h\n"; + out << "static const char *mariadbd_valid_options[]= {\n"; + for (auto option= parsed_output.options.begin(); + option != parsed_output.options.end(); ++option) + { + out << '\"' << *option << "\",\n"; + } + out << "};\n"; + + write_typelibs(out, parsed_output.enums); + write_typelib_map(out, "enum", parsed_output.enums); + + write_typelibs(out, parsed_output.sets); + write_typelib_map(out, "set", parsed_output.sets); + + out << "#endif /* _mariadbd_options_h */\n"; +} + +int main(int argc, const char *argv[]) +{ + std::string mariadbd_output; + struct parsed parsed_output; + + if (argc != 5) + { + std::cerr << "usage: " << argv[0] << " \n"; + return 1; + } + MY_INIT(argv[0]); + mariadbd_output= call_mariadbd(argv[1], argv[2], argv[3]); + parsed_output= parse_output(mariadbd_output); + write_output(argv[4], parsed_output); + + my_end(0); + exit(0); +} diff --git a/extra/mariadb_migrate_config_file.c b/extra/mariadb_migrate_config_file.c new file mode 100644 index 00000000000..2e5c4d52cd5 --- /dev/null +++ b/extra/mariadb_migrate_config_file.c @@ -0,0 +1,2567 @@ +/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2011, 2018, 2026 MariaDB Corporation + Copyright (c) 2024, Väinö Mäkelä + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +#define VER "1.0" +#include +#include "mariadbd_options.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if!defined (X_OK) && defined(_WIN32) +#define X_OK 0 /* Test existence of file with access() */ +#endif + + +#define load_default_groups mariadbd_groups +#include +#undef load_default_groups + +const char *mysqld_groups[]= +{ + "mysqld", "server", 0, 0 +}; + +const char *client_server_group= "client-server"; + +/* The following is from my_getopt.c */ +static const char *special_opt_prefix[]= +{"skip", "disable", "enable", "maximum", "loose", "autoset", 0}; +static const uint special_opt_prefix_lengths[]= +{ 4, 7, 6, 7, 5, 7, 0}; + +#ifndef WEXITSTATUS +# ifdef _WIN32 +# define WEXITSTATUS(stat_val) (stat_val) +# else +# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +# endif +#endif + +struct upgrade_ctx +{ + MEM_ROOT *alloc; + TYPELIB *group; /* Default groups and extra groups */ + DYNAMIC_ARRAY updated_files; + my_bool failed; +}; + + +enum edit_mode +{ + EDIT_MODE_NONE, + EDIT_MODE_REMOVE, + EDIT_MODE_COMMENT, + EDIT_MODE_INLINE, + EDIT_MODE_LAST, +}; + +static const char *edit_mode_values[]= +{ + "", "remove", "comment", "inline", "last", NullS +}; +static TYPELIB edit_mode_typelib= +{array_elements(edit_mode_values) - 1, "", edit_mode_values, NULL, NULL}; + +enum from_mode +{ + FROM_MYSQL, + FROM_MARIADB, +}; + +static const char *from_mode_values[]= +{ + "MySQL", "MariaDB", NullS +}; +static TYPELIB from_mode_typelib= +{array_elements(from_mode_values) - 1, "", from_mode_values, NULL, NULL}; + +struct RENAMED_OPTIONS +{ + const char *from, *to; +}; + +struct RENAMED_OPTIONS renamed_options[]= +{ + {"innodb_stats_sample_pages", "innodb_stats_transient_sample_pages" }, + {NullS, NullS}, +}; + + +LEX_CSTRING mysql_name= {STRING_WITH_LEN("mysql")}; +LEX_CSTRING mysqld_name= {STRING_WITH_LEN("mysqld")}; +LEX_CSTRING mariadb_name= {STRING_WITH_LEN("mariadb")}; + +static const char *opt_error_group="mysqld-5.7"; +static const char *opt_unsupported_group="options-not-recognized-by-mariadbd"; +static my_bool opt_update; +static my_bool opt_backup; +static my_bool opt_print; +static my_bool opt_no_myisam_options; +static my_bool opt_add_skip_slave_start; +static my_bool opt_add_mariadb_replication_compatibility; +static my_bool opt_add_mysql_replication_compatibility; +static my_bool opt_add_client_server_group; +static my_bool opt_silent; +static my_bool opt_update_paths; +static my_bool opt_copy_mysqld_groups; +static my_bool add_new_options_once=0, new_options_added= 0; +static uint audit_plugin_warning= 0; +static const char **groups_to_use; +static const char *opt_mariadbd= ""; +static ulong opt_edit_mode, opt_convert_from; +static size_t global_copied_lines=0, global_unsupported_lines= 0; +static size_t global_mariadbd_additions= 0; + +static PSI_memory_key key_memory_upgrade_config; +static PSI_file_key key_file_cnf; +static size_t global_update_count= 0; +static my_bool give_error_for_missing_files= 0; +static my_bool opt_mariadbd_testing; +static const char *mariadb_replication_compatibility_comment= + "# The following options enable MySQL to replicate to MariaDB"; +static const char *mysql_replication_compatibility_comment= + "# The following options enable MariaDB to replicate to MySQL"; + +/* Options found that require special handling */ +static longlong value_port; +static char *value_socket= 0; +static my_bool found_skip_slave_start= FALSE; +static my_bool found_innodb_log_files_in_group= 0; +static my_bool found_innodb_log_file_size= 0; +static my_bool found_character_set_server= 0; +static my_bool found_client_server_group= 0; +static my_bool found_mariadb_replication_compatibility= 0; +static my_bool found_mysql_replication_compatibility= 0; + +static uint value_innodb_log_files_in_group= 0; +static ulonglong value_innodb_log_file_size= 0; +static char suffix_innodb_log_file_size; + + +#ifdef _WIN32 +static const char *f_extensions[]= { ".ini", ".cnf", 0 }; +#else +static const char *f_extensions[]= { ".cnf", 0 }; +#endif + +static uint count_array_elements(DYNAMIC_ARRAY *array); +static my_bool delete_line(DYNAMIC_ARRAY *array, char *line); + +/** + Remove the -upgrade-config-orig backups of the updated files if + successful and replace the updated files with the backups if not. +*/ + +static int finish_updated_files(struct upgrade_ctx *ctx, my_bool success) +{ + size_t i; + if (!opt_silent && success && ctx->updated_files.elements) + fputs("Updated files:\n", stdout); + for (i= 0; i < ctx->updated_files.elements; i++) + { + char *name = *(char **)dynamic_array_ptr(&ctx->updated_files, i); + const char *suffix = "-upgrade-config-orig"; + size_t orig_len = strlen(name) + strlen(suffix) + 1; + char *orig = my_malloc(key_memory_upgrade_config, orig_len, MYF(MY_WME)); + if (!orig) + return 1; + strmov(strmov(orig, name), suffix); + if (success) + { + fprintf(stdout, "%s\n", name); + my_delete(orig, MYF(0)); + } + else + { + if (my_redel(name, orig, 0, MYF(MY_WME | MY_REDEL_MAKE_BACKUP))) + { + my_free(orig); + return 1; + } + } + my_free(orig); + my_free(name); + } + delete_dynamic(&ctx->updated_files); + return 0; +} + + +/** + Run a command using the shell, storing its output in the supplied dynamic + string. +*/ +static int run_command(char* cmd, + DYNAMIC_STRING *ds_res) +{ + char buf[512]= {0}; + FILE *res_file; + int error; + + if (!(res_file= my_popen(cmd, "r"))) + { + fprintf(stderr, "popen(\"%s\", \"r\") failed\n", cmd); + return -1; + } + + while (fgets(buf, sizeof(buf), res_file)) + { +#ifdef _WIN32 + /* Strip '\r' off newlines. */ + size_t len = strlen(buf); + if (len > 1 && buf[len - 2] == '\r' && buf[len - 1] == '\n') + { + buf[len - 2] = '\n'; + buf[len - 1] = 0; + } +#endif + dynstr_append(ds_res, buf); + } + + error= my_pclose(res_file); + return WEXITSTATUS(error); +} + + +/** + Run `mariadbd --help --verbose` with the supplied arguments and write its + stderr output to ds_res. +*/ +static int run_mariadbd(const char *mariadbd_path, + DYNAMIC_STRING *ds_res, + const char **defaults_args, + int defaults_args_count) +{ + int ret; + int i; + DYNAMIC_STRING ds_cmdline; + + if (init_dynamic_string(&ds_cmdline, IF_WIN("\"", ""), FN_REFLEN, FN_REFLEN)) + { + fputs("Out of memory\n", stderr); + return -1; + } + + dynstr_append_os_quoted(&ds_cmdline, mariadbd_path, NullS); + dynstr_append(&ds_cmdline, " "); + + for (i= 0; i < defaults_args_count; i++) + { + dynstr_append_os_quoted(&ds_cmdline, defaults_args[i], NullS); + dynstr_append(&ds_cmdline, " "); + } + + dynstr_append(&ds_cmdline, "--help "); + dynstr_append(&ds_cmdline, "--verbose "); + dynstr_append(&ds_cmdline, "--silent-startup "); + dynstr_append(&ds_cmdline, "--log-warnings=0 "); + dynstr_append(&ds_cmdline, "2>&1 "); + dynstr_append(&ds_cmdline, IF_WIN("1>NUL", "1>/dev/null")); + +#ifdef _WIN32 + dynstr_append(&ds_cmdline, "\""); +#endif + + ret= run_command(ds_cmdline.str, ds_res); + dynstr_free(&ds_cmdline); + return ret; +} + + +/** + Test whether mariadbd can be launched with --no-defaults. +*/ +static int test_mariadbd(const char *mariadbd_name) +{ + DYNAMIC_STRING ds_tmp; + const char *defaults_argument = "--no-defaults"; + int err= 0; + + if (init_dynamic_string(&ds_tmp, "", 32, 32)) + { + fputs("Out of memory\n", stderr); + return -1; + } + + if (run_mariadbd(mariadbd_name, + &ds_tmp, + &defaults_argument, + 1)) + { + fprintf(stderr, "Can't execute %s\n", mariadbd_name); + err= 1; + } + + dynstr_free(&ds_tmp); + return err; +} + + +static int compare_options(const void *a, const void *b) +{ + const char *first= *(const char **)a; + const char *second= *(const char **)b; + return strcmp(first, second); +} + + +static my_bool mariadbd_option_exists(const char *option) +{ + return bsearch(&option, mariadbd_valid_options, + array_elements(mariadbd_valid_options), + sizeof(mariadbd_valid_options[0]), + compare_options) != NULL; +} + + +static my_bool mariadbd_valid_enum_value(const char *option, const char *value) +{ + const char **option_ptr= bsearch(&option, mariadbd_enum_options, + array_elements(mariadbd_enum_options), + sizeof(mariadbd_enum_options[0]), + compare_options); + longlong val; + int error; + if (!option_ptr) + return TRUE; + if (find_type(value, + mariadbd_enum_typelibs[option_ptr - mariadbd_enum_options], + FIND_TYPE_BASIC) != 0) + return TRUE; + val= my_strtoll10(value, (char**) 0, &error); + return (error == 0 && val < mariadbd_enum_typelibs[option_ptr - + mariadbd_enum_options]->count); +} + + +/** + Check whether the given value is a valid set value for the given + option. + Returns 0 on success and the first invalid set index on + failure. If the option is not a set option, returns 0. +*/ + +static int mariadbd_check_set_value(const char *option, const char *value) +{ + const char **option_ptr= bsearch(&option, mariadbd_set_options, + array_elements(mariadbd_set_options), + sizeof(mariadbd_set_options[0]), + compare_options); + TYPELIB *typelib; + int error_pos= 0; + if (!option_ptr) + return 0; + typelib = mariadbd_set_typelibs[option_ptr - mariadbd_set_options]; + find_typeset(value, typelib, &error_pos); + if (error_pos) + { + ulonglong num; + char *endptr; + + if (!my_strcasecmp_latin1(value, "all")) + return 0; + + num= strtol(value, &endptr, 10); + if (!*endptr) + { + if ((num >> 1) >= (1ULL << (typelib->count - 1))) + return 1; + return 0; + } + } + return error_pos; +} + + +enum plugin_check_result +{ + PLUGINS_OK, + AUDIT_PLUGIN, +}; + +static enum plugin_check_result check_plugins(const char *option, + const char *value) +{ + if (!strcmp(option, "plugin_load") || !strcmp(option, "plugin_load_add")) + { + if (!strcmp(value, "audit_log")) + return AUDIT_PLUGIN; + return PLUGINS_OK; + } + return PLUGINS_OK; +} + + +static my_bool check_plugin_option(struct upgrade_ctx *ctx, + const char *option, + const char *value, + char *name, + uint line) +{ + + enum plugin_check_result plugin_check_result; + + if ((plugin_check_result= check_plugins(option, value)) != PLUGINS_OK) + { + if (!opt_print) + { + switch (plugin_check_result) { + case PLUGINS_OK: break; /* Impossible */ + case AUDIT_PLUGIN: + if (!audit_plugin_warning++ && !opt_silent) + fprintf(stdout, "In %s at line %d: Please replace audit_log " + "with the server_audit plugin\n", name, line); + } + return 1; + } + } + return 0; +} + +/* + Skip over keyword and get argument after keyword + + SYNOPSIS + get_argument() + keyword Include directive keyword + kwlen Length of keyword + ptr Pointer to the keword in the line under process + line line number + + RETURN + 0 error + # Returns pointer to the argument after the keyword. +*/ + +static char *get_argument(const char *keyword, size_t kwlen, + char *ptr, char *name, uint line) +{ + char *end; + + /* Skip over "include / includedir keyword" and following whitespace */ + + for (ptr+= kwlen - 1; + my_isspace(&my_charset_latin1, ptr[0]); + ptr++) + {} + + /* + Trim trailing whitespace from directory name + The -1 below is for the newline added by fgets() + Note that my_isspace() is true for \r and \n + */ + for (end= ptr + strlen(ptr) - 1; + my_isspace(&my_charset_latin1, *(end - 1)); + end--) + {} + end[0]= 0; /* Cut off end space */ + + /* Print error msg if there is nothing after !include* directive */ + if (end <= ptr) + { + fprintf(stderr, + "error: Wrong '!%s' directive in config file: %s at line %d\n", + keyword, name, line); + return 0; + } + return ptr; +} + + +static char *find_end_comment(char *ptr) +{ + char quote= 0; /* we are inside quote marks */ + char escape= 0; /* symbol is protected by escape chagacter */ + + for (; *ptr; ptr++) + { + if ((*ptr == '\'' || *ptr == '\"') && !escape) + { + if (!quote) + quote= *ptr; + else if (quote == *ptr) + quote= 0; + } + /* We are not inside a string */ + if (!quote && *ptr == '#') + return ptr; + escape= (quote && *ptr == '\\' && !escape); + } + return ptr; +} + +struct generator +{ + /* the memory root for allocating line strings */ + MEM_ROOT alloc; + /* array of strings for the main content */ + DYNAMIC_ARRAY main; + /* + array of strings for options that should be added to the error_group + section + */ + DYNAMIC_ARRAY old_version; + /* + array of strings for options that should be added to the unsupported_group + section + */ + DYNAMIC_ARRAY unsupported_version; + /* array of strings to be added to the mariadbd section */ + DYNAMIC_ARRAY mariadbd_additions; + /* array of strings to be added to the client_server section */ + DYNAMIC_ARRAY client_server; + + struct upgrade_ctx *ctx; /* Current context */ + + const char *name; /* config file name */ + int start_of_group; /* Start of current group */ + int mariadbd_group_start; /* Start of last mariadbd group */ + uint line; /* Current line number */ + /* + one past the last index of the original mariadbd section in the main array + */ + int mariadbd_group_end; + /* the current group from which options are read */ + const char *input_group; + /* + The current group in the generated output. This may be different from + input_group if lines are moved between groups. + */ + char *output_group; + /* whether last main line is empty or not */ + my_bool prev_empty; + /* If we should copy [mysqld-xxx] options to [mariadbd] */ + my_bool copy_code_to_mariadb; + /* If current file is valid */ + my_bool file_valid; +}; + +static void generator_init(struct generator *generator) +{ + init_alloc_root(key_memory_upgrade_config, &generator->alloc, 512, 0, MYF(0)); + init_dynamic_array2(key_memory_upgrade_config, + &generator->main, + sizeof(char *), + NULL, + 0, + 0, + MYF(0)); + init_dynamic_array2(key_memory_upgrade_config, + &generator->old_version, + sizeof(char *), + NULL, + 0, + 0, + MYF(0)); + init_dynamic_array2(key_memory_upgrade_config, + &generator->unsupported_version, + sizeof(char *), + NULL, + 0, + 0, + MYF(0)); + init_dynamic_array2(key_memory_upgrade_config, + &generator->mariadbd_additions, + sizeof(char *), + NULL, + 0, + 0, + MYF(0)); + init_dynamic_array2(key_memory_upgrade_config, + &generator->client_server, + sizeof(char *), + NULL, + 0, + 0, + MYF(0)); + generator->mariadbd_group_end= -1; + generator->input_group= NULL; + generator->output_group= NULL; + /* don't add extra newlines to the beginning */ + generator->prev_empty= TRUE; + generator->copy_code_to_mariadb= 0; +} + + +/* + Delete data in mariadbd_additions that was found in last [mariadbd] group + + This is needed to ensure that we don't generate new lines into the + [mariadbd] group if we run the program twice on it +*/ + +static void delete_dup_data_from_mariadbd_group(struct generator *generator) +{ + if (generator->mariadbd_group_end >= 0) + { + for (int i= generator->mariadbd_group_start; + i < generator->mariadbd_group_end; + i++) + { + char *element= *(char **) dynamic_array_ptr(&generator->main, i); + delete_line(&generator->mariadbd_additions, element); + } + } +} + + +static my_bool change_output_group(struct generator *generator, + const char *group) +{ + char *group_dupe= my_strdup(key_memory_upgrade_config, group, MYF(0)); + if (!group_dupe) + return TRUE; + my_free(generator->output_group); + generator->output_group= group_dupe; + return FALSE; +} + +/* + Generate output lines for one section + Returns number of lines added +*/ + + +static int generate_write_section(FILE *target_file, + struct generator *generator, + DYNAMIC_ARRAY *array, + const char *group_name) +{ + int lines= 0; + if (array->elements > 0) + { + if (!generator->prev_empty) + fputc('\n', target_file); + fprintf(target_file, "[%s]\n", group_name); + change_output_group(generator, group_name); + for (uint i= 0; i < array->elements; i++) + { + char *element= *(char **)dynamic_array_ptr(array, i); + if (element) + { + fputs(element, target_file); + lines++; + } + } + generator->prev_empty= 0; + } + return lines; +} + + +/* + Generate output lines + Returns true if file changed +*/ + +static my_bool generator_write(MYSQL_FILE *f, struct generator *generator) +{ + FILE *target_file= f ? f->m_file : stdout; + size_t i; + size_t lines_handled= 0; + size_t new_lines; + + delete_dup_data_from_mariadbd_group(generator); + + if (generator->mariadbd_group_end >= 0) + { + /* + There was a mariadbd group in the file. Put all generated mariadbd + options into this group. + */ + for (i= 0; i < (size_t)generator->mariadbd_group_end; i++) + { + char *element= *(char **) dynamic_array_ptr(&generator->main, i); + fputs(element, target_file); + } + for (i= 0; i < generator->mariadbd_additions.elements; i++) + { + char *element= (*(char **) + dynamic_array_ptr(&generator->mariadbd_additions, i)); + if (element) /* Ignore deleted elements */ + { + fputs(element, target_file); + generator->prev_empty= element[0] == '\n'; + lines_handled++; + } + } + for (i= (size_t)generator->mariadbd_group_end; + i < generator->main.elements; + i++) + { + char *element= *(char **) dynamic_array_ptr(&generator->main, i); + fputs(element, target_file); + generator->prev_empty= element[0] == '\n'; + } + } + else + { + for (i= 0; i < generator->main.elements; i++) + { + char *element= *(char **) dynamic_array_ptr(&generator->main, i); + fputs(element, target_file); + generator->prev_empty= element[0] == '\n'; + } + + if (count_array_elements(&generator->mariadbd_additions) > 0) + lines_handled+= generate_write_section(target_file, + generator, + &generator->mariadbd_additions, + "mariadbd"); + } + generate_write_section(target_file, generator, + &generator->old_version, opt_error_group); + generate_write_section(target_file, generator, + &generator->unsupported_version, + opt_unsupported_group); + generate_write_section(target_file, generator, + &generator->client_server, + client_server_group); + + new_lines= (lines_handled + generator->old_version.elements + + generator->unsupported_version.elements + + generator->client_server.elements); + if (new_lines) + { + global_update_count+= new_lines; + generator->copy_code_to_mariadb= 0; + } + return new_lines != 0; +} + + +static void generator_count_lines(struct generator *generator) +{ + int mariadbd_additions; + + delete_dup_data_from_mariadbd_group(generator); + mariadbd_additions= count_array_elements(&generator->mariadbd_additions); + global_mariadbd_additions+= mariadbd_additions; + global_update_count+= (mariadbd_additions + + generator->old_version.elements + + generator->unsupported_version.elements + + generator->client_server.elements); + global_copied_lines+= generator->old_version.elements; + global_unsupported_lines+= generator->unsupported_version.elements; +} + + +static void report_line_changes() +{ + if (!opt_print && !opt_silent && opt_edit_mode == EDIT_MODE_NONE) + { + if (global_mariadbd_additions) + fprintf(stdout, "%lld line/lines would be copied to [mariadbd] group\n", + (longlong) global_mariadbd_additions); + if (global_copied_lines > 0) + fprintf(stdout, "%lld line/lines would be copied to [%s] group\n", + (longlong) global_copied_lines, opt_error_group); + if (global_unsupported_lines) + fprintf(stdout, "%lld line/lines would be copied to [%s] group\n", + (longlong) global_unsupported_lines, opt_unsupported_group); + } +} + + +static void generator_free(struct generator *generator) +{ + free_root(&generator->alloc, MYF(0)); + delete_dynamic(&generator->main); + delete_dynamic(&generator->old_version); + delete_dynamic(&generator->unsupported_version); + delete_dynamic(&generator->mariadbd_additions); + my_free(generator->output_group); +} + + +/* Called on include of new default file */ + +static void generator_reset(struct generator *generator) +{ + generator->main.elements= 0; + generator->old_version.elements= 0; + generator->unsupported_version.elements= 0; + generator->mariadbd_additions.elements= 0; + generator->mariadbd_group_end= -1; +} + + +static char *print_alloc(MEM_ROOT *alloc, const char *format, va_list args) +{ + int length; + char *p= NULL; + va_list args2; + va_copy(args2, args); + + length= vsnprintf(p, 0, format, args) + 1; + p= alloc_root(alloc, length); + if (!p) + return NULL; + vsnprintf(p, length, format, args2); + va_end(args2); + return p; +} + +static my_bool vadd_line(MEM_ROOT *alloc, DYNAMIC_ARRAY *array, + const char *format, va_list args) +{ + char *p; + p= print_alloc(alloc, format, args); + if (!p) + return TRUE; + return insert_dynamic(array, &p); +} + +static my_bool add_line(MEM_ROOT *alloc, DYNAMIC_ARRAY *array, + const char *format, ...) +{ + va_list args; + my_bool res; + va_start(args, format); + res= vadd_line(alloc, array, format, args); + va_end(args); + return res; +} + +/* + Delete elements from array if it already exits. + + Delete is done by setting pointer to string element to 0; +*/ + +static my_bool delete_line(DYNAMIC_ARRAY *array, char *line) +{ + for (uint i= 0; i < array->elements ; i++) + { + char *element= *dynamic_element(array, i, char**); + if (element && !strcmp(element, line)) + { + *((char**) dynamic_array_ptr(array, i))= NullS; + return 1; + } + } + return 0; +} + + +/* Count not null elements in the array */ + +static uint count_array_elements(DYNAMIC_ARRAY *array) +{ + uint count= 0; + for (uint i= 0; i < array->elements ; i++) + if (*dynamic_element(array, i, char**)) + count++; + return count; +} + +enum line_type +{ + LINE_TYPE_EMPTY, + LINE_TYPE_OPTION, + LINE_TYPE_OTHER, + LINE_TYPE_PASSTHROUGH +}; + + +static my_bool add_main_line(struct generator *generator, enum line_type type, + const char *format, ...) +{ + va_list args; + my_bool res; + /* Ensure that --print without edit doesn't loose space */ + my_bool delay_empty= (type == LINE_TYPE_EMPTY && + opt_edit_mode != EDIT_MODE_NONE); + + /* generator->input_group is empty for comments at top of include files */ + if (!delay_empty && generator->input_group && + (!generator->output_group || + strcmp(generator->input_group, generator->output_group))) + { + if (add_line(&generator->alloc, &generator->main, + generator->prev_empty ? "[%s]\n" : "\n[%s]\n", + generator->input_group)) + return TRUE; + if (change_output_group(generator, generator->input_group)) + return TRUE; + generator->start_of_group= (int) generator->main.elements; + } + va_start(args, format); + res= vadd_line(&generator->alloc, &generator->main, format, args); + va_end(args); + if (!res) + { + if (type == LINE_TYPE_OPTION && + !strcmp(generator->input_group, "mariadbd")) + { + generator->mariadbd_group_start= generator->start_of_group; + generator->mariadbd_group_end= (int) generator->main.elements; + } + + generator->prev_empty= (type == LINE_TYPE_EMPTY); + } + return res; +} + + +/* + Change file paths from /mysql ending with /, \, . space or \n to /mariadbd + + If string contains 'from' return allocated string otherwise return + NullS +*/ + +char *change_file_path(const char *line, LEX_CSTRING *from, LEX_CSTRING *to) +{ + const char *pos; + + for (pos= line ; (pos= strstr(pos, from->str)); pos++) + { + char end= pos[from->length]; + if (pos != line && (pos[-1] == '/' || pos[-1] == '\\') && + (end == pos[-1] || end == 0 || my_isspace(&my_charset_latin1, end) || + end == '.')) + { + /* Found path, change 'from' to 'to' */ + char *path= my_malloc(key_memory_upgrade_config, + strlen(line) - from->length + to->length + 1, + MYF(MY_WME)); + if (!path) + break; + memcpy(path, line, (size_t) (pos - line)); + strxmov(path + (pos - line), to->str, pos + from->length, NullS); + return path; + } + } + return NullS; +} + + + +/* Change path with warning */ + +static char *path_changed(struct generator *generator, const char *line) +{ + char *new_line; + if (!(new_line= change_file_path(line, &mysql_name, &mariadb_name)) && + !(new_line= change_file_path(line, &mysqld_name, &mariadb_name))) + return 0; + + if (!opt_print && opt_edit_mode == EDIT_MODE_NONE) + { + fprintf(stdout, "In %s at line %d: '%.*s' would be " + "replaced with '%.*s'\n", generator->name, generator->line, + (int) strlen(line)-1, line, + (int) strlen(new_line)-1, new_line); + global_update_count++; + // generator->ctx->failed= 1; + } + return new_line; +} + + +/* + find new name of renamed option +*/ + +const char *renamed_option(const char *option) +{ + struct RENAMED_OPTIONS *options; + for (options= renamed_options; options->from ; options++) + if (!strcmp(option, options->from)) + return options->to; + return 0; +} + + +void error_unknown_option(struct generator *generator, + struct upgrade_ctx *ctx, + const char *option, const char *value, + const char *org_line) +{ + const char *renamed; + + if (!opt_print && opt_edit_mode == EDIT_MODE_NONE && + !generator->copy_code_to_mariadb) + { + if ((renamed= renamed_option(option))) + { + if (value) + fprintf(stdout, "In %s at line %u: '%.*s' would be " + "replaced with '%s=%.*s'\n", generator->name, generator->line, + (int) strlen(org_line)-1, org_line, renamed, + (int) strlen(value)-1, value); + else + fprintf(stdout, "In %s at line %u: '%.*s' would be " + "replaced with '%s'\n", generator->name, generator->line, + (int) strlen(org_line)-1, org_line, renamed); + } + else + { + fprintf(stdout, "In %s at line %u: Invalid option %s\n", generator->name, + generator->line, option); + } + // ctx->failed= 1; + global_update_count++; + } + if (!strncmp(option, STRING_WITH_LEN("audit_log")) && + !audit_plugin_warning++ && !opt_silent) + fprintf(stdout, "Warning: Please replace audit_log with the server_audit " + "plugin\n"); +} + + +/* + Store value for socket= option if used + @return 1 if socket found + @return 0 no socket. +*/ + +my_bool check_if_socket(const char *option, const char *value) +{ + if (!strcmp(option, "socket")) + { + const char *end; + my_free(value_socket); + + /* The string may have an '\n' if paths has changed */ + if (!(end= strchr(value, '\n'))) + end= strend(value); + value_socket= my_strndup(key_memory_upgrade_config, value, (end-value), + MYF(MY_WME)); + return 1; /* Socket found */ + } + return 0; +} + +/** + Write the given line to generator output as specified by opt_edit_mode. + Returns false on success and true on failure. +*/ +static my_bool generator_add_line(struct generator *generator, const char *line, + enum line_type type, my_bool is_valid) +{ + if (generator->copy_code_to_mariadb && is_valid && type != LINE_TYPE_EMPTY) + { + /* Copy lines from [mysqld-XXX] group to [mariadbd] */ + const char *pos= line, *new_line= 0; + if (opt_update_paths && + (new_line= path_changed(generator, line))) + pos= new_line; + add_line(&generator->alloc, &generator->mariadbd_additions, "%s", pos); + my_free((char*) new_line); + } + if (generator->copy_code_to_mariadb) + is_valid= 1; /* Print line to [mysqld-XXX] groups */ + + switch (opt_edit_mode) { + case EDIT_MODE_REMOVE: + global_update_count+= MY_TEST(!is_valid); + return is_valid ? add_main_line(generator, type, "%s", line) : FALSE; + case EDIT_MODE_LAST: + if (is_valid || type == LINE_TYPE_EMPTY) + return add_main_line(generator, type, "%s", line); + if (strcmp(generator->input_group, "mariadbd")) + return add_line(&generator->alloc, &generator->old_version, "%s", line); + return add_line(&generator->alloc, &generator->unsupported_version, "%s", + line); + case EDIT_MODE_COMMENT: + global_update_count+= MY_TEST(!is_valid); + return add_main_line(generator, type, is_valid ? "%s" : "#%s", line); + case EDIT_MODE_INLINE: + { + const char *old_input_group= generator->input_group; + my_bool res= TRUE; + global_update_count+= MY_TEST(!is_valid); + if (!is_valid) + generator->input_group= (strcmp(generator->input_group, "mariadbd") ? + opt_error_group : + opt_unsupported_group); + if (!add_main_line(generator, is_valid ? type : LINE_TYPE_OTHER, "%s", + line)) + res= FALSE; + generator->input_group= old_input_group; + return res; + } + case EDIT_MODE_NONE: + return opt_print ? add_main_line(generator, type, "%s", line) : 0; + } + return TRUE; +} + + +static int process_default_file_with_ext(struct upgrade_ctx *ctx, + const char *dir, const char *ext, + const char *config_file, + int recursion_level) +{ + char name[FN_REFLEN + 10], buff[4096], curr_gr[4096], *ptr, *end, **tmp_ext; + char tmp_name[FN_REFLEN + 30], restored_name[FN_REFLEN + 30]; + char option_buff[4096+2], conv_option[128], tmp[FN_REFLEN]; + char *value, *option, *option_value_start, *new_line, *end_of_option; + const char *renamed; + static const char includedir_keyword[]= "includedir"; + static const char include_keyword[]= "include"; + const int max_recursion_level= 10; + MYSQL_FILE *fp; + MYSQL_FILE *tmp_fp= NULL; + my_bool group_is_mariadbd= FALSE; + my_bool group_is_mysqld= FALSE; + uint option_start; + enum { NONE, PARSE, SKIP } found_group= NONE; + my_bool skip_prefix= 0, generator_inited= 0; + size_t i; + MY_DIR *search_dir; + FILEINFO *search_file; + struct generator generator; + + if (recursion_level == 0) + { + value_port= 0; + my_free(value_socket); + value_socket= 0; + found_skip_slave_start= FALSE; + found_innodb_log_files_in_group= 0; + found_innodb_log_file_size= 0; + found_character_set_server= 0; + value_innodb_log_files_in_group= 0; + value_innodb_log_file_size= 0; + suffix_innodb_log_file_size= 0; + found_mariadb_replication_compatibility= 0; + found_mysql_replication_compatibility= 0; + found_client_server_group= 0; + } + + if (safe_strlen(dir) + strlen(config_file) >= FN_REFLEN-3) + return 0; /* Ignore wrong paths */ + if (dir) + { + end=convert_dirname(name, dir, NullS); + if (dir[0] == FN_HOMELIB) /* Add . to filenames in home */ + *end++='.'; + strxmov(end,config_file,ext,NullS); + } + else + { + strmov(name,config_file); + } + fn_format(name,name,"","",4); +#if !defined(_WIN32) + { + MY_STAT stat_info; + if (!my_stat(name,&stat_info, + MYF(give_error_for_missing_files ? MY_WME : 0))) + return 1; + /* + Ignore world-writable regular files (exceptions apply). + This is mainly done to protect us to not read a file that may be + modified by anyone. + + Also check access so that read only mounted (EROFS) + or immutable files (EPERM) that are suitable protections. + + The main case we are allowing is a container readonly volume mount + from a filesystem that doesn't have unix permissions. This will + have a 0777 permission and access will set errno = EROFS. + + Note if a ROFS has a file with permissions 04n6, access sets errno + EACCESS, rather the ROFS, so in this case we'll error, even though + the ROFS is protecting the file. + + An ideal, race free, implementation would do fstat / fstatvfs / ioctl + for permission, read only filesystem, and immutability resprectively. + */ + if ((stat_info.st_mode & S_IWOTH) && + (stat_info.st_mode & S_IFMT) == S_IFREG && + (access(name, W_OK) == 0 || (errno != EROFS && errno != EPERM))) + { + fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n", + name); + return 0; + } + } +#endif + if (!(fp= mysql_file_fopen(key_file_cnf, name, O_RDONLY, MYF(MY_WME)))) + return 1; /* Ignore wrong files */ + + if (opt_update) + { + strmov(strmov(tmp_name, name), "-upgrade-config"); + strmov(strmov(restored_name, name), "-upgrade-config-orig"); + if (!(tmp_fp= mysql_file_fopen(key_file_cnf, tmp_name, + O_RDWR | O_CREAT | O_TRUNC, MYF(0)))) + { + fprintf(stderr, "error: Failed to open %s for writing: %s\n", tmp_name, + strerror(errno)); + goto err; + } + } + + generator_init(&generator); + generator_inited= 1; + generator.name= name; + generator.ctx= ctx; + generator.file_valid= TRUE; + generator.line= 0; + + if (opt_print || (opt_edit_mode != EDIT_MODE_NONE && !opt_update)) + fprintf(stdout, "### File %s:\n", name); + while (mysql_file_fgets(buff, sizeof(buff) - 3, fp)) + { + my_bool line_valid= TRUE; + int invalid_set_index; + generator.line++; + /* Ignore comment and empty lines */ + for (ptr= buff; my_isspace(&my_charset_latin1, *ptr); ptr++) + {} + + /* Ensure line ends with \n (delete_line code depends one this) */ + end= strend(ptr); + if (end != ptr && end[-1] != '\n') + { + end[0]= '\n'; + end[1]= 0; + } + + if (*ptr == '#' || *ptr == ';' || !*ptr) + { + if (is_prefix(ptr, mariadb_replication_compatibility_comment)) + { + /* File is already updated */ + found_mariadb_replication_compatibility= 0; + } + if (is_prefix(ptr, mysql_replication_compatibility_comment)) + { + /* File is already updated */ + found_mysql_replication_compatibility= 0; + } + generator_add_line(&generator, buff, + *ptr ? LINE_TYPE_OTHER : LINE_TYPE_EMPTY, line_valid); + continue; + } + + /* Configuration File Directives */ + if (*ptr == '!' || *ptr == '?') + { + /* Write out current cached items before include directive */ + my_bool prev_empty= generator.prev_empty; + if (opt_print || opt_update) + { + if (generator_write(tmp_fp, &generator)) + generator.file_valid= FALSE; + } + else + generator_count_lines(&generator); + generator_reset(&generator); + /* Ensure that when using --print we get !include next */ + if (prev_empty && !generator.prev_empty) + generator_add_line(&generator, "\n", LINE_TYPE_EMPTY, 1); + generator_add_line(&generator, buff, LINE_TYPE_PASSTHROUGH, 1); + generator_write(tmp_fp, &generator); + generator_reset(&generator); + + if (recursion_level >= max_recursion_level) + { + for (end= ptr + strlen(ptr) - 1; + my_isspace(&my_charset_latin1, *(end - 1)); + end--) + {} + end[0]= 0; + fprintf(stderr, + "Warning: skipping '%s' directive as maximum include" + "recursion level was reached in file %s at line %d\n", + ptr, name, generator.line); + continue; + } + + /* skip over `!' and following whitespace */ + for (++ptr; my_isspace(&my_charset_latin1, ptr[0]); ptr++) + {} + + if ((!strncmp(ptr, includedir_keyword, + sizeof(includedir_keyword) - 1)) && + my_isspace(&my_charset_latin1, ptr[sizeof(includedir_keyword) - 1])) + { + if (!(ptr= get_argument(includedir_keyword, + sizeof(includedir_keyword), + ptr, name, generator.line))) + goto err; + + if (!(search_dir= my_dir(ptr, MYF(MY_WME | MY_WANT_SORT)))) + goto err; + + for (i= 0; i < search_dir->number_of_files; i++) + { + search_file= search_dir->dir_entry + i; + ext= fn_ext2(search_file->name); + + /* check extension */ + for (tmp_ext= (char**) f_extensions; *tmp_ext; tmp_ext++) + { + if (!strcmp(ext, *tmp_ext)) + break; + } + + if (*tmp_ext) + { + fn_format(tmp, search_file->name, ptr, "", + MY_UNPACK_FILENAME | MY_SAFE_PATH); + + process_default_file_with_ext(ctx, "", "", tmp, + recursion_level + 1); + if (opt_print || (opt_edit_mode != EDIT_MODE_NONE && !opt_update)) + fprintf(stdout, "### Back in %s:\n", name); + } + } + + my_dirend(search_dir); + } + else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) && + my_isspace(&my_charset_latin1, ptr[sizeof(include_keyword)-1])) + { + if (!(ptr= get_argument(include_keyword, + sizeof(include_keyword), ptr, + name, generator.line))) + goto err; + + process_default_file_with_ext(ctx, "", "", ptr, recursion_level + 1); + if (opt_print || (opt_edit_mode != EDIT_MODE_NONE && !opt_update)) + fprintf(stdout, "### Back in %s:\n", name); + } + continue; + } + + if (*ptr == '[') /* Group name */ + { + if (!(end=(char *) strchr(++ptr,']'))) + { + fprintf(stderr, + "error: Wrong group definition in config file: %s at line %d\n", + name, generator.line); + goto err; + } + /* Remove end space */ + for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ; + end[0]=0; + + strmake(curr_gr, ptr, MY_MIN((size_t) (end-ptr), sizeof(curr_gr)-1)); + group_is_mariadbd= !strcmp(curr_gr, "mariadbd"); + group_is_mysqld= (!strcmp(curr_gr, "mysqld") || + !strcmp(curr_gr, "server")); + found_client_server_group|= !strcmp(curr_gr, client_server_group); + + generator.copy_code_to_mariadb= 0; + found_group= find_type(curr_gr, ctx->group, FIND_TYPE_NO_PREFIX) + ? PARSE : SKIP; + /* Ensure we process all groups with the mysqld prefix */ + if (found_group == SKIP) + { + if (!strncmp(curr_gr, "mysqld-", 7) && opt_copy_mysqld_groups) + { + found_group= PARSE; + /* Copy all valid code from the mysqld- group to the mariadbd group */ + generator.copy_code_to_mariadb= 1; + } + } + + generator.input_group= curr_gr; + if (found_group == PARSE && group_is_mariadbd) + { + /** + Force the mariadbd group to be emitted to allow potentially adding + new lines to it. + */ + generator_add_line(&generator, "", LINE_TYPE_OPTION, TRUE); + } + continue; + } + switch (found_group) { + case NONE: + fprintf(stderr, + "error: Found option without preceding group in config " + "file: %s at line: %d\n", + name, generator.line); + goto err; + case PARSE: + if (opt_print && opt_edit_mode == EDIT_MODE_NONE) + { + generator_add_line(&generator, buff, LINE_TYPE_OPTION, TRUE); + continue; + } + break; + case SKIP: + if (group_is_mariadbd && + (opt_edit_mode == EDIT_MODE_INLINE || + opt_edit_mode == EDIT_MODE_LAST)) + { + /* Remove lines with the /mysql/ path */ + char *pos= change_file_path(buff, &mariadb_name, &mysql_name); + if (pos) + { + delete_line(&generator.mariadbd_additions, pos); + my_free(pos); + } + delete_line(&generator.mariadbd_additions, buff); + } + generator_add_line(&generator, buff, LINE_TYPE_OPTION, line_valid); + continue; + } + + end= end_of_option= find_end_comment(ptr); + if ((value= strchr(ptr, '=')) && value < end_of_option) + end= value; + else + value= 0; + + for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) + ; + ptr= strmake(option_buff, ptr, (size_t) (end-ptr)); + + /* Change '-' to '_' in the option */ + { + char *from, *from_end, *to; + from_end= option_buff + sizeof(conv_option)-1; + for (from= option_buff, to= conv_option; + *from && from < from_end; + from++, to++) + *to= (*from == '-') ? '_' : *from; + *to= 0; + option_start= 0; + skip_prefix= 0; + + /* Ignore some prefix */ + for (uint i= 0; special_opt_prefix[i] ; i++) + { + if (!strncmp(conv_option, special_opt_prefix[i], + special_opt_prefix_lengths[i]) && + conv_option[special_opt_prefix_lengths[i]] == '_' && + conv_option[special_opt_prefix_lengths[i]+1]) + { + option_start= special_opt_prefix_lengths[i]+1; + skip_prefix= i == 0; /* skip- */ + break; + } + } + } + option= conv_option + option_start; + + if (value) + { + /* Remove pre- and end space */ + char *value_end; + my_bool tmp; + + for (value++ ; my_isspace(&my_charset_latin1,*value); value++) ; + value_end= end_of_option; + /* + We don't have to test for value_end >= value as we know there is + an '=' before + */ + for ( ; my_isspace(&my_charset_latin1,value_end[-1]) ; value_end--) ; + if (value_end < value) /* Empty string */ + value_end= value; + + /* remove quotes around argument */ + if ((*value == '\"' || *value == '\'') && /* First char is quote */ + (value + 1 < value_end ) && /* String is longer than 1 */ + *value == value_end[-1] ) /* First char is equal to last char */ + { + value++; + value_end--; + } + *ptr++= 0; + option_value_start= ptr; + + tmp= mariadbd_option_exists(option); + if (!tmp && skip_prefix && mariadbd_option_exists(conv_option)) + { + /* Option only exists with the 'skip-' prefix */ + tmp= 1; + option= conv_option; /* Option with skip- prefix */ + } + if (!tmp) + { + if (generator.copy_code_to_mariadb) /* [mysqld-#] group */ + { + /* Changes will be detected in generator_write() */ + generator_add_line(&generator, buff, LINE_TYPE_OPTION, FALSE); + continue; + } + line_valid= FALSE; + generator.file_valid= FALSE; + + error_unknown_option(&generator, ctx, conv_option, value, buff); + if (!opt_print && opt_edit_mode == EDIT_MODE_NONE) + continue; + } + for ( ; value != value_end; value++) + { + if (*value == '\\' && value != value_end-1) + { + switch(*++value) { + case 'n': + *ptr++='\n'; + break; + case 't': + *ptr++= '\t'; + break; + case 'r': + *ptr++ = '\r'; + break; + case 'b': + *ptr++ = '\b'; + break; + case 's': + *ptr++= ' '; /* space */ + break; + case '\"': + *ptr++= '\"'; + break; + case '\'': + *ptr++= '\''; + break; + case '\\': + *ptr++= '\\'; + break; + default: /* Unknown; Keep '\' */ + *ptr++= '\\'; + *ptr++= *value; + break; + } + } + else + *ptr++= *value; + } + *ptr=0; + if (!mariadbd_valid_enum_value(option, option_value_start)) + { + line_valid= FALSE; + generator.file_valid= FALSE; + if (!opt_print && opt_edit_mode == EDIT_MODE_NONE) + { + fprintf(stdout, + "In %s at line %d: Invalid enum value '%s' for option %s\n", + name, generator.line, option_value_start, option); + global_update_count++; + // ctx->failed= 1; + continue; + } + } + else if ((invalid_set_index= + mariadbd_check_set_value(option, option_value_start))) + { + line_valid= FALSE; + generator.file_valid= FALSE; + if (!opt_print && opt_edit_mode == EDIT_MODE_NONE) + { + fprintf(stdout, "In %s at line %d: Invalid set value '%s' at " + "index %d for option %s\n", + name, generator.line, option_value_start, invalid_set_index, + option); + global_update_count++; + // ctx->failed= 1; + continue; + } + } + else if (check_plugin_option(ctx, option, option_value_start, name, + generator.line)) + { + line_valid= FALSE; + generator.file_valid= FALSE; + } + else if (group_is_mysqld && line_valid && + opt_update_paths && + (new_line= path_changed(&generator, buff))) + { + line_valid= FALSE; + + /* We have alread validated that buff contains an '=' */ + check_if_socket(option, strchr(new_line, '=')+1); + if ((opt_edit_mode == EDIT_MODE_INLINE || + opt_edit_mode == EDIT_MODE_LAST)) + { + generator_add_line(&generator, buff, LINE_TYPE_OPTION, FALSE); + add_line(&generator.alloc, &generator.mariadbd_additions, "%s", + new_line); + my_free(new_line); + continue; + } + my_free(new_line); + } + else if (!group_is_mariadbd && + !strcmp(option, "key_buffer_size") && + (opt_no_myisam_options || opt_convert_from == FROM_MYSQL) && + ((!opt_print && opt_edit_mode == EDIT_MODE_NONE) || + opt_edit_mode == EDIT_MODE_INLINE || + opt_edit_mode == EDIT_MODE_LAST)) + { + generator.file_valid= FALSE; + if (opt_edit_mode == EDIT_MODE_NONE) + { + { + fprintf(stdout, "In %s at line %d: key_buffer_size needs " + "modifications. If you want to git rid of this warning and " + "keep as it now, move it to the [mariadbd] group\n", + name, generator.line); + global_update_count++; + } + continue; + } + generator_add_line(&generator, buff, LINE_TYPE_OPTION, FALSE); + if (opt_no_myisam_options) + { + add_line(&generator.alloc, &generator.mariadbd_additions, + "key_buffer_size=64K # Recommended value if no " + "MyISAM tables\n"); + snprintf(conv_option, sizeof(conv_option)-1, + "aria_pagecache_buffer_size=%s", + option_value_start); + add_line(&generator.alloc, &generator.mariadbd_additions, "%s\n", + conv_option); + if (!opt_silent) + fprintf(stdout, "Note: '%s' added to [mariadbd] group\n", + conv_option); + } + else if (opt_convert_from == FROM_MYSQL) + { + add_line(&generator.alloc, &generator.mariadbd_additions, "%s", buff); + add_line(&generator.alloc, &generator.mariadbd_additions, + "#key_buffer_size=64K " + "# Recommended value if no MyISAM tables\n"); + snprintf(conv_option, sizeof(conv_option)-1, + "aria_pagecache_buffer_size=%s", + option_value_start); + add_line(&generator.alloc, &generator.mariadbd_additions, "%s\n", + conv_option); + if (!opt_silent) + fprintf(stdout, "Note: %s added to [mariadbd] group\n", + conv_option); + } + continue; + } + else if (!group_is_mariadbd && + !strcmp(option, "innodb_log_files_in_group")) + { + found_innodb_log_files_in_group= 1; + value_innodb_log_files_in_group= atoi(option_value_start); + if (!value_innodb_log_files_in_group) + value_innodb_log_files_in_group= 1; /* Ensure it is not 0 */ + } + else if (!strcmp(option, "innodb_log_file_size")) + { + if (group_is_mariadbd) + { + /* Already handled. Don't add it again */ + found_innodb_log_file_size= 0; + found_innodb_log_files_in_group= 0; + } + else + { + int error; + char *int_end= 0; + value_innodb_log_file_size= my_strtoll10(option_value_start, + &int_end, &error); + found_innodb_log_file_size= (value_innodb_log_file_size != 0 && + error == 0); + suffix_innodb_log_file_size= *int_end; + } + } + else if (!strcmp(option, "character_set_server") || + !strcmp(option, "collation_server")) + { + found_character_set_server= 1; + } + else if (group_is_mysqld && !strcmp(option, "port")) + { + int error; + char *int_end= 0; + value_port= my_strtoll10(option_value_start, &int_end, &error); + } + else if (group_is_mysqld && check_if_socket(option, option_value_start)) + { + } + else if ((renamed= renamed_option(option))) + { + generator_add_line(&generator, buff, LINE_TYPE_OPTION, FALSE); + add_line(&generator.alloc, &generator.mariadbd_additions, + "%s=%s\n", renamed, option_value_start); + continue; + } + } /* !value */ + else if (!group_is_mariadbd && !strcmp(option, "skip_slave_start")) + { + found_skip_slave_start= TRUE; + } + else if (!mariadbd_option_exists(option) && + !(skip_prefix && mariadbd_option_exists(conv_option))) + { + line_valid= FALSE; + generator.file_valid= FALSE; + + error_unknown_option(&generator, ctx, conv_option, NullS, buff); + + if (!opt_print && opt_edit_mode == EDIT_MODE_NONE && + !generator.copy_code_to_mariadb) + continue; + } + else if ((renamed= renamed_option(option))) + { + generator_add_line(&generator, buff, LINE_TYPE_OPTION, FALSE); + add_line(&generator.alloc, &generator.mariadbd_additions, + "%s\n", renamed); + continue; + } + generator_add_line(&generator, buff, LINE_TYPE_OPTION, line_valid); + } + mysql_file_fclose(fp, MYF(0)); + fp= 0; + + if (recursion_level == 0) + { + if (found_innodb_log_file_size && found_innodb_log_files_in_group) + { + generator.file_valid= FALSE; + snprintf(conv_option, sizeof(conv_option)-1, + "innodb_log_file_size=%llu%c", + value_innodb_log_file_size * value_innodb_log_files_in_group, + (my_islower(&my_charset_latin1, suffix_innodb_log_file_size) || + my_isupper(&my_charset_latin1, suffix_innodb_log_file_size)) ? + suffix_innodb_log_file_size : ' '); + add_line(&generator.alloc, &generator.mariadbd_additions, "%s\n", conv_option); + if (!opt_silent) + fprintf(stdout, "Note: '%s' added to [mariadbd] group based on " + "innodb_log_file_size * innodb_log_files_in_group\n", conv_option); + found_innodb_log_file_size= found_innodb_log_files_in_group= 0; + } + if (opt_add_client_server_group && !found_client_server_group) + { + if (value_port) + add_line(&generator.alloc, &generator.client_server, + "port=%lld\n", value_port); + if (value_socket) + { + add_line(&generator.alloc, &generator.client_server, + "socket=%s\n", value_socket); + my_free(value_socket); + value_socket= 0; + } + } + /* The following options should only be added once */ + if (!add_new_options_once || !new_options_added) + { + new_options_added= 1; + + /* Add generated options to mariadbd section */ + if (opt_add_skip_slave_start && !found_skip_slave_start) + { + generator.file_valid= FALSE; + add_line(&generator.alloc, &generator.mariadbd_additions, + "skip_slave_start\n"); + found_skip_slave_start= 0; + } + if (opt_add_mariadb_replication_compatibility && + !found_mariadb_replication_compatibility) + { + generator.file_valid= FALSE; + /* We do this line by line to get correct row numbers for reporting */ + add_line(&generator.alloc, &generator.old_version, + "%s\n", mariadb_replication_compatibility_comment); + add_line(&generator.alloc, &generator.old_version, + "loose-binlog_row_value_options=\"\"\n"); + add_line(&generator.alloc, &generator.old_version, + "loose-binlog_transaction_compression=0\n"); + add_line(&generator.alloc, &generator.old_version, + "# Not required, but recommended for cross_replication\n"); + add_line(&generator.alloc, &generator.old_version, + "binlog_format=row\n"); + } + if (opt_add_mysql_replication_compatibility && + !found_mysql_replication_compatibility) + { + add_line(&generator.alloc, &generator.mariadbd_additions, + "%s\n", mysql_replication_compatibility_comment); + add_line(&generator.alloc, &generator.mariadbd_additions, + "encrypt_binlog=0\n"); + add_line(&generator.alloc, &generator.mariadbd_additions, + "log_bin_compress=0\n"); + add_line(&generator.alloc, &generator.mariadbd_additions, + "# Not required, but recommended for cross_replication\n"); + add_line(&generator.alloc, &generator.mariadbd_additions, + "binlog_format=row\n"); + if (!found_character_set_server) + { + add_line(&generator.alloc, &generator.mariadbd_additions, + "# Character set to be able to replicate new tables to " + "MySQL 8.0\n"); + add_line(&generator.alloc, &generator.mariadbd_additions, + "character_set_server=utf8mb4\n"); + add_line(&generator.alloc, &generator.mariadbd_additions, + "collation_server=utf8mb4_0900_ai_ci\n"); + if (!opt_silent) + fprintf(stdout, "Note: Added MySQL default character sets and " + "collation to [mariadbd] to be able to replicate to " + "MySQL\n"); + found_character_set_server= 0; + } + } + } + } + if (opt_print || opt_update) + { + if (generator_write(tmp_fp, &generator)) + generator.file_valid= 0; + } + else + generator_count_lines(&generator); + generator_free(&generator); + if (recursion_level == 0) + { + my_free(value_socket); + value_socket= 0; + } + + if (tmp_fp) + { + mysql_file_fclose(tmp_fp, MYF(0)); + tmp_fp= 0; + if (generator.file_valid) + { + my_delete(tmp_name, MYF(0)); + } + else + { + myf redel_flags = opt_backup ? MYF(MY_REDEL_MAKE_BACKUP) : MYF(0); + char *duped_name= my_strdup(key_memory_upgrade_config, name, MYF(0)); + if (!duped_name || insert_dynamic(&ctx->updated_files, &duped_name)) + goto err; + /* + Copy the file in case running mariadbd fails and the update must be + reverted. + */ + if (my_copy(name, restored_name, MYF(0))) + { + fprintf(stderr, "error: Failed to copy %s to %s: %s", + name, restored_name, strerror(errno)); + return -1; + } + if (my_redel(name, tmp_name, time(NULL), redel_flags)) + { + fprintf(stderr, "error: Failed to rename %s to %s: %s", + tmp_name, name, strerror(errno)); + return -1; + } + } + } + if (opt_print || (opt_edit_mode != EDIT_MODE_NONE && !opt_update)) + fputc('\n', stdout); + return(0); + +err: + if (fp) + mysql_file_fclose(fp, MYF(0)); + if (tmp_fp) + mysql_file_fclose(tmp_fp, MYF(0)); + if (generator_inited) + generator_free(&generator); + if (recursion_level == 0) + { + my_free(value_socket); + value_socket= 0; + } + return -1; /* Fatal error */ +} + + +static int process_default_file(struct upgrade_ctx *ctx, + const char *dir, + const char *config_file) +{ + char **ext; + const char *empty_list[]= { "", 0 }; + my_bool have_ext= fn_ext(config_file)[0] != 0; + const char **exts_to_use= have_ext ? empty_list : f_extensions; + + for (ext= (char**) exts_to_use; *ext; ext++) + { + int error; + if ((error= process_default_file_with_ext(ctx, dir, *ext, config_file, + 0)) < 0) + return error; + } + return 0; +} + + +static int process_option_files(const char *conf_file, + struct upgrade_ctx *ctx, + const char **default_directories) +{ + const char **dirs; + int error= 0; + + if (my_defaults_group_suffix) + { + /* Handle --defaults-group-suffix= */ + uint i; + const char **extra_groups; + const size_t instance_len= strlen(my_defaults_group_suffix); + char *ptr; + TYPELIB *group= ctx->group; + + if (!(extra_groups= + (const char**)alloc_root(ctx->alloc, + (2*group->count+1)*sizeof(char*)))) + return 2; + + for (i= 0; i < group->count; i++) + { + size_t len; + extra_groups[i]= group->type_names[i]; /** copy group */ + + len= strlen(extra_groups[i]); + if (!(ptr= alloc_root(ctx->alloc, (uint) (len+instance_len+1)))) + return 2; + + extra_groups[i+group->count]= ptr; + + /** Construct new group */ + memcpy(ptr, extra_groups[i], len); + memcpy(ptr+len, my_defaults_group_suffix, instance_len+1); + } + + group->count*= 2; + group->type_names= extra_groups; + group->type_names[group->count]= 0; + } + + if (my_defaults_file) + { + if ((error= process_default_file_with_ext(ctx, "", "", + my_defaults_file, 0)) < 0) + goto err; + if (error > 0) + { + fprintf(stderr, "Could not open required defaults file: %s\n", + my_defaults_file); + goto err; + } + } + else if (dirname_length(conf_file) || !default_directories) + { + if ((error= process_default_file(ctx, NullS, conf_file)) < 0) + goto err; + } + else + { + for (dirs= default_directories ; *dirs; dirs++) + { + if (**dirs) + { + if (process_default_file(ctx, *dirs, conf_file) < 0) + goto err; + } + else if (my_defaults_extra_file) + { + if ((error= process_default_file_with_ext(ctx, "", "", + my_defaults_extra_file, + 0)) < 0) + goto err; /* Fatal error */ + if (error > 0) + { + fprintf(stderr, "Could not open required defaults file: %s\n", + my_defaults_extra_file); + goto err; + } + } + } + } + + return 0; + +err: + fprintf(stderr,"Fatal error in defaults handling. Program aborted\n"); + return 1; +} + + +/* + Process defaults + + @args default_args --default options. Sent forward to mariadbd + @args default_args_count Number of default options + + @return 0 ok + @return 1 general error + @return 2 memory allocation error +*/ + +static int process_defaults(const char *conf_file, + const char **groups, + const char **dirs, + const char **defaults_args, + int defaults_args_count) +{ + int error= 0; + MEM_ROOT alloc; + TYPELIB group; + struct upgrade_ctx ctx; + char executable[FN_REFLEN]; + + init_alloc_root(key_memory_upgrade_config, &alloc, 512, 0, MYF(0)); + + group.count= 0; + group.name= "defaults"; + group.type_names= groups; + + for (; *groups ; groups++) + group.count++; + + ctx.alloc= &alloc; + ctx.group= &group; + init_dynamic_array2(key_memory_upgrade_config, + &ctx.updated_files, + sizeof(char *), + NULL, + 0, + 0, + MYF(0)); + ctx.failed= 0; + + if ((error= process_option_files(conf_file, &ctx, dirs))) + { + finish_updated_files(&ctx, FALSE); + free_root(&alloc,MYF(0)); + return error; + } + + if (opt_mariadbd_testing) + { + DYNAMIC_STRING mariadbd_output; + const char *mariadbd_name= IF_WIN("mariadbd.exe", "mariadbd"); + const char *used_name; + + if (opt_mariadbd) + used_name= opt_mariadbd; + else + { + used_name= mariadbd_name; + if (!(error= (find_file_in_path(executable, mariadbd_name) != 0))) + used_name= executable; + } + if (!error) + error= access(used_name, X_OK); + + if (error) + { + fprintf(stderr, + "Cannot execute '%s' to test if the new option files " + "works (error %d)\n" + "Try specifiying the full path for the MariaDB server with " + "--mariadbd=...\n", + used_name, (int) errno); + finish_updated_files(&ctx, 1); + return 1; + } + + if (init_dynamic_string(&mariadbd_output, "", 32, 32)) + goto err; + if (!test_mariadbd(used_name) && + (error= run_mariadbd(used_name, &mariadbd_output, defaults_args, + defaults_args_count))) + { + if (ctx.updated_files.elements) + fprintf(stderr, "error: Failed to run %s with the updated files, " + "reverting\n", used_name); + else + fprintf(stderr, "error: Failed to run %s with the original files.\n", + used_name); + if (error > 0) + fprintf(stderr, "mariadbd output:\n%s", mariadbd_output.str); + } + dynstr_free(&mariadbd_output); + } + + if (finish_updated_files(&ctx, error == 0)) + error= 1; + free_root(&alloc, MYF(0)); + return error; + +err: + finish_updated_files(&ctx, FALSE); + free_root(&alloc, MYF(0)); + return 1; +} + + +static const char *config_file="my"; /* Default config file */ + +enum upgrade_config_options +{ + OPT_UPDATE = 256, + OPT_BACKUP, + OPT_ERROR_GROUP, + OPT_UNSUPPORTED_GROUP, + OPT_EDIT, + OPT_PRINT, + OPT_NO_MYISAM_OPTIONS, + OPT_ADD_SKIP_SLAVE_START, + OPT_FIX_ALL, + OPT_CONVERT_FROM, + OPT_UPDATE_PATHS, + OPT_VERIFY, + OPT_MARIADBD, + OPT_ADD_MYSQL_REPLICATION_COMPATIBILITY, + OPT_ADD_MARIADB_REPLICATION_COMPATIBILITY, + OPT_COPY_MYSQLD_GROUPS, + OPT_GENERATE_CLIENT_SERVER_GROUP +}; + +static struct my_option my_long_options[] = +{ + {"add-skip-slave-start", OPT_ADD_SKIP_SLAVE_START, + "Add skip_slave_start to the [mariadbd] group if not present.", + &opt_add_skip_slave_start, &opt_add_skip_slave_start, + 0, GET_BOOL, NO_ARG, FALSE, 0, 0, 0, 0, 0}, + {"add-mariadb-replication-compatibility", + OPT_ADD_MARIADB_REPLICATION_COMPATIBILITY, + "Add options to [error-group] to enable MySQL to replicate to MariaDB. " + "Options added are: " + "binlog-row-value-options=\"\" binlog_transaction_compression=0 and " + "binlog_format=row.", + &opt_add_mariadb_replication_compatibility, + &opt_add_mariadb_replication_compatibility, + 0, GET_BOOL, NO_ARG, FALSE, 0, 0, 0, 0, 0}, + {"add-mysql-replication-compatibility", + OPT_ADD_MYSQL_REPLICATION_COMPATIBILITY, + "Add options to [mariadbd] section to enable MariaDB to replicate to MySQL.", + &opt_add_mysql_replication_compatibility, + &opt_add_mysql_replication_compatibility, + 0, GET_BOOL, NO_ARG, FALSE, 0, 0, 0, 0, 0}, + {"add-client-server-group", + OPT_ADD_MYSQL_REPLICATION_COMPATIBILITY, + "Add a [client-server] group if it does not exists. This will contain the " + "last port and socket found in the [mysqld] or [server] groups.", + &opt_add_client_server_group, + &opt_add_client_server_group, + 0, GET_BOOL, NO_ARG, FALSE, 0, 0, 0, 0, 0}, + {"backup", OPT_BACKUP, + "Backup the updated configuration files. The backup file name are of the " + "type: 'original_name'-timestamp.BAK", + &opt_backup, &opt_backup, 0, GET_BOOL, NO_ARG, FALSE, 0, 0, 0, 0, 0}, + {"copy-mysqld-groups", OPT_COPY_MYSQLD_GROUPS, + "Copy valid MariaDB options from [mysqld-###] groups to the [mariadbd] " + "group.", + &opt_copy_mysqld_groups, &opt_copy_mysqld_groups, 0, GET_BOOL, NO_ARG, TRUE, + 0, 0, 0, 0, 0}, + {"error-group", OPT_ERROR_GROUP, + "Group to use for options not supported by MariaDB when using " + "--edit=[inline|last]. Should be set usually to something like " + "'mysqld-#.##' when moving from MySQL and 'unknown' when upgrading " + "MariaDB or if there are already [mariadbd] groups in the config files.", + &opt_error_group, &opt_error_group, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"edit", OPT_EDIT, + "Select what to do with invalid options. '' (default) no changes. " + "'remove' removes them. 'comment' comments them with '#'. " + "inline' adds [error_group] before unknown options. " + "'last' moves incompatible or mariadbd specific options to the end of " + "the given file under [error_group], [unsupported_group] or [mariadbd].", + &opt_edit_mode, &opt_edit_mode, &edit_mode_typelib, GET_ENUM, + REQUIRED_ARG, EDIT_MODE_NONE, 0, 0, 0, 0, 0}, + {"fix-all", OPT_FIX_ALL, + "Same as --no-myisam --from=mysql --add-skip-slave-start " + "--add-mysql-replication-compatibility " + "--add-mariadb-replication-compatibility --add-client-server-group " + "--edit=last", + 0, 0, 0, GET_NO_ARG, NO_ARG, FALSE, 0, 0, 0, 0, 0}, + {"from", OPT_CONVERT_FROM, + "Options are MySQL (default) or MariaDB. Used to specify if your are " + "upgrading from MySQL or an earlier MariaDB version. " + "When upgrading from MySQL, only the MySQL groups [mysqld] and [server] " + "are processed. If MariaDB is specified, all MariaDB entries read by " + "the current MariaDB version (" MYSQL_SERVER_VERSION ") will be processed. " + "Note that when upgrading from an earlier MariaDB version, mariadb-upgrade " + "is the preferred tool! This tool is in this case mainly useful to check " + "if there is any incompatibilities in the MariaDB configuration files.", + &opt_convert_from, &opt_convert_from, &from_mode_typelib, GET_ENUM, + REQUIRED_ARG, FROM_MYSQL, 0, 0, 0, 0, 0}, + {"help", '?', "Display this help message and exit.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"mariadbd", OPT_MARIADBD, + "Path to the mariadbd server. Used to verify if the config file changes " + "succeeded.", + &opt_mariadbd, &opt_mariadbd, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"no-myisam", OPT_NO_MYISAM_OPTIONS, + "Assume no usage of MyISAM tables. Makes the MyISAM buffers very small " + "to save memory. " + "Useful when moving to MariaDB when there are no user data in MyISAM " + "tables. This option only has an effect if the config file contains " + "settings of the key-buffer-size variable.", + &opt_no_myisam_options, &opt_no_myisam_options, 0, GET_BOOL, NO_ARG, + FALSE, 0, 0, 0, 0, 0}, + {"print", OPT_PRINT, "Print upgraded files to stdout. The 'edit' option " + "decides the output format.", + &opt_print, &opt_print, 0, GET_BOOL, NO_ARG, FALSE, 0, 0, 0, 0, 0}, + {"silent", 's', "Print less information", + &opt_silent, &opt_silent, 0, GET_BOOL, NO_ARG, FALSE, 0, 0, 0, 0, 0}, + {"update", OPT_UPDATE, "Update the configuration files in place.", + &opt_update, &opt_update, 0, GET_BOOL, NO_ARG, FALSE, 0, 0, 0, 0, 0}, + {"update-paths", OPT_UPDATE_PATHS, + "When used with --from=mysql, change file paths having /mysql or /mysqld " + "ending with '/', '.', space, or new line to /mariadbd. This is intended " + "to be used when you want to run MySQL and MariaDB on the same system.", + &opt_update_paths, &opt_update_paths, + 0, GET_BOOL, NO_ARG, FALSE, 0, 0, 0, 0, 0}, + {"unsupported-group", OPT_UNSUPPORTED_GROUP, + "Group to use for options in [mariadbd] group that is not supported by " + "MariaDB when using '--edit=[inline|last] --from=mariadb'.", + &opt_unsupported_group, &opt_unsupported_group, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"verify", OPT_VERIFY, + "Verify updates by testing the used config files through mariadbd. " + "Disabled if --print is used. " + "Note that verify only works if one uses --defaults-file=# or if one does " + "not specify any configuration files on the command line. " + "When using verify the mariadbd option has also to be used.", + &opt_mariadbd_testing, &opt_mariadbd_testing, 0, GET_BOOL, NO_ARG, FALSE, + 0, 0, 0, 0, 0}, + {"version", 'V', "Output version information and exit.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} +}; + +static void cleanup_and_exit(int exit_code) __attribute__ ((noreturn)); +static void cleanup_and_exit(int exit_code) +{ + my_end(0); + exit(exit_code); +} + + +static void print_to_width(const char *line, uint width) +{ + const char *start= line, *space= 0; + fputs("- ", stdout); + + for (start= line ; *line ; line++) + { + if ((line-start) >= width) + { + if (!space) + space= line; /* No space */ + for ( ; start < space ; start++) + putchar(*start); + fputs("\n ", stdout); + while (*start == ' ') + start++; + space= 0; + } + if (*line == ' ') + space= line; + } + printf("%s:\n", start); +} + + +static void pe(const char *example, const char *description) +{ + print_to_width(description, 77); + fprintf(stdout, "%s %s\n\n", + my_progname + dirname_length(my_progname), + example); +} + + +static void usage() __attribute__ ((noreturn)); +static void usage() +{ + print_version(); + puts("This software comes with ABSOLUTELY NO WARRANTY. This is free " + "software,\nand you are welcome to modify and redistribute it under " + "the GPL license\n"); + puts("Display or change unrecognized MariaDB options in MariaDB/MySQL\n" + "configuration files. This is useful when planning an upgrade from\n" + "MySQL to MariaDB or to check if there are some unsupported\n" + "options in the option files.\n" + "This program can print errors, print the changed files, update the\n" + "configuration files in place.\n" + "When running with the options:\n" + "--update --edit=last --error-group=mysqld-5.7\n" + "The configuration files will be changed so that they should work\n" + "with both MySQL 5.7 and MariaDB. You should provide the currently\n" + "used MySQL version if --error-group is used.\n"); + + printf("Usage: %s [--print | --update] [OPTIONS] [OPTION_FILES]\n\n", + my_progname); + puts("If OPTION_FILES is not provided, all default MariaDB configuration\n" + "files will be printed/upgraded"); + + my_print_default_files(config_file); + puts(""); + my_print_help(my_long_options); + + puts(""); + puts("If moving from MYSQL, the recommended usage is to use the following " + "3 steps:"); + puts(""); + puts("- Check if there is anything that needs changing:"); + puts("mariadb-migrate-config-file --from=mysql"); + puts(""); + puts("- Check how the new configuration files would look like:"); + puts("mariadb-migrate-config-file --from=mysql --edit=last --print"); + puts(""); + puts("- Modify all configuration files keeping backups of the originals:"); + puts("mariadb-migrate-config-file --from=mysql --edit=last --update " + "--backup --error-group=mysqld-5.7\n"); + + puts("Examples:"); + pe("", "Go through all my.cnf and included files and print not supported " + "options. The groups checked are [server], [mysqld] and [mysqld-###]. " + "Options valid for MariaDB in [mysqld-###] groups are copied to " + "the [mariadbd] group"); + pe("--from=mariadb", + "Go through all my.cnf and include files and print options not supported " + "by the current MariaDB version. All MariaDB groups read by mariadbd are " + "checked"); + pe("~/.my.cnf", "Print not supported options in ~/.my.cnf"); + pe("--defaults-file=/etc/my.cnf --verify=1 --mariadbd=#path-to-mariadbd#", + "Go through /etc/my.cnf and print all not supported options. Check also " + "the by running it through the MariaDB server"); + pe("--print", "Print the current content of all my.cnf and included files " + "(no changes)"); + pe("--print --edit=last --update-paths", + "As print, but change all paths from /mysql to /mariadbd. Useful to " + "check the effect of --update-paths"); + pe("--print --edit=last", + "Print modified version of all my.cnf and included files where supported " + "options from [mysqld-###] groups are copied to a [mariadbd] group at " + "the end of the file. Not supported options from [mysqld] and [server] " + "are moved to [mysqld-5.7] (default value of 'error_group')"); + pe("--print --edit=inline --error-group=mysqld-8.0", + "Print modified version of all my.cnf and included files where supported " + "options from [mysqld-###] groups are copied inline to [mariadbd] " + "groups. Not supported options in the [mysqld] and [server] groups are " + "moved to [mysqld-8.0]"); + pe("--print --edit=remove", + "Print modified version of all my.cnf and includedfiles where supported " + "options from [mysqld-###] groups are copied to a [mariadbd] group. " + "Not supported options from [mysqld] and [server] are removed"); + pe("--print --edit=comment", + "As '--remove', but not supported options are commented"); + pe("--edit=update --edit=inline --backup", + "Modify all my.cnf and included files. Supported options from " + "[mysqld-###] groups are copied to [mariadbd] groups. Not supported " + "options in the [mysqld] and [server] groups are moved to a " + "[mysqld-5.7] group. " + "The original of the changed config files are stored as backup files. " + "If no option files are specified the mariadbd server will be started " + "using them to verify that the new options files works with it"); + pe("--update --edit=inline --error_group=unknown --from=mariadb", + "Move all unknown mariadbd options to the group [unknown]"); + pe("--fix-all", + "Use all common options when converting from MySQL to MariaDB. " + "See definition for --fix-all for more details"); + + my_print_variables(my_long_options); + cleanup_and_exit(0); +} + + +static my_bool +get_one_option(const struct my_option *opt __attribute__((unused)), + const char *argument __attribute__((unused)), + const char *filename __attribute__((unused))) +{ + switch (opt->id) { + case 'I': + case '?': + usage(); + case 'V': + print_version(); + cleanup_and_exit(0); + case OPT_FIX_ALL: + opt_no_myisam_options= TRUE; + opt_add_skip_slave_start= TRUE; + opt_edit_mode= EDIT_MODE_LAST; + opt_convert_from= FROM_MYSQL; + opt_add_mariadb_replication_compatibility= 1; + opt_add_mysql_replication_compatibility= 1; + opt_add_client_server_group= 1; + break; + } + return 0; +} + + +static int get_options(int *argc,char ***argv) +{ + int ho_error; + + if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) + cleanup_and_exit(ho_error); + + if (opt_update && opt_edit_mode == EDIT_MODE_NONE) + { + fputs("error: --update requires the '--edit=xxx' option\n", stderr); + cleanup_and_exit(1); + } + if ((!opt_error_group || !opt_unsupported_group) && + (opt_edit_mode == EDIT_MODE_INLINE || + opt_edit_mode == EDIT_MODE_LAST)) + { + fputs("error: Selected --edit mode requires --error-group and " + "--unsupported-group\n", stderr); + cleanup_and_exit(1); + } + if (opt_print && opt_update) + { + fputs("error: --print and --update can't be specified simultaneously\n", + stderr); + cleanup_and_exit(1); + } + if (!opt_print && !opt_update && opt_edit_mode != EDIT_MODE_NONE && + !opt_silent) + { + puts("Note: edit_mode used without print/update. --print assumed"); + opt_print= 1; + } + if (opt_print && opt_edit_mode == EDIT_MODE_NONE && opt_update_paths) + { + puts("Note: --print --update-paths without edit mode set will not " + "show updated paths"); + } + if (opt_print) + { + opt_silent= 1; /* Don't print notes with --print */ + opt_mariadbd_testing= 0; + } + if (opt_update_paths && opt_convert_from != FROM_MYSQL) + opt_update_paths= 0; + + groups_to_use= (opt_convert_from == FROM_MYSQL ? + mysqld_groups : mariadbd_groups); + return 0; +} + + +int main(int argc, char **argv) +{ + int count, error= 0, args_used; + char *tmp_arguments[4]; + char **arguments, **org_argv; + const char **default_directories; + MY_INIT(argv[0]); + + org_argv= argv; + args_used= get_defaults_options(argv); + + /* Copy defaults-xxx arguments & program name */ + count= args_used; + arguments= tmp_arguments; + memcpy((char*) arguments, (char*) org_argv, count*sizeof(*org_argv)); + arguments[count]= 0; + + /* + We already process --defaults* options at the beginning in + get_defaults_options(). So skip --defaults* options and + pass remaining options to handle_options(). + */ + org_argv+=args_used-1; + argc-=args_used-1; + + /* Check out the args */ + if (get_options(&argc, &org_argv)) + cleanup_and_exit(1); + + if (argc) + { + give_error_for_missing_files= 1; + /* We cannot test a list of provided option files */ + opt_mariadbd_testing= 0; + for (; argc-- ; org_argv++) + { + count= args_used; + arguments= tmp_arguments; + if ((error= my_load_defaults(*org_argv, groups_to_use, + &count, &arguments, 0))) + goto handle_error; + error= process_defaults(*org_argv, groups_to_use, + 0, + (const char **)(argv + 1), + args_used - 1); + free_defaults(arguments); + if (error) + goto handle_error; + } + } + else + { + /* Write 'add options' only to the first found config file */ + add_new_options_once= 1; + /* Ensure that symbolic links are not expanded. Needed for mtr */ + my_defaults_use_original_paths= 1; + if ((error= my_load_defaults(config_file, groups_to_use, + &count, &arguments, &default_directories))) + goto handle_error; + /* + The defaults-xxx arguments are still intact at the beginning of argv and + can be passed to mariadbd for testing the updated configuration files. + */ + error= process_defaults(config_file, groups_to_use, + default_directories, + (const char **)(argv + 1), + args_used - 1); + free_defaults(arguments); + if (error) + goto handle_error; + } + + report_line_changes(); + + if (!opt_silent && !opt_print) + { + if (global_update_count) + { + if (opt_update) + fprintf(stdout, "%d issue/issues fixed\n", (int) global_update_count); + else + fprintf(stdout, "%d issue/issues found\n", (int) global_update_count); + } + else + printf("No issues found\n"); + } + cleanup_and_exit(error != 0 || + (!opt_update && !opt_print && global_update_count != 0) ? + 2 : 0); + +handle_error: + DBUG_ASSERT(error); + if (error == 4) /* --print-defaults */ + { + free_defaults(arguments); + cleanup_and_exit(0); + } + cleanup_and_exit(2); +} diff --git a/include/my_default.h b/include/my_default.h index 0f158bbbe43..f7428175276 100644 --- a/include/my_default.h +++ b/include/my_default.h @@ -24,6 +24,7 @@ extern MYSQL_PLUGIN_IMPORT const char *my_defaults_extra_file; extern const char *my_defaults_group_suffix; extern MYSQL_PLUGIN_IMPORT const char *my_defaults_file; extern my_bool my_defaults_mark_files; +extern my_bool my_defaults_use_original_paths; extern int get_defaults_options(char **argv); extern int my_load_defaults(const char *conf_file, const char **groups, diff --git a/include/my_sys.h b/include/my_sys.h index 4148ef0ba04..bd73ebe7056 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -792,6 +792,7 @@ extern char * my_path(char * to,const char *progname, const char *own_pathname_part); extern char * my_load_path(char * to, const char *path, const char *own_path_prefix); +extern char *find_file_in_path(char *to,const char *name); extern int wild_compare(const char *str,const char *wildstr, pbool str_is_pattern); extern my_bool array_append_string_unique(const char *str, diff --git a/mysql-test/main/mariadb-migrate-config-file.result b/mysql-test/main/mariadb-migrate-config-file.result new file mode 100644 index 00000000000..133bf26cc95 --- /dev/null +++ b/mysql-test/main/mariadb-migrate-config-file.result @@ -0,0 +1,822 @@ +# +# Testing --edit=remove and !include +# +[mysqld] +invalid=true +alter_algorithm=invalid +key_buffer_size=20M +!include MYSQLTEST_VARDIR/tmp/tmp2.cnf +[mysqld] +default_regex_flags=invalid +Updated files: +MYSQLTEST_VARDIR/tmp/tmp2.cnf +MYSQLTEST_VARDIR/tmp/tmp1.cnf +3 issue/issues fixed +[mysqld] +key_buffer_size=20M +!include MYSQLTEST_VARDIR/tmp/tmp2.cnf +# +# Testing --update --edit=last with !include +# +[mysqld] +invalid=true +alter_algorithm=invalid +key_buffer_size=20M +invalid_option +!include MYSQLTEST_VARDIR/tmp/tmp2.cnf +log-bin +# Include file start + +[mysqld] +log-bin=1 +log_error_verbosity = 3 +Note: aria_pagecache_buffer_size=20M added to [mariadbd] group +Updated files: +MYSQLTEST_VARDIR/tmp/tmp2.cnf +MYSQLTEST_VARDIR/tmp/tmp1.cnf +8 issue/issues fixed +# Changed files +[mariadbd] +key_buffer_size=20M +#key_buffer_size=64K # Recommended value if no MyISAM tables +aria_pagecache_buffer_size=20M + +[mysqld-5.7] +invalid=true +alter_algorithm=invalid +key_buffer_size=20M +invalid_option + +[mysqld] +!include MYSQLTEST_VARDIR/tmp/tmp2.cnf +log-bin +# Include file start + +[mysqld] +log-bin=1 + +[mysqld-5.7] +log_error_verbosity = 3 +# Verify no more changes +Note: aria_pagecache_buffer_size=20M added to [mariadbd] group +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +No issues found +# +# Testing --edit=comment +# +[mysqld] +port=38 +invalid=true +alter_algorithm=invalid +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +2 issue/issues fixed +[mysqld] +port=38 +#invalid=true +#alter_algorithm=invalid +# +# Testing --edit=inline --from=mariadb +# +[mysqld] +invalid=true +invalid_option +skip-grant-tables +skip-name-resolve=0 +skip-networking +skip-show-database +skip-slave-start + +[mariadbd] +alter_algorithm=invalid + +[other] +a=b + +[mariadbd] +port=30 +alter_algorithm=impossible + +[other] +c=d + +[mariadbd] +port=32 +alter_algorithm=impossible2 +port=33 + +[mysqld] +key_buffer_size=20M +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +5 issue/issues fixed +# Changed file +[mysqld-5.7] +invalid=true +invalid_option + +[mysqld] +skip-grant-tables +skip-name-resolve=0 +skip-networking +skip-show-database +skip-slave-start + +[mariadbd] + +[options-not-recognized-by-mariadbd] +alter_algorithm=invalid + +[other] +a=b + +[mariadbd] +port=30 + +[options-not-recognized-by-mariadbd] +alter_algorithm=impossible + +[other] +c=d + +[mariadbd] +port=32 + +[options-not-recognized-by-mariadbd] +alter_algorithm=impossible2 + +[mariadbd] +port=33 + +[mysqld] +key_buffer_size=20M +# +# Testing --edit=last --from=mariadb +# +[mysqld] +invalid=true +invalid_option + +[mariadbd] +alter_algorithm=invalid + +[other] +a=b + +[mariadbd] +port=30 +alter_algorithm=impossible + +[other] +c=d + +[mariadbd] +port=32 +alter_algorithm=impossible2 +port=33 + +[mysqld] +key_buffer_size=20M +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +5 issue/issues fixed +# Changed file + +[mariadbd] + +[other] +a=b + +[mariadbd] +port=30 + +[other] +c=d + +[mariadbd] +port=32 +port=33 + +[mysqld] +key_buffer_size=20M + +[mysqld-5.7] +invalid=true +invalid_option + +[options-not-recognized-by-mariadbd] +alter_algorithm=invalid +alter_algorithm=impossible +alter_algorithm=impossible2 +# +# Testing --edit=last --from=mysql +# This will fail and changes will be reverted +# +[mysqld] +invalid=true +invalid_option + +[mariadbd] +alter_algorithm=invalid + +[other] +a=b + +[mariadbd] +port=30 +alter_algorithm=impossible + +[other] +c=d + +[mariadbd] +port=32 +alter_algorithm=impossible2 +port=33 + +[mysqld] +key_buffer_size=20M + +# Original unchanged file +[mysqld] +invalid=true +invalid_option + +[mariadbd] +alter_algorithm=invalid + +[other] +a=b + +[mariadbd] +port=30 +alter_algorithm=impossible + +[other] +c=d + +[mariadbd] +port=32 +alter_algorithm=impossible2 +port=33 + +[mysqld] +key_buffer_size=20M +# +# Testing mariadbd section additions with --from-mariadb +# +[mariadbd] +invalid1=true +join_buffer_size=5K +invalid2=true + +[mysqld] +key_buffer_size=20M +alter_algorithm=invalid +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +3 issue/issues fixed +[mariadbd] +join_buffer_size=5K + +[mysqld] +key_buffer_size=20M + +[unknown] +alter_algorithm=invalid + +[options-not-recognized-by-mariadbd] +invalid1=true +invalid2=true +# +# Testing key_buffer_size in mysqld section with --from=mysql +# +[mysqld] +key_buffer_size=20M +Note: aria_pagecache_buffer_size=20M added to [mariadbd] group +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +4 issue/issues fixed +[mariadbd] +key_buffer_size=20M +#key_buffer_size=64K # Recommended value if no MyISAM tables +aria_pagecache_buffer_size=20M + +[mysqld-5.7] +key_buffer_size=20M +# +# Testing key_buffer_size in mysqld section with --from=mysql --no-myisam +# +[mysqld] +key_buffer_size=20M +Note: 'aria_pagecache_buffer_size=20M' added to [mariadbd] group +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +3 issue/issues fixed +[mariadbd] +key_buffer_size=64K # Recommended value if no MyISAM tables +aria_pagecache_buffer_size=20M + +[mysqld-5.7] +key_buffer_size=20M +# +# Testing key_buffer_size in mariadbd section +# +[mariadbd] +key_buffer_size=20M +No issues found +[mariadbd] +key_buffer_size=20M +# +# Testing --no-myisam --edit=last +# +[mysqld] +key_buffer_size=20M +Note: 'aria_pagecache_buffer_size=20M' added to [mariadbd] group +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +3 issue/issues fixed +[mariadbd] +key_buffer_size=64K # Recommended value if no MyISAM tables +aria_pagecache_buffer_size=20M + +[mysqld-5.7] +key_buffer_size=20M +# +# Testing --add-skip-start-slave +# +[mysqld] +default_week_format=1 +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +1 issue/issues fixed +[mysqld] +default_week_format=1 + +[mariadbd] +skip_slave_start +# +# Testing --add-skip-slave-start with skip_start_slave already present +# +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +No issues found +[mariadbd] +skip_slave_start +# +# Testing audit_log part 1 +# +[mysqld] +plugin_load=audit_log +audit_log-a=5 +audit_log-disabled +audit_log=on +In MYSQLTEST_VARDIR/tmp/tmp1.cnf at line 2: Please replace audit_log with the server_audit plugin +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +5 issue/issues fixed +[mariadbd] +skip_slave_start + +[mysqld-5.7] +plugin_load=audit_log +audit_log-a=5 +audit_log-disabled +audit_log=on +# +# Testing audit_log part 2 +# +[mysqld] +audit_log=ON +audit_log_file=name +Warning: Please replace audit_log with the server_audit plugin +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +3 issue/issues fixed +[mariadbd] +skip_slave_start + +[mysqld-5.7] +audit_log=ON +audit_log_file=name +# +# Testing audit_log part 3 +# +[mysqld] +audit_log-disabled +Warning: Please replace audit_log with the server_audit plugin +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +2 issue/issues fixed +[mariadbd] +skip_slave_start + +[mysqld-5.7] +audit_log-disabled +# +# Testing comments +# +[mysqld] +character_set_server = utf8mb4 # It's a new world +collation_server = utf8mb4_0900_ai_ci +log_error_verbosity = 3 +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +2 issue/issues fixed +[mysqld] +character_set_server = utf8mb4 # It's a new world +collation_server = utf8mb4_0900_ai_ci + +[mariadbd] +skip_slave_start + +[mysqld-5.7] +log_error_verbosity = 3 +# +# Testing --fix-all +# +[mysqld] +innodb_data_file_path=/var/mysql/test2 +key_buffer_size=20M +Note: 'aria_pagecache_buffer_size=20M' added to [mariadbd] group +Note: Added MySQL default character sets and collation to [mariadbd] to be able to replicate to MySQL +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +17 issue/issues fixed +[mysqld] +innodb_data_file_path=/var/mysql/test2 + +[mariadbd] +key_buffer_size=64K # Recommended value if no MyISAM tables +aria_pagecache_buffer_size=20M +skip_slave_start +# The following options enable MariaDB to replicate to MySQL +encrypt_binlog=0 +log_bin_compress=0 +# Not required, but recommended for cross_replication +binlog_format=row +# Character set to be able to replicate new tables to MySQL 8.0 +character_set_server=utf8mb4 +collation_server=utf8mb4_0900_ai_ci + +[mysqld-5.7] +key_buffer_size=20M +# The following options enable MySQL to replicate to MariaDB +loose-binlog_row_value_options="" +loose-binlog_transaction_compression=0 +# Not required, but recommended for cross_replication +binlog_format=row +# +# Testing --fix-all --update-paths +# +[mysqld] +innodb_data_file_path=/var/mysql/test2 +key_buffer_size=20M +Note: 'aria_pagecache_buffer_size=20M' added to [mariadbd] group +Note: Added MySQL default character sets and collation to [mariadbd] to be able to replicate to MySQL +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +19 issue/issues fixed +[mariadbd] +innodb_data_file_path=/var/mariadb/test2 +key_buffer_size=64K # Recommended value if no MyISAM tables +aria_pagecache_buffer_size=20M +skip_slave_start +# The following options enable MariaDB to replicate to MySQL +encrypt_binlog=0 +log_bin_compress=0 +# Not required, but recommended for cross_replication +binlog_format=row +# Character set to be able to replicate new tables to MySQL 8.0 +character_set_server=utf8mb4 +collation_server=utf8mb4_0900_ai_ci + +[mysqld-5.7] +innodb_data_file_path=/var/mysql/test2 +key_buffer_size=20M +# The following options enable MySQL to replicate to MariaDB +loose-binlog_row_value_options="" +loose-binlog_transaction_compression=0 +# Not required, but recommended for cross_replication +binlog_format=row +# +# Testing path copying, without error-group and silent +# +[mysqld] +innodb_data_file_path=/var/mysql/test +port=38 +dummy=/var/mysql/test +log-error=/var/mysql/test2 + +[mysqld-8.0] +port=39 +dummy2=2 +innodb_data_file_path=/var/mysql/test2 +In MYSQLTEST_VARDIR/tmp/tmp1.cnf at line 2: 'innodb_data_file_path=/var/mysql/test' would be replaced with 'innodb_data_file_path=/var/mariadb/test' +In MYSQLTEST_VARDIR/tmp/tmp1.cnf at line 4: Invalid option dummy +In MYSQLTEST_VARDIR/tmp/tmp1.cnf at line 5: 'log-error=/var/mysql/test2' would be replaced with 'log-error=/var/mariadb/test2' +In MYSQLTEST_VARDIR/tmp/tmp1.cnf at line 10: 'innodb_data_file_path=/var/mysql/test2' would be replaced with 'innodb_data_file_path=/var/mariadb/test2' +2 line/lines would be copied to [mariadbd] group +5 line/lines would be copied to [mysqld-5.7] group +11 issue/issues found +MYSQLTEST_VARDIR/tmp/tmp1.cnf +# Changed file +[mysqld] +port=38 + +[mysqld-8.0] +port=39 +dummy2=2 +innodb_data_file_path=/var/mysql/test2 + +[mariadbd] +innodb_data_file_path=/var/mariadb/test +log-error=/var/mariadb/test2 +port=39 +innodb_data_file_path=/var/mariadb/test2 + +[mysqld-5.7] +innodb_data_file_path=/var/mysql/test +dummy=/var/mysql/test +log-error=/var/mysql/test2 +# +# Testing innodb_stats_sample_pages +# +[mysqld] +innodb_stats_sample_pages=1 +### File [name hidden] +[mariadbd] +innodb_stats_transient_sample_pages=1 + +[mysqld-5.7] +innodb_stats_sample_pages=1 + +In MYSQLTEST_VARDIR/tmp/tmp1.cnf at line 2: 'innodb_stats_sample_pages=1' would be replaced with 'innodb_stats_transient_sample_pages=1' +1 issue/issues found +# +# Testing innodb_log_files_in_group +# +[mysqld] +innodb_log_files_in_group=4 +innodb_log_file_size=2G +# Checking file +In MYSQLTEST_VARDIR/tmp/tmp1.cnf at line 2: Invalid option innodb_log_files_in_group +1 issue/issues found +# Updating file +Note: 'innodb_log_file_size=8G' added to [mariadbd] group based on innodb_log_file_size * innodb_log_files_in_group +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +2 issue/issues fixed +# Changed file +[mysqld] +innodb_log_file_size=2G + +[mariadbd] +innodb_log_file_size=8G + +[mysqld-5.7] +innodb_log_files_in_group=4 +# Checking if file is ok now +No issues found +# +# Test not existing character set +# +[mysqld] +character_set_server=xxx +# +# Testing --add-XXX-replication-compatibility +# +[mysqld] +port=38 +character-set-server=utf8mb4 +# MySQL -> MariaDB compatibility +### File MYSQLTEST_VARDIR/tmp/tmp1.cnf: +[mysqld] +port=38 +character-set-server=utf8mb4 + +[mysqld-5.7] +# The following options enable MySQL to replicate to MariaDB +loose-binlog_row_value_options="" +loose-binlog_transaction_compression=0 +# Not required, but recommended for cross_replication +binlog_format=row + +# MariaDB -> MySQL compatibility +### File MYSQLTEST_VARDIR/tmp/tmp1.cnf: +[mysqld] +port=38 +character-set-server=utf8mb4 + +[mariadbd] +# The following options enable MariaDB to replicate to MySQL +encrypt_binlog=0 +log_bin_compress=0 +# Not required, but recommended for cross_replication +binlog_format=row + +# +# Testing --add-client-server-group +# +[mysqld] +port=38 +port=39 +socket="/tmp/mysql.sock" +character-set-server=utf8mb4 + +[server] +port=50 + +[mysql-8.0] +port=99 +socket="/tmp/mysql8.sock" +# --add-client-server-group +### File MYSQLTEST_VARDIR/tmp/tmp1.cnf: +[mysqld] +port=38 +port=39 +character-set-server=utf8mb4 + +[server] +port=50 + +[mysql-8.0] +port=99 +socket="/tmp/mysql8.sock" + +[mariadbd] +socket="/tmp/mariadb.sock" + +[mysqld-5.7] +socket="/tmp/mysql.sock" + +[client-server] +port=50 +socket="/tmp/mariadb.sock" + +# Test 2 with update and without --update-paths +[mysqld] +port=38 +port=39 +socket="/tmp/mysql.sock" +innodb_log_file_size=2G + +[mysql-8.0] +port=99 +socket="/tmp/mysql8.sock" +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +2 issue/issues fixed +# Changed file +[mysqld] +port=38 +port=39 +socket="/tmp/mysql.sock" +innodb_log_file_size=2G + +[mysql-8.0] +port=99 +socket="/tmp/mysql8.sock" + +[client-server] +port=39 +socket=/tmp/mysql.sock +# +# Testing copy-mysqld-groups +# +[mysqld-8.0] +socket="/tmp/mysql.sock" +# Testing with --copy-mysqld-groups=0 +No issues found +# Testing with --copy-mysqld-groups=1 +1 line/lines would be copied to [mariadbd] group +1 issue/issues found +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +1 issue/issues fixed +[mysqld-8.0] +socket="/tmp/mysql.sock" + +[mariadbd] +socket="/tmp/mysql.sock" +# +# Testing path changing and different generated sections +# +[mysqld] +log-error = /var/log/mysql/mysqld.log +dummy=1; +default-storage-engine=innodb +socket=/var/lib/mysql/mysql.sock +datadir=/var/lib/mysql + +[server] +dummy=2; +socket=dummy; + +[mysqld-8.0] +default-storage-engine=misam +port=36 +qqq= hello + +[mysqld] +innodb_data_file_path=/var/mysql/test +port=38 +dummy=/var/mysql/test +log-error=/var/mysql/test2 + +[mysqld-8.0] +port=39 +dummy2=3 +innodb_data_file_path=/var/mysql/test2 +# Output from --print --edit=last --update-paths +### File [name hidden] +[mysqld] +default-storage-engine=innodb + +[server] +socket=dummy; + +[mysqld-8.0] +default-storage-engine=misam +port=36 +qqq= hello + +[mysqld] +port=38 + +[mysqld-8.0] +port=39 +dummy2=3 +innodb_data_file_path=/var/mysql/test2 + +[mariadbd] +log-error = /var/log/mariadb/mysqld.log +socket=/var/lib/mariadb/mysql.sock +datadir=/var/lib/mariadb +default-storage-engine=misam +port=36 +innodb_data_file_path=/var/mariadb/test +log-error=/var/mariadb/test2 +port=39 +innodb_data_file_path=/var/mariadb/test2 + +[mysqld-5.7] +log-error = /var/log/mysql/mysqld.log +dummy=1; +socket=/var/lib/mysql/mysql.sock +datadir=/var/lib/mysql +dummy=2; +innodb_data_file_path=/var/mysql/test +dummy=/var/mysql/test +log-error=/var/mysql/test2 + +# +# Test that second update of file with 'last' will no do anything +# +Updated files: +MYSQLTEST_VARDIR/tmp/tmp1.cnf +17 issue/issues fixed +No issues found +No issues found +"Next command should not change anything" +No issues found +[mysqld] +default-storage-engine=innodb + +[server] +socket=dummy; + +[mysqld-8.0] +default-storage-engine=misam +port=36 +qqq= hello + +[mysqld] +port=38 + +[mysqld-8.0] +port=39 +dummy2=3 +innodb_data_file_path=/var/mysql/test2 + +[mariadbd] +log-error = /var/log/mariadb/mysqld.log +socket=/var/lib/mariadb/mysql.sock +datadir=/var/lib/mariadb +default-storage-engine=misam +port=36 +innodb_data_file_path=/var/mariadb/test +log-error=/var/mariadb/test2 +port=39 +innodb_data_file_path=/var/mariadb/test2 + +[mysqld-5.7] +log-error = /var/log/mysql/mysqld.log +dummy=1; +socket=/var/lib/mysql/mysql.sock +datadir=/var/lib/mysql +dummy=2; +innodb_data_file_path=/var/mysql/test +dummy=/var/mysql/test +log-error=/var/mysql/test2 diff --git a/mysql-test/main/mariadb-migrate-config-file.test b/mysql-test/main/mariadb-migrate-config-file.test new file mode 100644 index 00000000000..ac3d35863ca --- /dev/null +++ b/mysql-test/main/mariadb-migrate-config-file.test @@ -0,0 +1,603 @@ +if (!$MARIADB_MIGRATE_CONFIG_FILE) { + --skip MARIADB_MIGRATE_CONFIG_FILE missing +} + +--echo # +--echo # Testing --edit=remove and !include +--echo # + +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +invalid=true +alter_algorithm=invalid +key_buffer_size=20M +EOF + +--exec echo "!include $MYSQLTEST_VARDIR/tmp/tmp2.cnf" >> $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--write_file $MYSQLTEST_VARDIR/tmp/tmp2.cnf +[mysqld] +default_regex_flags=invalid +EOF + +--cat_file $MYSQLTEST_VARDIR/tmp/tmp2.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --edit=remove +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--cat_file $MYSQLTEST_VARDIR/tmp/tmp2.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp2.cnf + +--echo # +--echo # Testing --update --edit=last with !include +--echo # + +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +invalid=true +alter_algorithm=invalid +key_buffer_size=20M +invalid_option +EOF +--exec echo "!include $MYSQLTEST_VARDIR/tmp/tmp2.cnf" >> $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--exec echo "log-bin" >> $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--write_file $MYSQLTEST_VARDIR/tmp/tmp2.cnf +# Include file start + +[mysqld] +log-bin=1 +log_error_verbosity = 3 +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp2.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --edit=last + +--echo # Changed files +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--cat_file $MYSQLTEST_VARDIR/tmp/tmp2.cnf + +--echo # Verify no more changes +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --edit=last + +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp2.cnf + +--echo # +--echo # Testing --edit=comment +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +port=38 +invalid=true +alter_algorithm=invalid +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --edit=comment +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing --edit=inline --from=mariadb +--echo # + +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +invalid=true +invalid_option +skip-grant-tables +skip-name-resolve=0 +skip-networking +skip-show-database +skip-slave-start + +[mariadbd] +alter_algorithm=invalid + +[other] +a=b + +[mariadbd] +port=30 +alter_algorithm=impossible + +[other] +c=d + +[mariadbd] +port=32 +alter_algorithm=impossible2 +port=33 + +[mysqld] +key_buffer_size=20M +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --error-group=mysqld-5.7 --edit=inline --from=mariadb +--echo # Changed file +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing --edit=last --from=mariadb +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +invalid=true +invalid_option + +[mariadbd] +alter_algorithm=invalid + +[other] +a=b + +[mariadbd] +port=30 +alter_algorithm=impossible + +[other] +c=d + +[mariadbd] +port=32 +alter_algorithm=impossible2 +port=33 + +[mysqld] +key_buffer_size=20M +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --error-group=mysqld-5.7 --edit=last --from=mariadb +--echo # Changed file +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing --edit=last --from=mysql +--echo # This will fail and changes will be reverted +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +invalid=true +invalid_option + +[mariadbd] +alter_algorithm=invalid + +[other] +a=b + +[mariadbd] +port=30 +alter_algorithm=impossible + +[other] +c=d + +[mariadbd] +port=32 +alter_algorithm=impossible2 +port=33 + +[mysqld] +key_buffer_size=20M +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--disable_result_log +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--error 2 +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --error-group=mysqld-5.7 --edit=last --from=mysql --verify +--enable_result_log +--echo +--echo # Original unchanged file +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing mariadbd section additions with --from-mariadb +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mariadbd] +invalid1=true +join_buffer_size=5K +invalid2=true + +[mysqld] +key_buffer_size=20M +alter_algorithm=invalid +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --error-group=unknown --edit=last --from=mariadb +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing key_buffer_size in mysqld section with --from=mysql +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +key_buffer_size=20M +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --error-group=mysqld-5.7 --edit=last --from=mysql +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing key_buffer_size in mysqld section with --from=mysql --no-myisam +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +key_buffer_size=20M +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --error-group=mysqld-5.7 --edit=last --from=mysql --no-myisam +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing key_buffer_size in mariadbd section +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mariadbd] +key_buffer_size=20M +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --error-group=mysqld-5.7 --edit=last +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing --no-myisam --edit=last +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +key_buffer_size=20M +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --error-group=mysqld-5.7 --edit=last --no-myisam +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing --add-skip-start-slave +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +default_week_format=1 +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --error-group=mysqld-5.7 --edit=last --add-skip-slave-start +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing --add-skip-slave-start with skip_start_slave already present +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mariadbd] +skip_slave_start +EOF +#--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --error-group=mysqld-5.7 --edit=last --add-skip-slave-start +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing audit_log part 1 +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +plugin_load=audit_log +audit_log-a=5 +audit_log-disabled +audit_log=on +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --error-group=mysqld-5.7 --edit=last --add-skip-slave-start +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing audit_log part 2 +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +audit_log=ON +audit_log_file=name +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --error-group=mysqld-5.7 --edit=last --add-skip-slave-start +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing audit_log part 3 +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +audit_log-disabled +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --error-group=mysqld-5.7 --edit=last --add-skip-slave-start +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing comments +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +character_set_server = utf8mb4 # It's a new world +collation_server = utf8mb4_0900_ai_ci +log_error_verbosity = 3 +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --error-group=mysqld-5.7 --edit=last --add-skip-slave-start +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing --fix-all +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +innodb_data_file_path=/var/mysql/test2 +key_buffer_size=20M +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --error-group=mysqld-5.7 --edit=last --fix-all +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing --fix-all --update-paths +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +innodb_data_file_path=/var/mysql/test2 +key_buffer_size=20M +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --update --verify --error-group=mysqld-5.7 --edit=last --fix-all --update-paths +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing path copying, without error-group and silent +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +innodb_data_file_path=/var/mysql/test +port=38 +dummy=/var/mysql/test +log-error=/var/mysql/test2 + +[mysqld-8.0] +port=39 +dummy2=2 +innodb_data_file_path=/var/mysql/test2 +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--error 2 +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --update-paths --add-mariadb-replication-compatibility +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd="not_found_here" --update --verify --edit=last --silent --update-paths --verify=0 +--echo # Changed file +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing innodb_stats_sample_pages +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +innodb_stats_sample_pages=1 +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_regex /### File[^\n]*/### File [name hidden]/ +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --print --edit=last +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--error 2 +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing innodb_log_files_in_group +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +innodb_log_files_in_group=4 +innodb_log_file_size=2G +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--echo # Checking file +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--error 2 +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf +--echo # Updating file +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --update --verify --edit=last --mariadbd=$MYSQLD --verify +--echo # Changed file +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--echo # Checking if file is ok now +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --verify=0 +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Test not existing character set +--echo # + +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +character_set_server=xxx +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--error 2 +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --update --verify --edit=last --mariadbd=$MYSQLD --verify +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing --add-XXX-replication-compatibility +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +port=38 +character-set-server=utf8mb4 +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--echo # MySQL -> MariaDB compatibility +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --print --edit=last --verify=0 --add-mariadb-replication-compatibility + +--echo # MariaDB -> MySQL compatibility +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --print --edit=last --verify=0 --add-mysql-replication-compatibility +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing --add-client-server-group +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +port=38 +port=39 +socket="/tmp/mysql.sock" +character-set-server=utf8mb4 + +[server] +port=50 + +[mysql-8.0] +port=99 +socket="/tmp/mysql8.sock" +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--echo # --add-client-server-group +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --print --edit=last --verify=0 --add-client-server-group --update-paths +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # Test 2 with update and without --update-paths +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +port=38 +port=39 +socket="/tmp/mysql.sock" +innodb_log_file_size=2G + +[mysql-8.0] +port=99 +socket="/tmp/mysql8.sock" +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --update --edit=last --add-client-server-group --mariadbd=$MYSQLD --verify +--echo # Changed file +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing copy-mysqld-groups +--echo # + +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld-8.0] +socket="/tmp/mysql.sock" +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--echo # Testing with --copy-mysqld-groups=0 +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --update --edit=last --copy-mysqld-groups=0 --mariadbd=$MYSQLD --verify +--echo # Testing with --copy-mysqld-groups=1 +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--error 2 +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --copy-mysqld-groups=1 +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --update --edit=last --copy-mysqld-groups=1 --mariadbd=$MYSQLD --verify +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf + +--echo # +--echo # Testing path changing and different generated sections +--echo # +--write_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +[mysqld] +log-error = /var/log/mysql/mysqld.log +dummy=1; +default-storage-engine=innodb +socket=/var/lib/mysql/mysql.sock +datadir=/var/lib/mysql + +[server] +dummy=2; +socket=dummy; + +[mysqld-8.0] +default-storage-engine=misam +port=36 +qqq= hello + +[mysqld] +innodb_data_file_path=/var/mysql/test +port=38 +dummy=/var/mysql/test +log-error=/var/mysql/test2 + +[mysqld-8.0] +port=39 +dummy2=3 +innodb_data_file_path=/var/mysql/test2 +EOF +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--echo # Output from --print --edit=last --update-paths +--replace_regex /### File[^\n]*/### File [name hidden]/ +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd="not_found_here" --print --edit=last --update-paths + +--echo # +--echo # Test that second update of file with 'last' will no do anything +--echo # +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --update --edit=last --update-paths --verify=0 +# Check file +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --mariadbd=$MYSQLD --copy-mysqld-groups=0 +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --update-paths --mariadbd=$MYSQLD --copy-mysqld-groups=0 +--echo "Next command should not change anything" +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--exec $MARIADB_MIGRATE_CONFIG_FILE --defaults-file=$MYSQLTEST_VARDIR/tmp/tmp1.cnf --update --edit=last --update-paths --backup --verify=0 +--cat_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf +--remove_file $MYSQLTEST_VARDIR/tmp/tmp1.cnf diff --git a/mysql-test/main/mysqld--help-aria.result b/mysql-test/main/mysqld--help-aria.result index f8be76c7a6a..563989cfe44 100644 --- a/mysql-test/main/mysqld--help-aria.result +++ b/mysql-test/main/mysqld--help-aria.result @@ -4,9 +4,7 @@ flush tables; # Check that we don't write any data to wrong or not existing datadir # [Warning] --table-cache is deprecated and will be removed in a future release. Please use --table-open-cache instead. -[Warning] Could not open mysql.plugin table: "Table 'mysql.plugin' doesn't exist". Some options may be missing from the help text # # Check with existing directory # [Warning] --table-cache is deprecated and will be removed in a future release. Please use --table-open-cache instead. -[Warning] Could not open mysql.plugin table: "Table 'mysql.plugin' doesn't exist". Some options may be missing from the help text diff --git a/mysql-test/main/mysqld--help.result b/mysql-test/main/mysqld--help.result index 44a92c2fc4c..2c65abf13c3 100644 --- a/mysql-test/main/mysqld--help.result +++ b/mysql-test/main/mysqld--help.result @@ -1343,7 +1343,8 @@ The following specify which files/extra groups are read (specified before remain the transaction) --show-slave-auth-info Show user and password in SHOW SLAVE HOSTS on this master - --silent-startup Don't print [Note] to the error log during startup + --silent-startup Don't print [Note] or failed plugin_loads to the error + log during startup --skip-grant-tables Start without grant tables. This gives all users FULL ACCESS to all tables --skip-host-cache Don't cache host names diff --git a/mysql-test/mariadb-test-run.pl b/mysql-test/mariadb-test-run.pl index 649b4013b4b..e09ae065080 100755 --- a/mysql-test/mariadb-test-run.pl +++ b/mysql-test/mariadb-test-run.pl @@ -1544,7 +1544,7 @@ sub command_line_setup { $opt_vardir= $default_vardir; } - # We make the path absolute, as the server will do a chdir() before usage + # We make the path asbolute, as the server will do a chdir() before usage unless ( $opt_vardir =~ m,^/, or (IS_WINDOWS and $opt_vardir =~ m,^[a-z]:[/\\],i) ) { @@ -2284,6 +2284,14 @@ sub environment_setup { "$path_client_bindir/my_print_defaults"); $ENV{'MYSQL_MY_PRINT_DEFAULTS'}= native_path($exe_my_print_defaults); + # ---------------------------------------------------- + # mariadb-migrate-config-file + # ---------------------------------------------------- + my $exe_mariadb_migrate_config_file= + mtr_exe_maybe_exists("$bindir/extra$multiconfig/mariadb-migrate-config-file", + "$path_client_bindir/mariadb-migrate-config-file"); + $ENV{'MARIADB_MIGRATE_CONFIG_FILE'}= native_path($exe_mariadb_migrate_config_file) if $exe_mariadb_migrate_config_file; + # ---------------------------------------------------- # myisam tools # ---------------------------------------------------- diff --git a/mysys/mf_path.c b/mysys/mf_path.c index cba80599daa..b14786a74f6 100644 --- a/mysys/mf_path.c +++ b/mysys/mf_path.c @@ -16,8 +16,6 @@ #include "mysys_priv.h" #include -static char *find_file_in_path(char *to,const char *name); - /* Finds where program can find it's files. pre_pathname is found by first locking at progname (argv[0]). if progname contains path the path is returned. @@ -82,7 +80,7 @@ char * my_path(char * to, const char *progname, #define PATH_SEP ':' #endif -static char *find_file_in_path(char *to, const char *name) +char *find_file_in_path(char *to, const char *name) { char *path,*pos,dir[2]; const char *ext=""; diff --git a/mysys/my_default.c b/mysys/my_default.c index 5e7b1bb3fca..9ec19dd1f4f 100644 --- a/mysys/my_default.c +++ b/mysys/my_default.c @@ -52,6 +52,8 @@ */ static char *file_marker= (char*)"----file-marker----"; my_bool my_defaults_mark_files= FALSE; +my_bool my_defaults_use_original_paths= FALSE; + my_bool is_file_marker(const char* arg) { return arg == file_marker; @@ -208,7 +210,7 @@ static int my_search_option_files(const char *conf_file, goto err; } } - else if (dirname_length(conf_file)) + else if (dirname_length(conf_file) || !default_directories) { if ((error= search_default_file(ctx, NullS, conf_file)) < 0) goto err; @@ -325,13 +327,15 @@ int get_defaults_options(char **argv) if (! my_defaults_group_suffix) my_defaults_group_suffix= getenv("MYSQL_GROUP_SUFFIX"); - if (my_defaults_extra_file && my_defaults_extra_file != extra_file_buffer) + if (my_defaults_extra_file && my_defaults_extra_file != extra_file_buffer && + ! my_defaults_use_original_paths) { my_realpath(extra_file_buffer, my_defaults_extra_file, MYF(0)); my_defaults_extra_file= extra_file_buffer; } - if (my_defaults_file && my_defaults_file != file_buffer) + if (my_defaults_file && my_defaults_file != file_buffer && + ! my_defaults_use_original_paths) { my_realpath(file_buffer, my_defaults_file, MYF(0)); my_defaults_file= file_buffer; @@ -401,6 +405,8 @@ int load_defaults(const char *conf_file, const char **groups, - 1 is returned if the given conf_file didn't exist. In this case, the value pointed to by default_directories is undefined. + - 4 is returned --print-defaults was used. The caller should just do exit(0) + in this ase */ diff --git a/mysys/my_delete.c b/mysys/my_delete.c index 6854033f84b..bc784fdee44 100644 --- a/mysys/my_delete.c +++ b/mysys/my_delete.c @@ -202,6 +202,7 @@ error: /* Remove directory recursively. + Symlinks are deleted, not followed */ int my_rmtree(const char *dir, myf MyFlags) { @@ -210,7 +211,9 @@ int my_rmtree(const char *dir, myf MyFlags) int err = 0; size_t i; - MY_DIR *dir_info = my_dir(dir, MYF(MY_DONT_SORT | MY_WANT_STAT)); + MY_DIR *dir_info = my_dir(dir, + MYF(MY_DONT_SORT | MY_WANT_STAT | + (MyFlags & (MY_NOSYMLINKS | MY_WME)))); if (!dir_info) return 1; @@ -225,7 +228,7 @@ int my_rmtree(const char *dir, myf MyFlags) if (!MY_S_ISDIR(file->mystat->st_mode)) { - err = my_delete(path, MyFlags); + err = my_delete(path, (MyFlags & ~MY_NOSYMLINKS)); #ifdef _WIN32 /* On Windows, check and possible reset readonly attribute. diff --git a/mysys/my_lib.c b/mysys/my_lib.c index 7365b9fa1ba..93ba680f582 100644 --- a/mysys/my_lib.c +++ b/mysys/my_lib.c @@ -350,11 +350,19 @@ MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags) if ((m_used= (stat_area == NULL))) if (!(stat_area= (MY_STAT *) my_malloc(key_memory_MY_STAT, sizeof(MY_STAT), my_flags))) - goto error; + goto err; #ifndef _WIN32 - if (!stat((char *) path, (struct stat *) stat_area)) { - DBUG_RETURN(stat_area); + int error; + if (my_flags & MY_NOSYMLINKS) + error= lstat((char *) path, (struct stat *) stat_area); + else + error= stat((char *) path, (struct stat *) stat_area); + + if (!error) + { + DBUG_RETURN(stat_area); + } } #else if (!my_win_stat(path, stat_area)) @@ -365,7 +373,7 @@ MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags) if (m_used) /* Free if new area */ my_free(stat_area); -error: +err: if (my_flags & (MY_FAE+MY_WME)) { my_error(EE_STAT, MYF(ME_BELL), path, my_errno); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e41070200c0..734f912ea0f 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -338,7 +338,7 @@ PSI_statement_info stmt_info_rpl; static bool lower_case_table_names_used= 0; static bool volatile select_thread_in_use, signal_thread_in_use; static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0; -static my_bool opt_short_log_format= 0, opt_silent_startup= 0; +static my_bool opt_short_log_format= 0; ulong max_used_connections; time_t max_used_connections_time; @@ -375,6 +375,7 @@ uint opt_bin_log_compress_min_len; my_bool opt_log, debug_assert_if_crashed_table= 0, opt_help= 0; my_bool debug_assert_on_not_freed_memory= 0; my_bool disable_log_notes, opt_support_flashback= 0; +my_bool opt_silent_startup= 0; static my_bool opt_abort; ulonglong log_output_options; my_bool opt_userstat_running; @@ -6924,8 +6925,10 @@ struct my_option my_long_options[]= "Show user and password in SHOW SLAVE HOSTS on this master", &opt_show_slave_auth_info, &opt_show_slave_auth_info, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"silent-startup", OPT_SILENT, "Don't print [Note] to the error log during startup", - &opt_silent_startup, &opt_silent_startup, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"silent-startup", OPT_SILENT, "Don't print [Note] or failed plugin_loads " + "to the error log during startup", + &opt_silent_startup, &opt_silent_startup, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"skip-host-cache", OPT_SKIP_HOST_CACHE, "Don't cache host names", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"skip-slave-start", 0, diff --git a/sql/mysqld.h b/sql/mysqld.h index 554234d3952..983842ec82d 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -122,6 +122,7 @@ extern MYSQL_PLUGIN_IMPORT bool volatile abort_loop; extern my_bool opt_safe_user_create; extern my_bool opt_local_infile, opt_myisam_use_mmap; extern my_bool opt_slave_compressed_protocol, use_temp_pool; +extern my_bool opt_silent_startup; extern ulong slave_exec_mode_options, slave_ddl_exec_mode_options; extern ulong slave_retried_transactions; extern ulong transactions_multi_engine; diff --git a/sql/sql_class.h b/sql/sql_class.h index dab2f82840e..87f179e915e 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1215,7 +1215,7 @@ public: done before any other THD constructors and decrement - after any other THD destructors. - Destructor unblocks close_conneciton() if there are no more THD's left. + Destructor unblocks close_connection() if there are no more THD's left. */ struct THD_count { diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index a3e83ac6297..6f8c4d0e1f7 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -545,7 +545,9 @@ static my_bool read_mysql_plugin_info(struct st_plugin_dl *plugin_dl, /* Determine interface version */ if (!sym) { - my_error(ER_CANT_FIND_DL_ENTRY, MyFlags, plugin_interface_version_sym, dlpath); + if (!opt_silent_startup) + my_error(ER_CANT_FIND_DL_ENTRY, MyFlags, plugin_interface_version_sym, + dlpath); DBUG_RETURN(TRUE); } plugin_dl->mariaversion= 0; @@ -664,8 +666,9 @@ static my_bool read_maria_plugin_info(struct st_plugin_dl *plugin_dl, Actually this branch impossible because in case of absence of maria version we try mysql version. */ - my_error(ER_CANT_FIND_DL_ENTRY, MyFlags, - maria_plugin_interface_version_sym, dlpath); + if (!opt_silent_startup) + my_error(ER_CANT_FIND_DL_ENTRY, MyFlags, + maria_plugin_interface_version_sym, dlpath); DBUG_RETURN(TRUE); } plugin_dl->mariaversion= *(int *)sym; @@ -779,7 +782,9 @@ static st_plugin_dl *plugin_dl_add(const LEX_CSTRING *dl, myf MyFlags) /* Open new dll handle */ if (!(plugin_dl.handle= dlopen(dlpath, RTLD_NOW))) { - my_error(ER_CANT_OPEN_LIBRARY, MyFlags, dlpath, errno, my_dlerror(dlpath)); + if (!opt_silent_startup) + my_error(ER_CANT_OPEN_LIBRARY, MyFlags, dlpath, errno, + my_dlerror(dlpath)); goto ret; } dlopen_count++; @@ -822,7 +827,8 @@ static st_plugin_dl *plugin_dl_add(const LEX_CSTRING *dl, myf MyFlags) my_snprintf(buf, sizeof(buf), "service '%s' interface version mismatch", list_of_services[i].name); - my_error(ER_CANT_OPEN_LIBRARY, MyFlags, dlpath, ENOEXEC, buf); + if (!opt_silent_startup) + my_error(ER_CANT_OPEN_LIBRARY, MyFlags, dlpath, ENOEXEC, buf); goto ret; } tmp_backup[plugin_dl.nbackups++].save(ptr); @@ -1112,8 +1118,9 @@ static st_plugin_int *plugin_insert_or_reuse(struct st_plugin_int *plugin) NOTE Requires that a write-lock is held on LOCK_system_variables_hash */ -static enum install_status plugin_add(MEM_ROOT *tmp_root, bool if_not_exists, - const LEX_CSTRING *name, LEX_CSTRING *dl, myf MyFlags) +static enum install_status +plugin_add(MEM_ROOT *tmp_root, bool if_not_exists, + const LEX_CSTRING *name, LEX_CSTRING *dl, myf MyFlags) { struct st_plugin_int tmp, *maybe_dupe; struct st_maria_plugin *plugin; @@ -1153,7 +1160,7 @@ static enum install_status plugin_add(MEM_ROOT *tmp_root, bool if_not_exists, if (!name->str && (maybe_dupe= plugin_find_internal(&tmp.name, MYSQL_ANY_PLUGIN))) { - if (plugin->name != maybe_dupe->plugin->name) + if (plugin->name != maybe_dupe->plugin->name && !opt_silent_startup) { my_error(ER_UDF_EXISTS, MyFlags, plugin->name); DBUG_RETURN(INSTALL_FAIL_NOT_OK); @@ -1190,10 +1197,11 @@ static enum install_status plugin_add(MEM_ROOT *tmp_root, bool if_not_exists, } else if (plugin_maturity_map[plugin->maturity] < SERVER_MATURITY_LEVEL) { - sql_print_warning("Plugin '%s' is of maturity level %s while the server is %s", - tmp.name.str, - plugin_maturity_names[plugin->maturity], - plugin_maturity_names[SERVER_MATURITY_LEVEL]); + if (!opt_silent_startup) + sql_print_warning("Plugin '%s' is of maturity level %s while the server is %s", + tmp.name.str, + plugin_maturity_names[plugin->maturity], + plugin_maturity_names[SERVER_MATURITY_LEVEL]); } tmp.plugin= plugin; @@ -1910,14 +1918,10 @@ static void plugin_load(MEM_ROOT *tmp_root) if (result) { DBUG_PRINT("error",("Can't open plugin table")); - if (!opt_help) + if (!opt_silent_startup) sql_print_error("Could not open mysql.plugin table: \"%s\". " "Some plugins may be not loaded", new_thd->get_stmt_da()->message()); - else - sql_print_warning("Could not open mysql.plugin table: \"%s\". " - "Some options may be missing from the help text", - new_thd->get_stmt_da()->message()); goto end; } @@ -2003,8 +2007,10 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, const char *list) { char buffer[FN_REFLEN]; LEX_CSTRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name; + bool got_error= 0; char *p= buffer; DBUG_ENTER("plugin_load_list"); + while (list) { if (p == buffer + sizeof(buffer) - 1) @@ -2018,9 +2024,7 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, const char *list) list= NULL; /* terminate the loop */ /* fall through */ case ';': -#ifndef _WIN32 - case ':': /* can't use this as delimiter as it may be drive letter */ -#endif + case ':': p[-1]= 0; if (str == &name) // load all plugins in named module { @@ -2065,16 +2069,23 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, const char *list) str->length++; continue; } - } - DBUG_RETURN(FALSE); + error: - mysql_mutex_unlock(&LOCK_plugin); - if (name.str) - sql_print_error("Couldn't load plugin '%s' from '%s'.", - name.str, dl.str); - else - sql_print_error("Couldn't load plugins from '%s'.", dl.str); - DBUG_RETURN(TRUE); + got_error= 1; + mysql_mutex_unlock(&LOCK_plugin); + if (!opt_silent_startup) + { + if (name.str) + sql_print_error("Couldn't load plugin '%s' from '%s'.", + name.str, dl.str); + else + sql_print_error("Couldn't load plugins from '%s'.", dl.str); + } + name.length= dl.length= 0; + dl.str= NULL; name.str= p= buffer; + str= &name; + } // Continue with next plugin + DBUG_RETURN(got_error); } @@ -4066,6 +4077,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, (opt->flags & PLUGIN_VAR_MEMALLOC)) { char *def_val= *(char**)var_def_ptr(opt); + my_free(*(char**)val); *(char**)val= def_val ? my_strdup(PSI_INSTRUMENT_ME, def_val, MYF(0)) : NULL; } else