/*
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
*/
#define VER "1.0"
#include <my_global.h>
#include <m_string.h>
#include <mysql.h>
#include <my_getopt.h>
#include <my_dir.h>
#include <mysql_version.h>
#include <welcome_copyright_notice.h>
/* 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;
}
Messung V0.5 in Prozent C=95 H=87 G=90
¤ Dauer der Verarbeitung: 0.30 Sekunden
(vorverarbeitet am 2026-10-08)
¤
*© Formatika GbR, Deutschland