mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 02:46:29 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1244 lines
		
	
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1244 lines
		
	
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|    Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
 | |
| 
 | |
|    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 <my_global.h>
 | |
| #include <m_string.h>
 | |
| #include <mysql.h>
 | |
| #include <my_getopt.h>
 | |
| #include <my_dir.h>
 | |
| #include <mysql_version.h>
 | |
| 
 | |
| #define SHOW_VERSION "1.0.0"
 | |
| #define PRINT_VERSION do { printf("%s  Ver %s Distrib %s\n",    \
 | |
|                         my_progname, SHOW_VERSION, MYSQL_SERVER_VERSION);    \
 | |
|                       } while(0)
 | |
| 
 | |
| /* Global variables. */
 | |
| static uint my_end_arg= 0;
 | |
| static uint opt_verbose=0;
 | |
| static uint opt_no_defaults= 0;
 | |
| static uint opt_print_defaults= 0;
 | |
| static char *opt_datadir=0, *opt_basedir=0,
 | |
|             *opt_plugin_dir=0, *opt_plugin_ini=0,
 | |
|             *opt_mysqld=0, *opt_my_print_defaults=0, *opt_lc_messages_dir;
 | |
| static char bootstrap[FN_REFLEN];
 | |
| 
 | |
| 
 | |
| /* plugin struct */
 | |
| struct st_plugin
 | |
| {
 | |
|   const char *name;           /* plugin name */
 | |
|   const char *so_name;        /* plugin so (library) name */
 | |
|   const char *components[16]; /* components to load */
 | |
| } plugin_data;
 | |
| 
 | |
| 
 | |
| /* Options */
 | |
| static struct my_option my_long_options[] =
 | |
| {
 | |
|   {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
 | |
|     0, 0, 0, 0, 0, 0},
 | |
|   {"basedir", 'b', "The basedir for the server.",
 | |
|     0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 | |
|   {"datadir", 'd', "The datadir for the server.",
 | |
|     0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 | |
|   {"plugin-dir", 'p', "The plugin dir for the server.",
 | |
|     0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 | |
|   {"plugin-ini", 'i', "Read plugin information from configuration file "
 | |
|    "specified instead of from <plugin-dir>/<plugin_name>.ini.",
 | |
|     0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 | |
|   {"no-defaults", 'n', "Do not read values from configuration file.",
 | |
|     0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 | |
|   {"print-defaults", 'P', "Show default values from configuration file.",
 | |
|     0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 | |
|   {"mysqld", 'm', "Path to mysqld executable. Example: /sbin/temp1/mysql/bin",
 | |
|     0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 | |
|   {"my-print-defaults", 'f', "Path to my_print_defaults executable. "
 | |
|    "Example: /source/temp11/extra",
 | |
|     0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 | |
|   {"lc-messages-dir", 'l', "The error messages dir for the server. ",
 | |
|     0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 | |
|   {"verbose", 'v',
 | |
|     "More verbose output; you can use this multiple times to get even more "
 | |
|     "verbose output.",
 | |
|     0, 0, 0, GET_NO_ARG, NO_ARG, 0, 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}
 | |
| };
 | |
| 
 | |
| 
 | |
| /* Methods */
 | |
| static int process_options(int argc, char *argv[], char *operation);
 | |
| static int check_access();
 | |
| static int find_tool(const char *tool_name, char *tool_path);
 | |
| static int find_plugin(char *tp_path);
 | |
| static int build_bootstrap_file(char *operation, char *bootstrap);
 | |
| static int dump_bootstrap_file(char *bootstrap_file);
 | |
| static int bootstrap_server(char *server_path, char *bootstrap_file);
 | |
| 
 | |
| 
 | |
| int main(int argc,char *argv[])
 | |
| {
 | |
|   int error= 0;
 | |
|   char tp_path[FN_REFLEN];
 | |
|   char server_path[FN_REFLEN];
 | |
|   char operation[16];
 | |
| 
 | |
|   MY_INIT(argv[0]);
 | |
|   sf_leaking_memory=1; /* don't report memory leaks on early exits */
 | |
|   plugin_data.name= 0; /* initialize name                          */
 | |
| 
 | |
|   /*
 | |
|     The following operations comprise the method for enabling or disabling
 | |
|     a plugin. We begin by processing the command options then check the
 | |
|     directories specified for --datadir, --basedir, --plugin-dir, and
 | |
|     --plugin-ini (if specified). If the directories are Ok, we then look
 | |
|     for the mysqld executable and the plugin soname. Finally, we build a
 | |
|     bootstrap command file for use in bootstraping the server.
 | |
| 
 | |
|     If any step fails, the method issues an error message and the tool exits.
 | |
| 
 | |
|       1) Parse, execute, and verify command options.
 | |
|       2) Check access to directories.
 | |
|       3) Look for mysqld executable.
 | |
|       4) Look for the plugin.
 | |
|       5) Build a bootstrap file with commands to enable or disable plugin.
 | |
| 
 | |
|   */
 | |
|   if ((error= process_options(argc, argv, operation)) ||
 | |
|       (error= check_access()) ||
 | |
|       (error= find_tool("mysqld" FN_EXEEXT, server_path)) ||
 | |
|       (error= find_plugin(tp_path)) ||
 | |
|       (error= build_bootstrap_file(operation, bootstrap)))
 | |
|     goto exit;
 | |
| 
 | |
|   /* Dump the bootstrap file if --verbose specified. */
 | |
|   if (opt_verbose && ((error= dump_bootstrap_file(bootstrap))))
 | |
|     goto exit;
 | |
| 
 | |
|   /* Start the server in bootstrap mode and execute bootstrap commands */
 | |
|   error= bootstrap_server(server_path, bootstrap);
 | |
| 
 | |
| exit:
 | |
|   /* Remove file */
 | |
|   my_delete(bootstrap, MYF(0));
 | |
|   if (opt_verbose && error == 0)
 | |
|   {
 | |
|     printf("# Operation succeeded.\n");
 | |
|   }
 | |
| 
 | |
|   my_end(my_end_arg);
 | |
|   exit(error ? 1 : 0);
 | |
|   return 0;        /* No compiler warnings */
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Get a temporary file name.
 | |
| 
 | |
|   @param[out]  filename   The file name of the temporary file
 | |
|   @param[in]   ext        An extension for the file (optional)
 | |
| 
 | |
|   @retval int error = 1, success = 0
 | |
| */
 | |
| 
 | |
| static int make_tempfile(char *filename, const char *ext)
 | |
| {
 | |
|   int fd= 0;
 | |
| 
 | |
|   if ((fd= create_temp_file(filename, NullS, ext, 0, MYF(MY_WME))) < 0)
 | |
|   {
 | |
|     fprintf(stderr, "ERROR: Cannot generate temporary file. Error code: %d.\n",
 | |
|             fd);
 | |
|     return 1;
 | |
|   }
 | |
|   my_close(fd, MYF(0));
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Get the value of an option from a string read from my_print_defaults output.
 | |
| 
 | |
|   @param[in]  line   The line (string) read from the file
 | |
|   @param[in]  item   The option to search for (e.g. --datadir)
 | |
| 
 | |
|   @returns NULL if not found, string containing value if found
 | |
| */
 | |
| 
 | |
| static char *get_value(char *line, const char *item)
 | |
| {
 | |
|   char *destination= 0;
 | |
|   int item_len= (int)strlen(item);
 | |
|   int line_len = (int)strlen(line);
 | |
| 
 | |
|   if ((strncasecmp(line, item, item_len) == 0))
 | |
|   {
 | |
|     int start= 0;
 | |
|     char *s= 0;
 | |
| 
 | |
|     s = line + item_len + 1;
 | |
|     destination= my_strndup(PSI_NOT_INSTRUMENTED, s, line_len - start, MYF(MY_FAE));
 | |
|     destination[line_len - item_len - 2]= 0;
 | |
|   }
 | |
|   return destination;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Run a command in a shell.
 | |
| 
 | |
|   This function will attempt to execute the command specified by using the
 | |
|   popen() method to open a shell and execute the command passed and store the
 | |
|   output in a result file. If the --verbose option was specified, it will open
 | |
|   the result file and print the contents to stdout.
 | |
| 
 | |
|   @param[in]  cmd   The command to execute.
 | |
|   @param[in]  mode  The mode for popen() (e.g. "r", "w", "rw")
 | |
| 
 | |
|   @return int error code or 0 for success.
 | |
| */
 | |
| 
 | |
| static int run_command(char* cmd, const char *mode)
 | |
| {
 | |
|   char buf[512]= {0};
 | |
|   FILE *res_file;
 | |
|   int error;
 | |
| 
 | |
|   if (!(res_file= popen(cmd, mode)))
 | |
|     return -1;
 | |
| 
 | |
|   if (opt_verbose)
 | |
|   {
 | |
|     while (fgets(buf, sizeof(buf), res_file))
 | |
|     {
 | |
|       fprintf(stdout, "%s", buf);
 | |
|     }
 | |
|   }
 | |
|   error= pclose(res_file);
 | |
|   return error;
 | |
| }
 | |
| 
 | |
| 
 | |
| #ifdef _WIN32
 | |
| /**
 | |
|   Check to see if there are spaces in a path.
 | |
| 
 | |
|   @param[in]  path  The Windows path to examine.
 | |
| 
 | |
|   @retval int spaces found = 1, no spaces = 0
 | |
| */
 | |
| static int has_spaces(const char *path)
 | |
| {
 | |
|   if (strchr(path, ' ') != NULL)
 | |
|     return 1;
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Convert a Unix path to a Windows path.
 | |
| 
 | |
|   @param[in]  path  The Windows path to examine.
 | |
| 
 | |
|   @returns string containing path with / changed to \\
 | |
| */
 | |
| static char *convert_path(const char *argument)
 | |
| {
 | |
|   /* Convert / to \\ to make Windows paths */
 | |
|   char *winfilename= my_strdup(PSI_NOT_INSTRUMENTED, argument, MYF(MY_FAE));
 | |
|   char *pos, *end;
 | |
|   size_t length= strlen(argument);
 | |
| 
 | |
|   for (pos= winfilename, end= pos+length ; pos < end ; pos++)
 | |
|   {
 | |
|     if (*pos == '/')
 | |
|     {
 | |
|       *pos= '\\';
 | |
|     }
 | |
|   }
 | |
|   return winfilename;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Add quotes if the path has spaces in it.
 | |
| 
 | |
|   @param[in]  path  The Windows path to examine.
 | |
| 
 | |
|   @returns string containing escaped quotes if spaces found in path
 | |
| */
 | |
| static char *add_quotes(const char *path)
 | |
| {
 | |
|   char windows_cmd_friendly[FN_REFLEN];
 | |
| 
 | |
|   if (has_spaces(path))
 | |
|     snprintf(windows_cmd_friendly, sizeof(windows_cmd_friendly),
 | |
|              "\"%s\"", path);
 | |
|   else
 | |
|     snprintf(windows_cmd_friendly, sizeof(windows_cmd_friendly),
 | |
|              "%s", path);
 | |
|   return my_strdup(PSI_NOT_INSTRUMENTED, windows_cmd_friendly, MYF(MY_FAE));
 | |
| }
 | |
| #endif
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Get the default values from the my.cnf file.
 | |
| 
 | |
|   This method gets the default values for the following parameters:
 | |
| 
 | |
|   --datadir
 | |
|   --basedir
 | |
|   --plugin-dir
 | |
|   --plugin-ini
 | |
|   --lc-messages-dir
 | |
| 
 | |
|   These values are used if the user has not specified a value.
 | |
| 
 | |
|   @retval int error = 1, success = 0
 | |
| */
 | |
| 
 | |
| static int get_default_values()
 | |
| {
 | |
|   char tool_path[FN_REFLEN];
 | |
|   char defaults_cmd[FN_REFLEN];
 | |
|   char defaults_file[FN_REFLEN];
 | |
|   char line[FN_REFLEN];
 | |
|   int error= 0;
 | |
|   int ret= 0;
 | |
|   FILE *file= 0;
 | |
| 
 | |
|   memset(tool_path, 0, FN_REFLEN);
 | |
|   if ((error= find_tool("my_print_defaults" FN_EXEEXT, tool_path)))
 | |
|     goto exit;
 | |
|   else
 | |
|   {
 | |
|     if ((error= make_tempfile(defaults_file, "txt")))
 | |
|       goto exit;
 | |
| 
 | |
| #ifdef _WIN32
 | |
|     {
 | |
|       char *format_str= 0;
 | |
| 
 | |
|       if (has_spaces(tool_path) || has_spaces(defaults_file))
 | |
|         format_str = "\"%s --mysqld > %s\"";
 | |
|       else
 | |
|         format_str = "%s --mysqld > %s";
 | |
| 
 | |
|       snprintf(defaults_cmd, sizeof(defaults_cmd), format_str,
 | |
|                add_quotes(tool_path), add_quotes(defaults_file));
 | |
|       if (opt_verbose)
 | |
|       {
 | |
|         printf("# my_print_defaults found: %s\n", tool_path);
 | |
|       }
 | |
|     }
 | |
| #else
 | |
|     snprintf(defaults_cmd, sizeof(defaults_cmd),
 | |
|              "%s --mysqld > %s", tool_path, defaults_file);
 | |
| #endif
 | |
| 
 | |
|     /* Execute the command */
 | |
|     if (opt_verbose)
 | |
|     {
 | |
|       printf("# Command: %s\n", defaults_cmd);
 | |
|     }
 | |
|     error= run_command(defaults_cmd, "r");
 | |
|     if (error)
 | |
|     {
 | |
|       fprintf(stderr, "ERROR: my_print_defaults failed. Error code: %d.\n",
 | |
|               ret);
 | |
|       goto exit;
 | |
|     }
 | |
|     /* Now open the file and read the defaults we want. */
 | |
|     file= fopen(defaults_file, "r");
 | |
|     if (file == NULL)
 | |
|     {
 | |
|       fprintf(stderr, "ERROR: failed to open file %s: %s.\n", defaults_file,
 | |
|               strerror(errno));
 | |
|       goto exit;
 | |
|     }
 | |
|     while (fgets(line, FN_REFLEN, file) != NULL)
 | |
|     {
 | |
|       char *value= 0;
 | |
| 
 | |
|       if ((opt_datadir == 0) && ((value= get_value(line, "--datadir"))))
 | |
|       {
 | |
|         opt_datadir= my_strdup(PSI_NOT_INSTRUMENTED, value, MYF(MY_FAE));
 | |
|       }
 | |
|       if ((opt_basedir == 0) && ((value= get_value(line, "--basedir"))))
 | |
|       {
 | |
|         opt_basedir= my_strdup(PSI_NOT_INSTRUMENTED, value, MYF(MY_FAE));
 | |
|       }
 | |
|       if ((opt_plugin_dir == 0) && ((value= get_value(line, "--plugin_dir")) ||
 | |
|           (value= get_value(line, "--plugin-dir"))))
 | |
|       {
 | |
|         opt_plugin_dir= my_strdup(PSI_NOT_INSTRUMENTED, value, MYF(MY_FAE));
 | |
|       }
 | |
|       if ((opt_lc_messages_dir == 0) &&
 | |
|           ((value= get_value(line, "--lc_messages_dir")) ||
 | |
|           (value= get_value(line, "--lc_messages-dir")) ||
 | |
|           (value= get_value(line, "--lc-messages_dir")) ||
 | |
|           (value= get_value(line, "--lc-messages-dir"))))
 | |
|       {
 | |
|         opt_lc_messages_dir= my_strdup(PSI_NOT_INSTRUMENTED, value, MYF(MY_FAE));
 | |
|       }
 | |
| 
 | |
|     }
 | |
|   }
 | |
| exit:
 | |
|   if (file)
 | |
|   {
 | |
|     fclose(file);
 | |
|     /* Remove file */
 | |
|     my_delete(defaults_file, MYF(0));
 | |
|   }
 | |
|   return error;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Print usage.
 | |
| */
 | |
| 
 | |
| static void usage(void)
 | |
| {
 | |
|   PRINT_VERSION;
 | |
|   puts("Copyright (c) 2011, 2015, Oracle and/or its affiliates. "
 | |
|        "All rights reserved.\n");
 | |
|   puts("Enable or disable plugins.");
 | |
|   printf("\nUsage: %s [options] <plugin> ENABLE|DISABLE\n\nOptions:\n",
 | |
|      my_progname);
 | |
|   my_print_help(my_long_options);
 | |
|   puts("\n");
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Print the default values as read from the my.cnf file.
 | |
| 
 | |
|   This method displays the default values for the following parameters:
 | |
| 
 | |
|   --datadir
 | |
|   --basedir
 | |
|   --plugin-dir
 | |
|   --plugin-ini
 | |
|   --lc-messages-dir
 | |
| 
 | |
| */
 | |
| 
 | |
| static void print_default_values(void)
 | |
| {
 | |
|   printf("%s would have been started with the following arguments:\n",
 | |
|          my_progname);
 | |
|   get_default_values();
 | |
|   if (opt_datadir)
 | |
|   {
 | |
|     printf("--datadir=%s ", opt_datadir);
 | |
|   }
 | |
|   if (opt_basedir)
 | |
|   {
 | |
|     printf("--basedir=%s ", opt_basedir);
 | |
|   }
 | |
|   if (opt_plugin_dir)
 | |
|   {
 | |
|     printf("--plugin_dir=%s ", opt_plugin_dir);
 | |
|   }
 | |
|   if (opt_plugin_ini)
 | |
|   {
 | |
|     printf("--plugin_ini=%s ", opt_plugin_ini);
 | |
|   }
 | |
|   if (opt_mysqld)
 | |
|   {
 | |
|     printf("--mysqld=%s ", opt_mysqld);
 | |
|   }
 | |
|   if (opt_my_print_defaults)
 | |
|   {
 | |
|     printf("--my_print_defaults=%s ", opt_my_print_defaults);
 | |
|   }
 | |
|   if (opt_lc_messages_dir)
 | |
|   {
 | |
|     printf("--lc_messages_dir=%s ", opt_lc_messages_dir);
 | |
|   }
 | |
|   printf("\n");
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Process the arguments and identify an option and store its value.
 | |
| 
 | |
|   @param[in]  optid      The single character shortcut for the argument.
 | |
|   @param[in]  my_option  Structure of legal options.
 | |
|   @param[in]  argument   The argument value to process.
 | |
| */
 | |
| 
 | |
| static my_bool
 | |
| get_one_option(const struct my_option *opt,
 | |
|                const char *argument,
 | |
|                const char *filename __attribute__((unused)))
 | |
| {
 | |
|   switch(opt->id) {
 | |
|   case 'n':
 | |
|     opt_no_defaults++;
 | |
|     break;
 | |
|   case 'P':
 | |
|     opt_print_defaults++;
 | |
|     print_default_values();
 | |
|     break;
 | |
|   case 'v':
 | |
|     opt_verbose++;
 | |
|     break;
 | |
|   case 'V':
 | |
|     PRINT_VERSION;
 | |
|     exit(0);
 | |
|     break;
 | |
|   case '?':
 | |
|   case 'I':          /* Info */
 | |
|     usage();
 | |
|     exit(0);
 | |
|   case 'd':
 | |
|     opt_datadir= my_strdup(PSI_NOT_INSTRUMENTED, argument, MYF(MY_FAE));
 | |
|     break;
 | |
|   case 'b':
 | |
|     opt_basedir= my_strdup(PSI_NOT_INSTRUMENTED, argument, MYF(MY_FAE));
 | |
|     break;
 | |
|   case 'p':
 | |
|     opt_plugin_dir= my_strdup(PSI_NOT_INSTRUMENTED, argument, MYF(MY_FAE));
 | |
|     break;
 | |
|   case 'i':
 | |
|     opt_plugin_ini= my_strdup(PSI_NOT_INSTRUMENTED, argument, MYF(MY_FAE));
 | |
|     break;
 | |
|   case 'm':
 | |
|     opt_mysqld= my_strdup(PSI_NOT_INSTRUMENTED, argument, MYF(MY_FAE));
 | |
|     break;
 | |
|   case 'f':
 | |
|     opt_my_print_defaults= my_strdup(PSI_NOT_INSTRUMENTED, argument, MYF(MY_FAE));
 | |
|     break;
 | |
|   case 'l':
 | |
|     opt_lc_messages_dir= my_strdup(PSI_NOT_INSTRUMENTED, argument, MYF(MY_FAE));
 | |
|     break;
 | |
| 
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Check to see if a file exists.
 | |
| 
 | |
|   @param[in]  filename  File to locate.
 | |
| 
 | |
|   @retval int file not found = 1, file found = 0
 | |
| */
 | |
| 
 | |
| static int file_exists(char * filename)
 | |
| {
 | |
|   MY_STAT stat_arg;
 | |
| 
 | |
|   if (!my_stat(filename, &stat_arg, MYF(0)))
 | |
|   {
 | |
|     return 0;
 | |
|   }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Search a specific path and sub directory for a file name.
 | |
| 
 | |
|   @param[in]  base_path  Original path to use.
 | |
|   @param[in]  tool_name  Name of the tool to locate.
 | |
|   @param[in]  subdir     The sub directory to search.
 | |
|   @param[out] tool_path  If tool found, return complete path.
 | |
| 
 | |
|   @retval int error = 1, success = 0
 | |
| */
 | |
| 
 | |
| static int search_dir(const char *base_path, const char *tool_name,
 | |
|                       const char *subdir, char *tool_path)
 | |
| {
 | |
|   char new_path[FN_REFLEN];
 | |
|   char source_path[FN_REFLEN];
 | |
| 
 | |
|   safe_strcpy(source_path, sizeof(source_path), base_path);
 | |
|   safe_strcat(source_path, sizeof(source_path), subdir);
 | |
|   fn_format(new_path, tool_name, source_path, "", MY_UNPACK_FILENAME);
 | |
|   if (file_exists(new_path))
 | |
|   {
 | |
|     strcpy(tool_path, new_path);
 | |
|     return 1;
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Search known common paths and sub directories for a file name.
 | |
| 
 | |
|   @param[in]  base_path  Original path to use.
 | |
|   @param[in]  tool_name  Name of the tool to locate.
 | |
|   @param[out] tool_path  If tool found, return complete path.
 | |
| 
 | |
|   @retval int error = 1, success = 0
 | |
| */
 | |
| 
 | |
| static int search_paths(const char *base_path, const char *tool_name,
 | |
|                         char *tool_path)
 | |
| {
 | |
|   int i= 0;
 | |
| 
 | |
|   static const char *paths[]= {
 | |
|     "", "/share/",  "/scripts/", "/bin/", "/sbin/", "/libexec/",
 | |
|     "/mysql/", "/sql/",
 | |
|   };
 | |
|   for (i = 0 ; i < (int)array_elements(paths); i++)
 | |
|   {
 | |
|     if (search_dir(base_path, tool_name, paths[i], tool_path))
 | |
|     {
 | |
|       return 1;
 | |
|     }
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Read the plugin ini file.
 | |
| 
 | |
|   This function attempts to read the plugin config file from the plugin_dir
 | |
|   path saving the data in the the st_plugin structure. If the file is not
 | |
|   found or the file cannot be read, an error is generated.
 | |
| 
 | |
|   @retval int error = 1, success = 0
 | |
| */
 | |
| 
 | |
| static int load_plugin_data(char *plugin_name, char *config_file)
 | |
| {
 | |
|   FILE *file_ptr;
 | |
|   char path[FN_REFLEN];
 | |
|   char line[1024];
 | |
|   const char *reason= 0;
 | |
|   char *res;
 | |
|   int i= -1;
 | |
| 
 | |
|   if (opt_plugin_ini == 0)
 | |
|   {
 | |
|     fn_format(path, config_file, opt_plugin_dir, "", MYF(0));
 | |
|     opt_plugin_ini= my_strdup(PSI_NOT_INSTRUMENTED, path, MYF(MY_FAE));
 | |
|   }
 | |
|   if (!file_exists(opt_plugin_ini))
 | |
|   {
 | |
|     reason= "File does not exist.";
 | |
|     goto error;
 | |
|   }
 | |
| 
 | |
|   file_ptr= fopen(opt_plugin_ini, "r");
 | |
|   if (file_ptr == NULL)
 | |
|   {
 | |
|     reason= "Cannot open file.";
 | |
|     goto error;
 | |
|   }
 | |
| 
 | |
|   /* save name */
 | |
|   plugin_data.name= my_strdup(PSI_NOT_INSTRUMENTED, plugin_name, MYF(MY_WME));
 | |
| 
 | |
|   /* Read plugin components */
 | |
|   while (i < 16)
 | |
|   {
 | |
|     size_t line_len;
 | |
| 
 | |
|     res= fgets(line, sizeof(line), file_ptr);
 | |
|     line_len= strlen(line);
 | |
| 
 | |
|     /* strip /n */
 | |
|     if (line[line_len - 1] == '\n')
 | |
|       line[line_len - 1]= '\0';
 | |
| 
 | |
|     if (res == NULL)
 | |
|     {
 | |
|       if (i < 1)
 | |
|       {
 | |
|         reason= "Bad format in plugin configuration file.";
 | |
|         fclose(file_ptr);
 | |
|         goto error;
 | |
|       }
 | |
|       break;
 | |
|     }
 | |
|     if ((line[0] == '#') || (line[0] == '\n')) /* skip comment and blank lines */
 | |
|     {
 | |
|       continue;
 | |
|     }
 | |
|     if (i == -1) /* if first pass, read this line as so_name */
 | |
|     {
 | |
|       /* Add proper file extension for soname */
 | |
|       if (safe_strcpy_truncated(line + line_len - 1, sizeof line, FN_SOEXT))
 | |
|       {
 | |
|         reason= "Plugin name too long.";
 | |
|         fclose(file_ptr);
 | |
|         goto error;
 | |
|       }
 | |
|       /* save so_name */
 | |
|       plugin_data.so_name= my_strdup(PSI_NOT_INSTRUMENTED, line, MYF(MY_WME|MY_ZEROFILL));
 | |
|       i++;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       if (line_len > 0)
 | |
|       {
 | |
|         plugin_data.components[i]= my_strdup(PSI_NOT_INSTRUMENTED, line, MYF(MY_WME));
 | |
|         i++;
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         plugin_data.components[i]= NULL;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   fclose(file_ptr);
 | |
|   return 0;
 | |
| 
 | |
| error:
 | |
|   fprintf(stderr, "ERROR: Cannot read plugin config file %s. %s\n",
 | |
|           plugin_name, reason);
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Check the options for validity.
 | |
| 
 | |
|   This function checks the arguments for validity issuing the appropriate
 | |
|   error message if arguments are missing or invalid. On success, @operation
 | |
|   is set to either "ENABLE" or "DISABLE".
 | |
| 
 | |
|   @param[in]  argc       The number of arguments.
 | |
|   @param[in]  argv       The arguments.
 | |
|   @param[out] operation  The operation chosen (enable|disable)
 | |
| 
 | |
|   @retval int error = 1, success = 0
 | |
| */
 | |
| 
 | |
| static int check_options(int argc, char **argv, char *operation)
 | |
| {
 | |
|   int i= 0;                    /* loop counter */
 | |
|   int num_found= 0;            /* number of options found (shortcut loop) */
 | |
|   char config_file[FN_REFLEN+1]; /* configuration file name */
 | |
|   char plugin_name[FN_REFLEN+1]; /* plugin name */
 | |
| 
 | |
|   /* Form prefix strings for the options. */
 | |
|   const char *basedir_prefix = "--basedir=";
 | |
|   size_t basedir_len= strlen(basedir_prefix);
 | |
|   const char *datadir_prefix = "--datadir=";
 | |
|   size_t datadir_len= strlen(datadir_prefix);
 | |
|   const char *plugin_dir_prefix = "--plugin_dir=";
 | |
|   size_t plugin_dir_len= strlen(plugin_dir_prefix);
 | |
| 
 | |
|   *plugin_name= '\0';
 | |
|   for (i = 0; i < argc && num_found < 5; i++)
 | |
|   {
 | |
| 
 | |
|     if (!argv[i])
 | |
|     {
 | |
|       continue;
 | |
|     }
 | |
|     if ((strcasecmp(argv[i], "ENABLE") == 0) ||
 | |
|         (strcasecmp(argv[i], "DISABLE") == 0))
 | |
|     {
 | |
|       strcpy(operation, argv[i]);
 | |
|       num_found++;
 | |
|     }
 | |
|     else if ((strncasecmp(argv[i], basedir_prefix, basedir_len) == 0) &&
 | |
|              !opt_basedir)
 | |
|     {
 | |
|       opt_basedir= my_strndup(PSI_NOT_INSTRUMENTED, argv[i]+basedir_len,
 | |
|                               strlen(argv[i])-basedir_len, MYF(MY_FAE));
 | |
|       num_found++;
 | |
|     }
 | |
|     else if ((strncasecmp(argv[i], datadir_prefix, datadir_len) == 0) &&
 | |
|              !opt_datadir)
 | |
|     {
 | |
|       opt_datadir= my_strndup(PSI_NOT_INSTRUMENTED, argv[i]+datadir_len,
 | |
|                               strlen(argv[i])-datadir_len, MYF(MY_FAE));
 | |
|       num_found++;
 | |
|     }
 | |
|     else if ((strncasecmp(argv[i], plugin_dir_prefix, plugin_dir_len) == 0) &&
 | |
|              !opt_plugin_dir)
 | |
|     {
 | |
|       opt_plugin_dir= my_strndup(PSI_NOT_INSTRUMENTED, argv[i]+plugin_dir_len,
 | |
|                                  strlen(argv[i])-plugin_dir_len, MYF(MY_FAE));
 | |
|       num_found++;
 | |
|     }
 | |
|     /* read the plugin config file and check for match against argument */
 | |
|     else
 | |
|     {
 | |
|       if (safe_strcpy_truncated(plugin_name, sizeof(plugin_name)-1, argv[i]) ||
 | |
|           safe_strcpy_truncated(config_file, sizeof(config_file)-1, argv[i]) ||
 | |
|           safe_strcat(config_file, sizeof(config_file), ".ini"))
 | |
|       {
 | |
|         fprintf(stderr, "ERROR: argument is too long.\n");
 | |
|         return 1;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!opt_basedir)
 | |
|   {
 | |
|     fprintf(stderr, "ERROR: Missing --basedir option.\n");
 | |
|     return 1;
 | |
|   }
 | |
| 
 | |
|   if (!opt_datadir)
 | |
|   {
 | |
|     fprintf(stderr, "ERROR: Missing --datadir option.\n");
 | |
|     return 1;
 | |
|   }
 | |
| 
 | |
|   if (!opt_plugin_dir)
 | |
|   {
 | |
|     fprintf(stderr, "ERROR: Missing --plugin_dir option.\n");
 | |
|     return 1;
 | |
|   }
 | |
|   /* If a plugin was specified, read the config file. */
 | |
|   else if (strlen(plugin_name) > 0)
 | |
|   {
 | |
|     if (load_plugin_data(plugin_name, config_file))
 | |
|     {
 | |
|       return 1;
 | |
|     }
 | |
|     if (strcasecmp(plugin_data.name, plugin_name) != 0)
 | |
|     {
 | |
|       fprintf(stderr, "ERROR: plugin name requested does not match config "
 | |
|               "file data.\n");
 | |
|       return 1;
 | |
|     }
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     fprintf(stderr, "ERROR: No plugin specified.\n");
 | |
|     return 1;
 | |
|   }
 | |
| 
 | |
|   if ((strlen(operation) == 0))
 | |
|   {
 | |
|     fprintf(stderr, "ERROR: missing operation. Please specify either "
 | |
|             "'<plugin> ENABLE' or '<plugin> DISABLE'.\n");
 | |
|     return 1;
 | |
|   }
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Parse, execute, and verify command options.
 | |
| 
 | |
|   This method handles all of the option processing including the optional
 | |
|   features for displaying data (--print-defaults, --help ,etc.) that do not
 | |
|   result in an attempt to ENABLE or DISABLE of a plugin.
 | |
| 
 | |
|   @param[in]   arc        Count of arguments
 | |
|   @param[in]   argv       Array of arguments
 | |
|   @param[out]  operation  Operation (ENABLE or DISABLE)
 | |
| 
 | |
|   @retval int error = 1, success = 0, exit program = -1
 | |
| */
 | |
| 
 | |
| static int process_options(int argc, char *argv[], char *operation)
 | |
| {
 | |
|   int error= 0;
 | |
| 
 | |
|   /* Parse and execute command-line options */
 | |
|   if ((error= handle_options(&argc, &argv, my_long_options, get_one_option)))
 | |
|     return error;
 | |
| 
 | |
|   /* If the print defaults option used, exit. */
 | |
|   if (opt_print_defaults)
 | |
|     return -1;
 | |
| 
 | |
|   /* Add a trailing directory separator if not present */
 | |
|   if (opt_basedir)
 | |
|   {
 | |
|     size_t basedir_len= strlength(opt_basedir);
 | |
|     if (opt_basedir[basedir_len - 1] != FN_LIBCHAR ||
 | |
|         opt_basedir[basedir_len - 1] != FN_LIBCHAR2)
 | |
|     {
 | |
|       char buff[FN_REFLEN];
 | |
|       if (basedir_len + 2 > FN_REFLEN)
 | |
|         return -1;
 | |
| 
 | |
|       memcpy(buff, opt_basedir, basedir_len);
 | |
|       buff[basedir_len]= '/';
 | |
|       buff[basedir_len + 1]= '\0';
 | |
| 
 | |
|       my_free(opt_basedir);
 | |
|       opt_basedir= my_strdup(PSI_NOT_INSTRUMENTED, buff, MYF(MY_FAE));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /*
 | |
|     If the user did not specify the option to skip loading defaults from a
 | |
|     config file and the required options are not present or there was an error
 | |
|     generated when the defaults were read from the file, exit.
 | |
|   */
 | |
|   if (!opt_no_defaults && ((error= get_default_values())))
 | |
|     return -1;
 | |
| 
 | |
|   /*
 | |
|    Check to ensure required options are present and validate the operation.
 | |
|    Note: this method also validates the plugin specified by attempting to
 | |
|    read a configuration file named <plugin_name>.ini from the --plugin-dir
 | |
|    or --plugin-ini location if the --plugin-ini option presented.
 | |
|   */
 | |
|   operation[0]= '\0';
 | |
|   if ((error= check_options(argc, argv, operation)))
 | |
|     return error;
 | |
| 
 | |
|   if (opt_verbose)
 | |
|   {
 | |
|     printf("#    basedir = %s\n", opt_basedir);
 | |
|     printf("# plugin_dir = %s\n", opt_plugin_dir);
 | |
|     printf("#    datadir = %s\n", opt_datadir);
 | |
|     printf("# plugin_ini = %s\n", opt_plugin_ini);
 | |
|     if (opt_lc_messages_dir != 0)
 | |
|       printf("# lc_messages_dir = %s\n", opt_lc_messages_dir);
 | |
|   }
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Check access
 | |
| 
 | |
|   This method checks to ensure all of the directories (opt_basedir,
 | |
|   opt_plugin_dir, opt_datadir, and opt_plugin_ini) are accessible by
 | |
|   the user.
 | |
| 
 | |
|   @retval int error = 1, success = 0
 | |
| */
 | |
| 
 | |
| static int check_access()
 | |
| {
 | |
|   int error= 0;
 | |
| 
 | |
|   if ((error= my_access(opt_basedir, F_OK)))
 | |
|   {
 | |
|     fprintf(stderr, "ERROR: Cannot access basedir at '%s'.\n",
 | |
|             opt_basedir);
 | |
|     goto exit;
 | |
|   }
 | |
|   if ((error= my_access(opt_plugin_dir, F_OK)))
 | |
|   {
 | |
|     fprintf(stderr, "ERROR: Cannot access plugin_dir at '%s'.\n",
 | |
|             opt_plugin_dir);
 | |
|     goto exit;
 | |
|   }
 | |
|   if ((error= my_access(opt_datadir, F_OK)))
 | |
|   {
 | |
|     fprintf(stderr, "ERROR: Cannot access datadir at '%s'.\n",
 | |
|             opt_datadir);
 | |
|     goto exit;
 | |
|   }
 | |
|   if (opt_plugin_ini && (error= my_access(opt_plugin_ini, F_OK)))
 | |
|   {
 | |
|     fprintf(stderr, "ERROR: Cannot access plugin config file at '%s'.\n",
 | |
|             opt_plugin_ini);
 | |
|     goto exit;
 | |
|   }
 | |
|   if (opt_mysqld && (error= my_access(opt_mysqld, F_OK)))
 | |
|   {
 | |
|     fprintf(stderr, "ERROR: Cannot access mariadbd path '%s'.\n",
 | |
|             opt_mysqld);
 | |
|     goto exit;
 | |
|   }
 | |
|   if (opt_my_print_defaults && (error= my_access(opt_my_print_defaults, F_OK)))
 | |
|   {
 | |
|     fprintf(stderr, "ERROR: Cannot access my-print-defaults path '%s'.\n",
 | |
|             opt_my_print_defaults);
 | |
|     goto exit;
 | |
|   }
 | |
|   if (opt_lc_messages_dir && (error= my_access(opt_lc_messages_dir, F_OK)))
 | |
|   {
 | |
|     fprintf(stderr, "ERROR: Cannot access lc-messages-dir path '%s'.\n",
 | |
|             opt_lc_messages_dir);
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
| exit:
 | |
|   return error;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Locate the tool and form tool path.
 | |
| 
 | |
|   @param[in]  tool_name  Name of the tool to locate.
 | |
|   @param[out] tool_path  If tool found, return complete path.
 | |
| 
 | |
|   @retval int error = 1, success = 0
 | |
| */
 | |
| 
 | |
| static int find_tool(const char *tool_name, char *tool_path)
 | |
| {
 | |
|   int i= 0;
 | |
| 
 | |
|   const char *paths[]= {
 | |
|     opt_mysqld, opt_basedir, opt_my_print_defaults, "/usr",
 | |
|     "/usr/local/mysql", "/usr/sbin", "/usr/share", "/extra", "/extra/debug",
 | |
|     "/extra/release", "/bin", "/usr/bin", "/mysql/bin"
 | |
|   };
 | |
|   for (i= 0; i < (int)array_elements(paths); i++)
 | |
|   {
 | |
|     if (paths[i] && (search_paths(paths[i], tool_name, tool_path)))
 | |
|       goto found;
 | |
|   }
 | |
|   fprintf(stderr, "WARNING: Cannot find %s.\n", tool_name);
 | |
|   return 1;
 | |
| found:
 | |
|   if (opt_verbose)
 | |
|     printf("# Found tool '%s' as '%s'.\n", tool_name, tool_path);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Find the plugin library.
 | |
| 
 | |
|   This function attempts to use the @c plugin_dir option passed on the
 | |
|   command line to locate the plugin.
 | |
| 
 | |
|   @param[out] tp_path   The actual path to plugin with FN_SOEXT applied.
 | |
| 
 | |
|   @retval int error = 1, success = 0
 | |
| */
 | |
| 
 | |
| static int find_plugin(char *tp_path)
 | |
| {
 | |
|   /* Check for existence of plugin */
 | |
|   fn_format(tp_path, plugin_data.so_name, opt_plugin_dir, "", MYF(0));
 | |
|   if (!file_exists(tp_path))
 | |
|   {
 | |
|     fprintf(stderr, "ERROR: The plugin library is missing or in a different"
 | |
|             " location.\n");
 | |
|     return 1;
 | |
|   }
 | |
|   else if (opt_verbose)
 | |
|   {
 | |
|     printf("# Found plugin '%s' as '%s'\n", plugin_data.name, tp_path);
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Build the bootstrap file.
 | |
| 
 | |
|   Create a new file and populate it with SQL commands to ENABLE or DISABLE
 | |
|   the plugin via REPLACE and DELETE operations on the mysql.plugin table.
 | |
| 
 | |
|   param[in]  operation  The type of operation (ENABLE or DISABLE)
 | |
|   param[out] bootstrap  A FILE* pointer
 | |
| 
 | |
|   @retval int error = 1, success = 0
 | |
| */
 | |
| 
 | |
| static int build_bootstrap_file(char *operation, char *bootstrap)
 | |
| {
 | |
|   int error= 0;
 | |
|   FILE *file= 0;
 | |
| 
 | |
|   /*
 | |
|     Perform plugin operation : ENABLE or DISABLE
 | |
| 
 | |
|     The following creates a temporary bootstrap file and populates it with
 | |
|     the appropriate SQL commands for the operation. For ENABLE, REPLACE
 | |
|     statements are created. For DISABLE, DELETE statements are created. The
 | |
|     values for these statements are derived from the plugin_data read from the
 | |
|     <plugin_name>.ini configuration file. Once the file is built, a call to
 | |
|     mysqld is made in read only, bootstrap modes to read the SQL statements
 | |
|     and execute them.
 | |
| 
 | |
|     Note: Replace was used so that if a user loads a newer version of a
 | |
|           library with a different library name, the new library name is
 | |
|           used for symbols that match.
 | |
|   */
 | |
|   if ((error= make_tempfile(bootstrap, "sql")))
 | |
|   {
 | |
|     /* Fail if we cannot create a temporary file for the bootstrap commands. */
 | |
|     fprintf(stderr, "ERROR: Cannot create bootstrap file.\n");
 | |
|     goto exit;
 | |
|   }
 | |
|   if ((file= fopen(bootstrap, "w+")) == NULL)
 | |
|   {
 | |
|     fprintf(stderr, "ERROR: Cannot open bootstrap file for writing.\n");
 | |
|     error= 1;
 | |
|     goto exit;
 | |
|   }
 | |
|   if (strcasecmp(operation, "enable") == 0)
 | |
|   {
 | |
|     int i= 0;
 | |
|     fprintf(file, "REPLACE INTO mysql.plugin VALUES ");
 | |
|     for (i= 0; i < (int)array_elements(plugin_data.components); i++)
 | |
|     {
 | |
|       /* stop when we read the end of the symbol list - marked with NULL */
 | |
|       if (plugin_data.components[i] == NULL)
 | |
|       {
 | |
|         break;
 | |
|       }
 | |
|       if (i > 0)
 | |
|       {
 | |
|         fprintf(file, ", ");
 | |
|       }
 | |
|       fprintf(file, "('%s','%s')",
 | |
|               plugin_data.components[i], plugin_data.so_name);
 | |
|     }
 | |
|     fprintf(file, ";\n");
 | |
|     if (opt_verbose)
 | |
|     {
 | |
|       printf("# Enabling %s...\n", plugin_data.name);
 | |
|     }
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     fprintf(file,
 | |
|             "DELETE FROM mysql.plugin WHERE dl = '%s';", plugin_data.so_name);
 | |
|     if (opt_verbose)
 | |
|     {
 | |
|       printf("# Disabling %s...\n", plugin_data.name);
 | |
|     }
 | |
|   }
 | |
| 
 | |
| exit:
 | |
|   fclose(file);
 | |
|   return error;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Dump bootstrap file.
 | |
| 
 | |
|   Read the contents of the bootstrap file and print it out.
 | |
| 
 | |
|   @param[in]  bootstrap_file  Name of bootstrap file to read
 | |
| 
 | |
|   @retval int error = 1, success = 0
 | |
| */
 | |
| 
 | |
| static int dump_bootstrap_file(char *bootstrap_file)
 | |
| {
 | |
|   char *ret= 0;
 | |
|   int error= 0;
 | |
|   char query_str[512];
 | |
|   FILE *file= 0;
 | |
| 
 | |
|   if ((file= fopen(bootstrap_file, "r")) == NULL)
 | |
|   {
 | |
|     fprintf(stderr, "ERROR: Cannot open bootstrap file for reading.\n");
 | |
|     error= 1;
 | |
|     goto exit;
 | |
|   }
 | |
|   ret= fgets(query_str, 512, file);
 | |
|   if (ret == 0)
 | |
|   {
 | |
|     fprintf(stderr, "ERROR: Cannot read bootstrap file.\n");
 | |
|     error= 1;
 | |
|     goto exit;
 | |
|   }
 | |
|   printf("# Query: %s\n", query_str);
 | |
| 
 | |
| exit:
 | |
|   if (file)
 | |
|   {
 | |
|     fclose(file);
 | |
|   }
 | |
|   return error;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Bootstrap the server
 | |
| 
 | |
|   Create a command line sequence to launch mysqld in bootstrap mode. This
 | |
|   will allow mysqld to launch a minimal server instance to read and
 | |
|   execute SQL commands from a file piped in (the bootstrap file). We use
 | |
|   the --no-defaults option to skip reading values from the config file.
 | |
| 
 | |
|   The bootstrap mode skips loading of plugins and many other subsystems.
 | |
|   This allows the mysql_plugin tool to insert the correct rows into the
 | |
|   mysql.plugin table (for ENABLE) or delete the rows (for DISABLE). Once
 | |
|   the server is launched in normal mode, the plugin will be loaded
 | |
|   (for ENABLE) or not loaded (for DISABLE). In this way, we avoid the
 | |
|   (sometimes) complicated LOAD PLUGIN commands.
 | |
| 
 | |
|   @param[in]  server_path     Path to server executable
 | |
|   @param[in]  bootstrap_file  Name of bootstrap file to read
 | |
| 
 | |
|   @retval int error = 1, success = 0
 | |
| */
 | |
| 
 | |
| static int bootstrap_server(char *server_path, char *bootstrap_file)
 | |
| {
 | |
|   char bootstrap_cmd[FN_REFLEN]= {0};
 | |
|   char lc_messages_dir_str[FN_REFLEN]= {0};
 | |
|   int error= 0;
 | |
| 
 | |
| #ifdef _WIN32
 | |
|   char *format_str= 0;
 | |
|   const char *verbose_str= NULL;
 | |
| #endif
 | |
| 
 | |
|   if (opt_lc_messages_dir != NULL)
 | |
|     snprintf(lc_messages_dir_str, sizeof(lc_messages_dir_str), "--lc-messages-dir=%s",
 | |
|              opt_lc_messages_dir);
 | |
| 
 | |
| #ifdef _WIN32
 | |
|   if (opt_verbose)
 | |
|     verbose_str= "--console";
 | |
|   else
 | |
|     verbose_str= "";
 | |
| 
 | |
|   if (has_spaces(opt_datadir) || has_spaces(opt_basedir) ||
 | |
|       has_spaces(bootstrap_file) || has_spaces(lc_messages_dir_str))
 | |
|     format_str= "\"%s %s --bootstrap --datadir=%s --basedir=%s %s <%s\"";
 | |
|   else
 | |
|     format_str= "%s %s --bootstrap --datadir=%s --basedir=%s %s <%s";
 | |
| 
 | |
|   snprintf(bootstrap_cmd, sizeof(bootstrap_cmd), format_str,
 | |
|            add_quotes(convert_path(server_path)), verbose_str,
 | |
|            add_quotes(opt_datadir), add_quotes(opt_basedir),
 | |
|            add_quotes(lc_messages_dir_str), add_quotes(bootstrap_file));
 | |
| #else
 | |
|   snprintf(bootstrap_cmd, sizeof(bootstrap_cmd),
 | |
|            "%s --no-defaults --bootstrap --datadir=%s --basedir=%s %s"
 | |
|            " <%s", server_path, opt_datadir, opt_basedir, lc_messages_dir_str, bootstrap_file);
 | |
| #endif
 | |
| 
 | |
|   /* Execute the command */
 | |
|   if (opt_verbose)
 | |
|   {
 | |
|     printf("# Command: %s\n", bootstrap_cmd);
 | |
|   }
 | |
|   error= run_command(bootstrap_cmd, "r");
 | |
|   if (error)
 | |
|     fprintf(stderr,
 | |
|             "ERROR: Unexpected result from bootstrap. Error code: %d.\n",
 | |
|             error);
 | |
| 
 | |
|   return error;
 | |
| }
 | 
