|
|
|
@ -16,21 +16,42 @@ |
|
|
|
|
|
|
|
#include "client_priv.h" |
|
|
|
#include <my_dir.h> |
|
|
|
#include <my_list.h> |
|
|
|
#include <sslopt-vars.h> |
|
|
|
|
|
|
|
#define UPGRADE_DEFAULTS_NAME "mysql_upgrade_defaults" |
|
|
|
#define MYSQL_UPGRADE_INFO_NAME "mysql_upgrade_info" |
|
|
|
#define MYSQL_FIX_PRIV_TABLES_NAME "mysql_fix_privilege_tables.sql" |
|
|
|
|
|
|
|
#define MY_PARENT (1 << 0) |
|
|
|
#define MY_ISDIR (1 << 1) |
|
|
|
#define MY_SEARCH_SELF (1 << 2) |
|
|
|
|
|
|
|
#ifdef __WIN__ |
|
|
|
const char *mysqlcheck_name= "mysqlcheck.exe"; |
|
|
|
const char *mysql_name= "mysql.exe"; |
|
|
|
const char *mysqld_name= "mysqld.exe"; |
|
|
|
#else |
|
|
|
const char *mysqlcheck_name= "mysqlcheck"; |
|
|
|
const char *mysql_name= "mysql"; |
|
|
|
const char *mysqld_name= "mysqld"; |
|
|
|
#endif /*__WIN__*/ |
|
|
|
|
|
|
|
static my_bool opt_force= 0, opt_verbose= 0, tty_password= 0; |
|
|
|
extern TYPELIB sql_protocol_typelib; |
|
|
|
|
|
|
|
static my_bool opt_force= 0, opt_verbose= 0, opt_compress= 0; |
|
|
|
static char *user= (char*) "root", *basedir= 0, *datadir= 0, *opt_password= 0; |
|
|
|
static my_bool upgrade_defaults_created= 0; |
|
|
|
static my_string opt_mysql_port, opt_mysql_unix_port= 0; |
|
|
|
static char *default_dbug_option= (char*) "d:t:O,/tmp/comp_err.trace"; |
|
|
|
static my_bool info_flag= 0; |
|
|
|
static char *current_host= 0; |
|
|
|
static char *opt_default_charset= 0, *opt_charsets_dir= 0; |
|
|
|
#ifdef HAVE_SMEM |
|
|
|
static char *shared_memory_base_name= 0; |
|
|
|
#endif |
|
|
|
static char *opt_protocol= 0; |
|
|
|
static my_string opt_mysql_port= 0, opt_mysql_unix_port= 0; |
|
|
|
#ifndef DBUG_OFF |
|
|
|
static char *default_dbug_option= (char*) "d:t:O,/tmp/mysql_upgrade.trace"; |
|
|
|
#endif |
|
|
|
static my_bool info_flag= 0, tty_password= 0; |
|
|
|
|
|
|
|
static struct my_option my_long_options[]= |
|
|
|
{ |
|
|
|
@ -50,27 +71,51 @@ static struct my_option my_long_options[]= |
|
|
|
#endif |
|
|
|
{"debug-info", 'T', "Print some debug info at exit.", (gptr *) & info_flag, |
|
|
|
(gptr *) & info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
|
|
|
{"force", 'f', "Continue even if we get an sql-error.", |
|
|
|
{"default-character-set", OPT_DEFAULT_CHARSET, |
|
|
|
"Set the default character set.", (gptr*) &opt_default_charset, |
|
|
|
(gptr*) &opt_default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|
|
|
{"force", 'f', "Force execution of mysqlcheck even if mysql_upgrade " |
|
|
|
"has already been executed for the current version of MySQL.", |
|
|
|
(gptr*) &opt_force, (gptr*) &opt_force, 0, GET_BOOL, NO_ARG, 0, 0, |
|
|
|
0, 0, 0, 0}, |
|
|
|
{"character-sets-dir", OPT_CHARSETS_DIR, |
|
|
|
"Directory where character sets are.", (gptr*) &opt_charsets_dir, |
|
|
|
(gptr*) &opt_charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|
|
|
{"compress", OPT_COMPRESS, "Use compression in server/client protocol.", |
|
|
|
(gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, |
|
|
|
0, 0, 0}, |
|
|
|
{"host",'h', "Connect to host.", (gptr*) ¤t_host, |
|
|
|
(gptr*) ¤t_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|
|
|
{"password", 'p', |
|
|
|
"Password to use when connecting to server. If password is not given it's solicited on the tty.", |
|
|
|
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, |
|
|
|
"Password to use when connecting to server. If password is not given" |
|
|
|
" it's solicited on the tty.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, |
|
|
|
#ifdef __WIN__ |
|
|
|
{"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, |
|
|
|
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
|
|
|
#endif |
|
|
|
{"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port, |
|
|
|
(gptr*) &opt_mysql_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, |
|
|
|
0}, |
|
|
|
(gptr*) &opt_mysql_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|
|
|
{"protocol", OPT_MYSQL_PROTOCOL, |
|
|
|
"The protocol of connection (tcp,socket,pipe,memory).", |
|
|
|
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|
|
|
#ifdef HAVE_SMEM |
|
|
|
{"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME, |
|
|
|
"Base name of shared memory.", (gptr*) &shared_memory_base_name, |
|
|
|
(gptr*) &shared_memory_base_name, 0, |
|
|
|
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|
|
|
#endif |
|
|
|
{"socket", 'S', "Socket file to use for connection.", |
|
|
|
(gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR, |
|
|
|
REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|
|
|
(gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, |
|
|
|
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|
|
|
{"user", 'u', "User for login if not current user.", (gptr*) &user, |
|
|
|
(gptr*) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|
|
|
{"verbose", 'v', "Display more output about the process", (gptr*) &opt_verbose, |
|
|
|
(gptr *) &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
|
|
|
#include <sslopt-longopts.h> |
|
|
|
{"verbose", 'v', "Display more output about the process", |
|
|
|
(gptr*) &opt_verbose, (gptr*) &opt_verbose, 0, |
|
|
|
GET_BOOL, 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 const char *load_default_groups[]= |
|
|
|
{ |
|
|
|
"mysql_upgrade", 0 |
|
|
|
@ -78,6 +123,81 @@ static const char *load_default_groups[]= |
|
|
|
|
|
|
|
#include <help_end.h> |
|
|
|
|
|
|
|
static LIST *extra_defaults= NULL; |
|
|
|
|
|
|
|
typedef struct _extra_default |
|
|
|
{ |
|
|
|
int id; |
|
|
|
const char *name; |
|
|
|
int n_len; |
|
|
|
const char *value; |
|
|
|
int v_len; |
|
|
|
} extra_default_t; |
|
|
|
|
|
|
|
static inline |
|
|
|
void set_extra_default(int id, const struct my_option *opt) |
|
|
|
{ |
|
|
|
switch (id) { |
|
|
|
case 'b': case 'd': /* these are ours */ |
|
|
|
case 'f': /* --force is ours */ |
|
|
|
case 'u': /* --user passed on cmdline */ |
|
|
|
case 'T': /* --debug-info is not accepted by mysqlcheck */ |
|
|
|
/* so, do nothing */ |
|
|
|
break; |
|
|
|
default: |
|
|
|
{ |
|
|
|
LIST *l; |
|
|
|
extra_default_t *d; |
|
|
|
|
|
|
|
/* |
|
|
|
Remove any earlier duplicates: they can |
|
|
|
refer to invalid memory addresses (stale pointers) |
|
|
|
*/ |
|
|
|
l= extra_defaults; |
|
|
|
while (l) |
|
|
|
{ |
|
|
|
LIST *n= l->next; |
|
|
|
|
|
|
|
d= l->data; |
|
|
|
if (d->id == id) |
|
|
|
{ |
|
|
|
extra_defaults= list_delete(extra_defaults, l); |
|
|
|
my_free((gptr)l, MYF(0)); |
|
|
|
my_free((gptr)d, MYF(0)); |
|
|
|
} |
|
|
|
l= n; |
|
|
|
} |
|
|
|
|
|
|
|
d= (extra_default_t *)my_malloc(sizeof(extra_default_t), |
|
|
|
MYF(MY_FAE|MY_ZEROFILL)); |
|
|
|
d->id= id; |
|
|
|
d->name= opt->name; |
|
|
|
d->n_len= strlen(opt->name); |
|
|
|
if (opt->arg_type != NO_ARG) |
|
|
|
switch (opt->var_type & GET_TYPE_MASK) { |
|
|
|
case GET_BOOL: |
|
|
|
if (*((int *)opt->value)) |
|
|
|
{ |
|
|
|
d->value= "true"; |
|
|
|
d->v_len= 4; |
|
|
|
} |
|
|
|
break; |
|
|
|
case GET_STR: |
|
|
|
case GET_STR_ALLOC: |
|
|
|
d->value= *opt->value; |
|
|
|
d->v_len= strlen(d->value); |
|
|
|
break; |
|
|
|
default: |
|
|
|
my_printf_error(0, "Error: internal error at %s:%d", MYF(0), |
|
|
|
__FILE__, __LINE__); |
|
|
|
exit(1); |
|
|
|
} |
|
|
|
list_push(extra_defaults, d); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static my_bool |
|
|
|
get_one_option(int optid, const struct my_option *opt __attribute__ ((unused)), |
|
|
|
char *argument) |
|
|
|
@ -85,16 +205,13 @@ get_one_option(int optid, const struct my_option *opt __attribute__ ((unused)), |
|
|
|
switch (optid) { |
|
|
|
case '?': |
|
|
|
puts |
|
|
|
("MySQL utility script to upgrade database to the current server version"); |
|
|
|
("MySQL utility to upgrade database to the current server version"); |
|
|
|
puts(""); |
|
|
|
my_print_help(my_long_options); |
|
|
|
exit(0); |
|
|
|
case '#': |
|
|
|
DBUG_PUSH(argument ? argument : default_dbug_option); |
|
|
|
break; |
|
|
|
case 'f': |
|
|
|
opt_force= TRUE; |
|
|
|
break; |
|
|
|
case 'p': |
|
|
|
tty_password= 1; |
|
|
|
if (argument) |
|
|
|
@ -109,315 +226,416 @@ get_one_option(int optid, const struct my_option *opt __attribute__ ((unused)), |
|
|
|
tty_password= 0; |
|
|
|
} |
|
|
|
break; |
|
|
|
#ifdef __WIN__ |
|
|
|
case 'W': |
|
|
|
my_free(opt_protocol, MYF(MY_ALLOW_ZERO_PTR)); |
|
|
|
opt_protocol= my_strdup("pipe", MYF(MY_FAE)); |
|
|
|
break; |
|
|
|
#endif |
|
|
|
case OPT_MYSQL_PROTOCOL: |
|
|
|
if (find_type(argument, &sql_protocol_typelib, 0) > 0) |
|
|
|
{ |
|
|
|
my_free(opt_protocol, MYF(MY_ALLOW_ZERO_PTR)); |
|
|
|
opt_protocol= my_strdup(argument, MYF(MY_FAE)); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
fprintf(stderr, "Unknown option to protocol: %s\n", argument); |
|
|
|
exit(1); |
|
|
|
} |
|
|
|
break; |
|
|
|
#include <sslopt-case.h> |
|
|
|
default:; |
|
|
|
}; |
|
|
|
} |
|
|
|
set_extra_default(opt->id, opt); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* buffer should be not smaller than FN_REFLEN */ |
|
|
|
static my_bool test_file_exists_res(const char *dir, const char *fname, |
|
|
|
char *buffer, char **buf_end) |
|
|
|
{ |
|
|
|
MY_STAT stat_info; |
|
|
|
|
|
|
|
*buf_end= strxnmov(buffer, FN_REFLEN-1, dir, "/", fname, NullS); |
|
|
|
unpack_filename(buffer, buffer); |
|
|
|
return my_stat(buffer, &stat_info, MYF(0)) != 0; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static my_bool test_file_exists(const char *dir, const char *fname) |
|
|
|
{ |
|
|
|
char path[FN_REFLEN]; |
|
|
|
char *path_end; |
|
|
|
return test_file_exists_res(dir, fname, path, &path_end); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int create_check_file(const char *path) |
|
|
|
{ |
|
|
|
File check_file= my_open(path, O_CREAT | O_WRONLY, MYF(MY_FAE | MY_WME)); |
|
|
|
int error; |
|
|
|
|
|
|
|
if (check_file < 0) |
|
|
|
return 1; |
|
|
|
|
|
|
|
error= my_write(check_file, |
|
|
|
MYSQL_SERVER_VERSION, strlen(MYSQL_SERVER_VERSION), |
|
|
|
int ret; |
|
|
|
File fd; |
|
|
|
|
|
|
|
fd= my_open(path, O_CREAT | O_WRONLY, MYF(MY_FAE | MY_WME)); |
|
|
|
if (fd < 0) { |
|
|
|
ret= 1; |
|
|
|
goto error; |
|
|
|
} |
|
|
|
ret= my_write(fd, MYSQL_SERVER_VERSION, |
|
|
|
sizeof(MYSQL_SERVER_VERSION) - 1, |
|
|
|
MYF(MY_WME | MY_FNABP)); |
|
|
|
error= my_close(check_file, MYF(MY_FAE | MY_WME)) || error; |
|
|
|
return error; |
|
|
|
ret|= my_close(fd, MYF(MY_FAE | MY_WME)); |
|
|
|
error: |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int create_defaults_file(const char *path, const char *our_defaults_path) |
|
|
|
static int create_defaults_file(const char *path, const char *forced_path) |
|
|
|
{ |
|
|
|
uint b_read; |
|
|
|
File our_defaults_file, defaults_file; |
|
|
|
char buffer[512]; |
|
|
|
char *buffer_end; |
|
|
|
int failed_to_open_count= 0; |
|
|
|
int error; |
|
|
|
|
|
|
|
/* check if the defaults file is needed at all */ |
|
|
|
if (!opt_password) |
|
|
|
return 0; |
|
|
|
|
|
|
|
retry_open: |
|
|
|
int ret; |
|
|
|
uint cnt; |
|
|
|
File forced_file, defaults_file; |
|
|
|
|
|
|
|
DYNAMIC_STRING buf; |
|
|
|
extra_default_t *d; |
|
|
|
|
|
|
|
my_delete(path, MYF(0)); |
|
|
|
|
|
|
|
defaults_file= my_open(path, O_BINARY | O_CREAT | O_WRONLY | O_EXCL, |
|
|
|
MYF(MY_FAE | MY_WME)); |
|
|
|
|
|
|
|
if (defaults_file < 0) |
|
|
|
{ |
|
|
|
if (failed_to_open_count == 0) |
|
|
|
{ |
|
|
|
remove(path); |
|
|
|
failed_to_open_count+= 1; |
|
|
|
goto retry_open; |
|
|
|
} |
|
|
|
else |
|
|
|
return 1; |
|
|
|
ret= 1; |
|
|
|
goto out; |
|
|
|
} |
|
|
|
|
|
|
|
if (init_dynamic_string(&buf, NULL, my_getpagesize(), FN_REFLEN)) |
|
|
|
{ |
|
|
|
ret= 1; |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
upgrade_defaults_created= 1; |
|
|
|
if (our_defaults_path) |
|
|
|
if (forced_path) |
|
|
|
{ |
|
|
|
our_defaults_file= my_open(our_defaults_path, O_RDONLY, |
|
|
|
MYF(MY_FAE | MY_WME)); |
|
|
|
if (our_defaults_file < 0) |
|
|
|
return 1; |
|
|
|
forced_file= my_open(forced_path, O_RDONLY, MYF(MY_FAE | MY_WME)); |
|
|
|
if (forced_file < 0) |
|
|
|
{ |
|
|
|
ret= 1; |
|
|
|
goto error; |
|
|
|
} |
|
|
|
do |
|
|
|
{ |
|
|
|
if (((b_read= my_read(our_defaults_file, buffer, |
|
|
|
sizeof(buffer), MYF(MY_WME))) == MY_FILE_ERROR) || |
|
|
|
my_write(defaults_file, buffer, b_read, MYF(MY_FNABP | MY_WME))) |
|
|
|
cnt= my_read(forced_file, buf.str, buf.max_length, MYF(MY_WME)); |
|
|
|
if ((cnt == MY_FILE_ERROR) |
|
|
|
|| my_write(defaults_file, buf.str, cnt, MYF(MY_FNABP | MY_WME))) |
|
|
|
{ |
|
|
|
error= 1; |
|
|
|
goto close_return; |
|
|
|
ret= 1; |
|
|
|
my_close(forced_file, MYF(0)); |
|
|
|
goto error; |
|
|
|
} |
|
|
|
} while (b_read == sizeof(buffer)); |
|
|
|
} while (cnt == buf.max_length); |
|
|
|
my_close(forced_file, MYF(0)); |
|
|
|
} |
|
|
|
buffer_end= strnmov(buffer, "\n[client]", sizeof(buffer)); |
|
|
|
if (opt_password) |
|
|
|
buffer_end= strxnmov(buffer_end, sizeof(buffer), |
|
|
|
"\npassword=", opt_password, NullS); |
|
|
|
error= my_write(defaults_file, buffer, (int) (buffer_end - buffer), |
|
|
|
MYF(MY_WME | MY_FNABP)); |
|
|
|
close_return: |
|
|
|
return my_close(defaults_file, MYF(MY_WME)) || error; |
|
|
|
|
|
|
|
dynstr_set(&buf, "\n[client]"); |
|
|
|
while (extra_defaults) |
|
|
|
{ |
|
|
|
int len; |
|
|
|
|
|
|
|
d= extra_defaults->data; |
|
|
|
len= d->n_len + d->v_len + 1; |
|
|
|
if (buf.length + len >= buf.max_length) /* to avoid realloc() */ |
|
|
|
{ |
|
|
|
if (my_write(defaults_file, buf.str, buf.length, MYF(MY_FNABP | MY_WME))) |
|
|
|
{ |
|
|
|
ret= 1; |
|
|
|
goto error; |
|
|
|
} |
|
|
|
dynstr_set(&buf, NULL); |
|
|
|
} |
|
|
|
if (dynstr_append_mem(&buf, "\n", 1) |
|
|
|
|| dynstr_append_mem(&buf, d->name, d->n_len) |
|
|
|
|| (d->v_len && (dynstr_append_mem(&buf, "=", 1) |
|
|
|
|| dynstr_append_mem(&buf, d->value, d->v_len)))) |
|
|
|
{ |
|
|
|
ret= 1; |
|
|
|
goto error; |
|
|
|
} |
|
|
|
my_delete((gptr)d, MYF(0)); |
|
|
|
list_pop(extra_defaults); /* pop off the head */ |
|
|
|
} |
|
|
|
if (my_write(defaults_file, buf.str, buf.length, MYF(MY_FNABP | MY_WME))) |
|
|
|
{ |
|
|
|
ret= 1; |
|
|
|
goto error; |
|
|
|
} |
|
|
|
/* everything's all right */ |
|
|
|
ret= 0; |
|
|
|
error: |
|
|
|
dynstr_free(&buf); |
|
|
|
|
|
|
|
if (defaults_file >= 0) |
|
|
|
ret|= my_close(defaults_file, MYF(MY_WME)); |
|
|
|
|
|
|
|
if (ret) |
|
|
|
my_delete(path, MYF(0)); |
|
|
|
|
|
|
|
out: |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Compare filenames */ |
|
|
|
static int comp_names(struct fileinfo *a, struct fileinfo *b) |
|
|
|
{ |
|
|
|
return (strcmp(a->name,b->name)); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int |
|
|
|
find_file(const char *name, const char *root, uint flags, char *result, size_t len, ...) |
|
|
|
{ |
|
|
|
int ret; |
|
|
|
va_list va; |
|
|
|
FILEINFO key= { name }; |
|
|
|
const char *subdir; |
|
|
|
char *cp; |
|
|
|
|
|
|
|
DBUG_ASSERT(root != NULL); |
|
|
|
|
|
|
|
cp= strmake(result, root, len); |
|
|
|
if (cp[-1] != FN_LIBCHAR) |
|
|
|
*cp= FN_LIBCHAR; |
|
|
|
|
|
|
|
ret= 1; |
|
|
|
va_start(va, len); |
|
|
|
subdir= (!(flags & MY_SEARCH_SELF)) ? va_arg(va, char *) : ""; |
|
|
|
while (ret && subdir) |
|
|
|
{ |
|
|
|
MY_DIR *dir; |
|
|
|
FILEINFO *match; |
|
|
|
uint i; |
|
|
|
char *cp1; |
|
|
|
|
|
|
|
cp1= strnmov(cp + 1, subdir, len - (cp - result) - 1); |
|
|
|
|
|
|
|
dir= my_dir(result, (flags & MY_ISDIR) ? MY_WANT_STAT : MYF(0)); |
|
|
|
if (dir) |
|
|
|
{ |
|
|
|
match= bsearch(&key, dir->dir_entry, dir->number_off_files, |
|
|
|
sizeof(FILEINFO), (qsort_cmp)comp_names); |
|
|
|
if (match) |
|
|
|
{ |
|
|
|
if (!(flags & MY_PARENT)) |
|
|
|
{ |
|
|
|
if (cp1[-1] != FN_LIBCHAR) |
|
|
|
*cp1++= FN_LIBCHAR; |
|
|
|
strnmov(cp1, name, len - (cp1 - result)); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (cp1[-1] == FN_LIBCHAR) |
|
|
|
--cp1; |
|
|
|
while (*--cp1 == FN_LIBCHAR) |
|
|
|
{} |
|
|
|
*++cp1= FN_LIBCHAR; |
|
|
|
*++cp1= '\0'; |
|
|
|
} |
|
|
|
if (flags & MY_ISDIR) |
|
|
|
ret= !MY_S_ISDIR(match->mystat->st_mode); |
|
|
|
else |
|
|
|
ret= 0; |
|
|
|
} |
|
|
|
my_dirend(dir); |
|
|
|
} |
|
|
|
subdir= va_arg(va, char *); |
|
|
|
} |
|
|
|
va_end(va); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, char **argv) |
|
|
|
{ |
|
|
|
char bindir[FN_REFLEN]; |
|
|
|
char *bindir_end, *buf_end; |
|
|
|
char datadir_buf[FN_REFLEN]; |
|
|
|
char mysqlcheck_line[FN_REFLEN], *mysqlcheck_end; |
|
|
|
char check_file_name[FN_REFLEN]; |
|
|
|
int check_file; |
|
|
|
char fix_priv_tables_cmd[FN_REFLEN], *fix_cmd_end; |
|
|
|
char script_line[FN_REFLEN]; |
|
|
|
int error; |
|
|
|
int ret; |
|
|
|
|
|
|
|
char *forced_defaults_file; |
|
|
|
char *forced_extra_defaults; |
|
|
|
char *defaults_group_suffix; |
|
|
|
char upgrade_defaults_path[FN_REFLEN], *defaults_to_use= 0; |
|
|
|
char port_socket[100], *port_socket_end; |
|
|
|
const char *script_line; |
|
|
|
char *upgrade_defaults_path; |
|
|
|
char *defaults_to_use= NULL; |
|
|
|
int upgrade_defaults_created= 0; |
|
|
|
|
|
|
|
char path[FN_REFLEN]; |
|
|
|
DYNAMIC_STRING cmdline; |
|
|
|
|
|
|
|
MY_INIT(argv[0]); |
|
|
|
#ifdef __NETWARE__ |
|
|
|
setscreenmode(SCR_AUTOCLOSE_ON_EXIT); |
|
|
|
#endif |
|
|
|
|
|
|
|
/* Check if we are forced to use specific defaults */ |
|
|
|
get_defaults_options(argc, argv, |
|
|
|
&forced_defaults_file, &forced_extra_defaults, |
|
|
|
&defaults_group_suffix); |
|
|
|
|
|
|
|
load_defaults("my", load_default_groups, &argc, &argv); |
|
|
|
|
|
|
|
if ((error= handle_options(&argc, &argv, my_long_options, get_one_option))) |
|
|
|
exit(error); |
|
|
|
|
|
|
|
if (handle_options(&argc, &argv, my_long_options, get_one_option)) |
|
|
|
{ |
|
|
|
ret= 1; |
|
|
|
goto error; |
|
|
|
} |
|
|
|
if (tty_password) |
|
|
|
opt_password= get_tty_password(NullS); |
|
|
|
|
|
|
|
/* Check if we want to force the use a specific default file */ |
|
|
|
get_defaults_options(argc, argv, |
|
|
|
&forced_defaults_file, &forced_extra_defaults, |
|
|
|
&defaults_group_suffix); |
|
|
|
|
|
|
|
port_socket_end= port_socket; |
|
|
|
if (opt_mysql_port) |
|
|
|
port_socket_end= strxnmov(port_socket, sizeof(port_socket) - 1, " --port=", |
|
|
|
opt_mysql_port, NullS); |
|
|
|
if (opt_mysql_unix_port) |
|
|
|
port_socket_end= strxnmov(port_socket_end, |
|
|
|
sizeof(port_socket) - |
|
|
|
(int)(port_socket_end - port_socket) - 1, |
|
|
|
" --socket=", opt_mysql_unix_port, NullS); |
|
|
|
*port_socket_end= 0; |
|
|
|
|
|
|
|
if (basedir) |
|
|
|
if (init_dynamic_string(&cmdline, NULL, 2 * FN_REFLEN + 128, FN_REFLEN)) |
|
|
|
{ |
|
|
|
bindir_end= strmake(bindir, basedir, sizeof(bindir)-1); |
|
|
|
ret= 1; |
|
|
|
goto error; |
|
|
|
} |
|
|
|
else |
|
|
|
if (!basedir) |
|
|
|
{ |
|
|
|
if (test_file_exists("./share/mysql/english", "errmsg.sys") |
|
|
|
&& (test_file_exists("./bin", "mysqld") || |
|
|
|
test_file_exists("./libexec", "mysqld"))) |
|
|
|
{ |
|
|
|
my_getwd(bindir, sizeof(bindir), MYF(0)); |
|
|
|
bindir_end= bindir + strlen(bindir); |
|
|
|
} |
|
|
|
else |
|
|
|
my_getwd(path, sizeof(path), MYF(0)); |
|
|
|
basedir= my_strdup(path, MYF(0)); |
|
|
|
if (find_file("errmsg.sys", basedir, MYF(0), path, sizeof(path), |
|
|
|
"share/mysql/english", NullS) |
|
|
|
|| find_file(mysqld_name, basedir, MYF(0), path, sizeof(path), |
|
|
|
"bin", "libexec", NullS)) |
|
|
|
{ |
|
|
|
bindir_end= strmake(bindir, DEFAULT_MYSQL_HOME, sizeof(bindir)-1); |
|
|
|
my_strdup((gptr)basedir, MYF(0)); |
|
|
|
basedir= (char *)DEFAULT_MYSQL_HOME; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!datadir) |
|
|
|
{ |
|
|
|
datadir= datadir_buf; |
|
|
|
if (test_file_exists(bindir, "data/mysql")) |
|
|
|
{ |
|
|
|
*strxnmov(datadir_buf, sizeof(datadir_buf)-1, bindir, "/data", NullS)= 0; |
|
|
|
} |
|
|
|
else if (test_file_exists(bindir, "var/mysql")) |
|
|
|
{ |
|
|
|
*strxnmov(datadir_buf, sizeof(datadir_buf)-1, bindir, "/var", NullS)= 0; |
|
|
|
} |
|
|
|
if (!find_file("mysql", basedir, MYF(MY_ISDIR|MY_PARENT), |
|
|
|
path, sizeof(path), |
|
|
|
"data", "var", NullS)) |
|
|
|
datadir= my_strdup(path, MYF(0)); |
|
|
|
else |
|
|
|
datadir= (char*) DATADIR; |
|
|
|
datadir= (char *)DATADIR; |
|
|
|
} |
|
|
|
|
|
|
|
strmake(bindir_end, "/bin", sizeof(bindir) - (int) (bindir_end - bindir)-1); |
|
|
|
|
|
|
|
if (!test_file_exists_res |
|
|
|
(bindir, mysqlcheck_name, mysqlcheck_line, &mysqlcheck_end)) |
|
|
|
if (find_file("user.frm", datadir, MYF(0), path, sizeof(path), |
|
|
|
"mysql", NullS)) |
|
|
|
{ |
|
|
|
printf("Can't find program '%s'\n", mysqlcheck_line); |
|
|
|
puts("Please restart with --basedir=mysql-install-directory"); |
|
|
|
exit(1); |
|
|
|
ret= 1; |
|
|
|
puts("Can't find data directory. Please restart with" |
|
|
|
" --datadir=path-to-writable-data-dir"); |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
if (!test_file_exists(datadir, "mysql/user.frm")) |
|
|
|
/* |
|
|
|
Create the modified defaults file to be used by mysqlcheck |
|
|
|
and mysql tools |
|
|
|
*/ |
|
|
|
fn_format(path, UPGRADE_DEFAULTS_NAME, datadir, "", MYF(0)); |
|
|
|
upgrade_defaults_path= my_strdup(path, MYF(0)); |
|
|
|
|
|
|
|
if (extra_defaults) |
|
|
|
{ |
|
|
|
puts |
|
|
|
("Can't find data directory. Please restart with --datadir=path-to-data-dir"); |
|
|
|
exit(1); |
|
|
|
} |
|
|
|
|
|
|
|
/* create the modified defaults file to be used by mysqlcheck */ |
|
|
|
/* and mysql tools */ |
|
|
|
*strxnmov(upgrade_defaults_path, sizeof(upgrade_defaults_path)-1, |
|
|
|
datadir, "/upgrade_defaults", NullS)= 0; |
|
|
|
unpack_filename(upgrade_defaults_path, upgrade_defaults_path); |
|
|
|
if ((error= |
|
|
|
create_defaults_file(upgrade_defaults_path, forced_extra_defaults))) |
|
|
|
goto err_exit; |
|
|
|
|
|
|
|
defaults_to_use= upgrade_defaults_created ? |
|
|
|
upgrade_defaults_path : forced_extra_defaults; |
|
|
|
ret= create_defaults_file(upgrade_defaults_path, forced_extra_defaults); |
|
|
|
if (ret) |
|
|
|
goto error; |
|
|
|
|
|
|
|
defaults_to_use= upgrade_defaults_path; |
|
|
|
upgrade_defaults_created= 1; |
|
|
|
} |
|
|
|
else |
|
|
|
defaults_to_use= forced_extra_defaults; |
|
|
|
|
|
|
|
if (test_file_exists_res(datadir, "mysql_upgrade_info", check_file_name, |
|
|
|
&buf_end) && !opt_force) |
|
|
|
if (!find_file(MYSQL_UPGRADE_INFO_NAME, datadir, MY_SEARCH_SELF, |
|
|
|
path, sizeof(path), NULL, NullS) |
|
|
|
&& !opt_force) |
|
|
|
{ |
|
|
|
char chf_buffer[50]; |
|
|
|
int b_read; |
|
|
|
check_file= my_open(check_file_name, O_RDONLY, MYF(0)); |
|
|
|
b_read= my_read(check_file, chf_buffer, sizeof(chf_buffer)-1, MYF(0)); |
|
|
|
chf_buffer[b_read]= 0; |
|
|
|
my_close(check_file, MYF(0)); |
|
|
|
if (!strcmp(chf_buffer, MYSQL_SERVER_VERSION)) |
|
|
|
char buf[sizeof(MYSQL_SERVER_VERSION)]; |
|
|
|
int fd, cnt; |
|
|
|
|
|
|
|
fd= my_open(path, O_RDONLY, MYF(0)); |
|
|
|
cnt= my_read(fd, buf, sizeof(buf) - 1, MYF(0)); |
|
|
|
my_close(fd, MYF(0)); |
|
|
|
buf[cnt]= 0; |
|
|
|
if (!strcmp(buf, MYSQL_SERVER_VERSION)) |
|
|
|
{ |
|
|
|
if (opt_verbose) |
|
|
|
puts("mysql_upgrade already done for this version"); |
|
|
|
puts("mysql_upgrade has already been done for this version"); |
|
|
|
goto fix_priv_tables; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (find_file(mysqlcheck_name, basedir, MYF(0), path, sizeof(path), |
|
|
|
"bin", NullS)) |
|
|
|
{ |
|
|
|
ret= 1; |
|
|
|
printf("Can't find program '%s'\n", mysqlcheck_name); |
|
|
|
puts("Please restart with --basedir=mysql-install-directory"); |
|
|
|
goto error; |
|
|
|
} |
|
|
|
else |
|
|
|
dynstr_set(&cmdline, path); |
|
|
|
|
|
|
|
if (defaults_to_use) |
|
|
|
{ |
|
|
|
mysqlcheck_end= strxnmov(mysqlcheck_end, |
|
|
|
sizeof(mysqlcheck_line) - (int) (mysqlcheck_end - |
|
|
|
mysqlcheck_line), |
|
|
|
" --defaults-extra-file=", defaults_to_use,NullS); |
|
|
|
dynstr_append(&cmdline, " --defaults-extra-file="); |
|
|
|
dynstr_append(&cmdline, defaults_to_use); |
|
|
|
} |
|
|
|
|
|
|
|
mysqlcheck_end= strxnmov(mysqlcheck_end, |
|
|
|
sizeof(mysqlcheck_line) - |
|
|
|
(int) (mysqlcheck_end - mysqlcheck_line - 1), |
|
|
|
" --check-upgrade --all-databases --auto-repair --user=", |
|
|
|
user, port_socket, NullS); |
|
|
|
*mysqlcheck_end= 0; |
|
|
|
|
|
|
|
dynstr_append(&cmdline, " --check-upgrade --all-databases" |
|
|
|
" --auto-repair --user="); |
|
|
|
dynstr_append(&cmdline, user); |
|
|
|
|
|
|
|
if (opt_verbose) |
|
|
|
printf("Running %s\n", mysqlcheck_line); |
|
|
|
if ((error= system(mysqlcheck_line))) |
|
|
|
printf("Running %s\n", cmdline.str); |
|
|
|
|
|
|
|
ret= system(cmdline.str); |
|
|
|
if (ret) |
|
|
|
{ |
|
|
|
printf("Error executing '%s'\n", mysqlcheck_line); |
|
|
|
goto err_exit; |
|
|
|
printf("Error executing '%s'\n", cmdline.str); |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
if ((error= create_check_file(check_file_name))) |
|
|
|
goto err_exit; |
|
|
|
fn_format(path, MYSQL_UPGRADE_INFO_NAME, datadir, "", MYF(0)); |
|
|
|
ret= create_check_file(path); |
|
|
|
if (ret) |
|
|
|
goto error; |
|
|
|
|
|
|
|
fix_priv_tables: |
|
|
|
if (!test_file_exists_res(bindir, mysql_name, |
|
|
|
fix_priv_tables_cmd, &fix_cmd_end)) |
|
|
|
if (find_file(mysql_name, basedir, MYF(0), path, sizeof(path), |
|
|
|
"bin", NullS)) |
|
|
|
{ |
|
|
|
puts("Could not find MySQL command-line client (mysql)."); |
|
|
|
puts |
|
|
|
("Please use --basedir to specify the directory where MySQL is installed."); |
|
|
|
error= 1; |
|
|
|
goto err_exit; |
|
|
|
ret= 1; |
|
|
|
puts("Could not find MySQL command-line client (mysql).\n" |
|
|
|
"Please use --basedir to specify the directory" |
|
|
|
" where MySQL is installed."); |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
if (!test_file_exists_res(basedir, |
|
|
|
"support_files/mysql_fix_privilege_tables.sql", |
|
|
|
script_line, &buf_end) |
|
|
|
&& !test_file_exists_res(basedir, "share/mysql_fix_privilege_tables.sql", |
|
|
|
script_line, &buf_end) |
|
|
|
&& !test_file_exists_res(basedir, |
|
|
|
"share/mysql/mysql_fix_privilege_tables.sql", |
|
|
|
script_line, &buf_end) |
|
|
|
&& !test_file_exists_res(basedir, |
|
|
|
"scripts/mysql_fix_privilege_tables.sql", |
|
|
|
script_line, &buf_end) |
|
|
|
&& !test_file_exists_res("/usr/local/mysql/share/mysql", |
|
|
|
"mysql_fix_privilege_tables.sql", script_line, |
|
|
|
&buf_end)) |
|
|
|
else |
|
|
|
dynstr_set(&cmdline, path); |
|
|
|
|
|
|
|
if (find_file(MYSQL_FIX_PRIV_TABLES_NAME, basedir, MYF(0), |
|
|
|
path, sizeof(path), |
|
|
|
"support_files", "share/mysql", "scripts", |
|
|
|
NullS) |
|
|
|
&& find_file(MYSQL_FIX_PRIV_TABLES_NAME, "/usr/local/mysql", MYF(0), |
|
|
|
path, sizeof(path), |
|
|
|
"share/mysql", NullS)) |
|
|
|
{ |
|
|
|
puts("Could not find file mysql_fix_privilege_tables.sql"); |
|
|
|
puts |
|
|
|
("Please use --basedir to specify the directory where MySQL is installed"); |
|
|
|
error= 1; |
|
|
|
goto err_exit; |
|
|
|
ret= 1; |
|
|
|
puts("Could not find file " MYSQL_FIX_PRIV_TABLES_NAME "\n" |
|
|
|
"Please use --basedir to specify the directory" |
|
|
|
" where MySQL is installed"); |
|
|
|
goto error; |
|
|
|
} |
|
|
|
else |
|
|
|
script_line= my_strdup(path, MYF(0)); |
|
|
|
|
|
|
|
if (defaults_to_use) |
|
|
|
{ |
|
|
|
fix_cmd_end= strxnmov(fix_cmd_end, |
|
|
|
sizeof(fix_priv_tables_cmd) - |
|
|
|
(int) (fix_cmd_end - fix_priv_tables_cmd - 1), |
|
|
|
" --defaults-extra-file=", defaults_to_use, NullS); |
|
|
|
dynstr_append(&cmdline, " --defaults-extra-file="); |
|
|
|
dynstr_append(&cmdline, defaults_to_use); |
|
|
|
} |
|
|
|
fix_cmd_end= strxnmov(fix_cmd_end, |
|
|
|
sizeof(fix_priv_tables_cmd) - (int) (fix_cmd_end - |
|
|
|
fix_priv_tables_cmd), |
|
|
|
" --user=", user, port_socket, " mysql < ", script_line, NullS); |
|
|
|
*fix_cmd_end= 0; |
|
|
|
dynstr_append(&cmdline, " --force --no-auto-rehash --batch --user="); |
|
|
|
dynstr_append(&cmdline, user); |
|
|
|
dynstr_append(&cmdline, " mysql < "); |
|
|
|
dynstr_append(&cmdline, script_line); |
|
|
|
|
|
|
|
if ((error= system(fix_priv_tables_cmd))) |
|
|
|
{ |
|
|
|
/* Problem is that the 'Duplicate column' error */ |
|
|
|
/* which is not a bug for the script makes 'mysql' return */ |
|
|
|
/* an error */ |
|
|
|
/* printf("Error executing '%s'\n", fix_priv_tables_cmd); */ |
|
|
|
} |
|
|
|
if (opt_verbose) |
|
|
|
printf("Running %s\n", cmdline.str); |
|
|
|
|
|
|
|
ret= system(cmdline.str); |
|
|
|
if (ret) |
|
|
|
printf("Error executing '%s'\n", cmdline.str); |
|
|
|
|
|
|
|
error: |
|
|
|
dynstr_free(&cmdline); |
|
|
|
|
|
|
|
err_exit: |
|
|
|
if (upgrade_defaults_created) |
|
|
|
my_delete(upgrade_defaults_path, MYF(0)); |
|
|
|
|
|
|
|
my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); |
|
|
|
return error; |
|
|
|
} /* main */ |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|