00001 /* Copyright (C) 2000 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 #include "client_priv.h" 00018 #include <my_dir.h> 00019 00020 #ifdef __WIN__ 00021 const char *mysqlcheck_name= "mysqlcheck.exe"; 00022 const char *mysql_name= "mysql.exe"; 00023 #else 00024 const char *mysqlcheck_name= "mysqlcheck"; 00025 const char *mysql_name= "mysql"; 00026 #endif /*__WIN__*/ 00027 00028 static my_bool opt_force= 0, opt_verbose= 0, tty_password= 0; 00029 static char *user= (char*) "root", *basedir= 0, *datadir= 0, *opt_password= 0; 00030 static my_bool upgrade_defaults_created= 0; 00031 static my_string opt_mysql_port, opt_mysql_unix_port= 0; 00032 static char *default_dbug_option= (char*) "d:t:O,/tmp/comp_err.trace"; 00033 static my_bool info_flag= 0; 00034 00035 static struct my_option my_long_options[]= 00036 { 00037 {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG, 00038 NO_ARG, 0, 0, 0, 0, 0, 0}, 00039 {"basedir", 'b', "Specifies the directory where MySQL is installed", 00040 (gptr*) &basedir, 00041 (gptr*) &basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00042 {"datadir", 'd', "Specifies the data directory", (gptr*) &datadir, 00043 (gptr*) &datadir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00044 #ifdef DBUG_OFF 00045 {"debug", '#', "This is a non-debug version. Catch this and exit", 00046 0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0}, 00047 #else 00048 {"debug", '#', "Output debug log", (gptr *) & default_dbug_option, 00049 (gptr *) & default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, 00050 #endif 00051 {"debug-info", 'T', "Print some debug info at exit.", (gptr *) & info_flag, 00052 (gptr *) & info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, 00053 {"force", 'f', "Continue even if we get an sql-error.", 00054 (gptr*) &opt_force, (gptr*) &opt_force, 0, GET_BOOL, NO_ARG, 0, 0, 00055 0, 0, 0, 0}, 00056 {"password", 'p', 00057 "Password to use when connecting to server. If password is not given it's solicited on the tty.", 00058 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, 00059 {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port, 00060 (gptr*) &opt_mysql_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 00061 0}, 00062 {"protocol", OPT_MYSQL_PROTOCOL, 00063 "The protocol of connection (tcp,socket,pipe,memory).", 00064 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00065 {"socket", 'S', "Socket file to use for connection.", 00066 (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR, 00067 REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00068 {"user", 'u', "User for login if not current user.", (gptr*) &user, 00069 (gptr*) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00070 {"verbose", 'v', "Display more output about the process", (gptr*) &opt_verbose, 00071 (gptr *) &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, 00072 {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} 00073 }; 00074 static const char *load_default_groups[]= 00075 { 00076 "mysql_upgrade", 0 00077 }; 00078 00079 #include <help_end.h> 00080 00081 static my_bool 00082 get_one_option(int optid, const struct my_option *opt __attribute__ ((unused)), 00083 char *argument) 00084 { 00085 switch (optid) { 00086 case '?': 00087 puts 00088 ("MySQL utility script to upgrade database to the current server version"); 00089 puts(""); 00090 my_print_help(my_long_options); 00091 exit(0); 00092 case '#': 00093 DBUG_PUSH(argument ? argument : default_dbug_option); 00094 break; 00095 case 'f': 00096 opt_force= TRUE; 00097 break; 00098 case 'p': 00099 tty_password= 1; 00100 if (argument) 00101 { 00102 char *start= argument; 00103 my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); 00104 opt_password= my_strdup(argument, MYF(MY_FAE)); 00105 while (*argument) 00106 *argument++= 'x'; /* Destroy argument */ 00107 if (*start) 00108 start[1]= 0; /* Cut length of argument */ 00109 tty_password= 0; 00110 } 00111 break; 00112 default:; 00113 }; 00114 return 0; 00115 } 00116 00117 00118 /* buffer should be not smaller than FN_REFLEN */ 00119 static my_bool test_file_exists_res(const char *dir, const char *fname, 00120 char *buffer, char **buf_end) 00121 { 00122 MY_STAT stat_info; 00123 00124 *buf_end= strxnmov(buffer, FN_REFLEN-1, dir, "/", fname, NullS); 00125 unpack_filename(buffer, buffer); 00126 return my_stat(buffer, &stat_info, MYF(0)) != 0; 00127 } 00128 00129 00130 static my_bool test_file_exists(const char *dir, const char *fname) 00131 { 00132 char path[FN_REFLEN]; 00133 char *path_end; 00134 return test_file_exists_res(dir, fname, path, &path_end); 00135 } 00136 00137 00138 static int create_check_file(const char *path) 00139 { 00140 File check_file= my_open(path, O_CREAT | O_WRONLY, MYF(MY_FAE | MY_WME)); 00141 int error; 00142 00143 if (check_file < 0) 00144 return 1; 00145 00146 error= my_write(check_file, 00147 MYSQL_SERVER_VERSION, strlen(MYSQL_SERVER_VERSION), 00148 MYF(MY_WME | MY_FNABP)); 00149 error= my_close(check_file, MYF(MY_FAE | MY_WME)) || error; 00150 return error; 00151 } 00152 00153 00154 static int create_defaults_file(const char *path, const char *our_defaults_path) 00155 { 00156 uint b_read; 00157 File our_defaults_file, defaults_file; 00158 char buffer[512]; 00159 char *buffer_end; 00160 int error; 00161 00162 /* check if the defaults file is needed at all */ 00163 if (!opt_password) 00164 return 0; 00165 00166 defaults_file= my_open(path, O_BINARY | O_CREAT | O_WRONLY, 00167 MYF(MY_FAE | MY_WME)); 00168 00169 if (defaults_file < 0) 00170 return 1; 00171 upgrade_defaults_created= 1; 00172 if (our_defaults_path) 00173 { 00174 our_defaults_file= my_open(our_defaults_path, O_RDONLY, 00175 MYF(MY_FAE | MY_WME)); 00176 if (our_defaults_file < 0) 00177 return 1; 00178 do 00179 { 00180 if (((b_read= my_read(our_defaults_file, buffer, 00181 sizeof(buffer), MYF(MY_WME))) == MY_FILE_ERROR) || 00182 my_write(defaults_file, buffer, b_read, MYF(MY_FNABP | MY_WME))) 00183 { 00184 error= 1; 00185 goto close_return; 00186 } 00187 } while (b_read == sizeof(buffer)); 00188 } 00189 buffer_end= strnmov(buffer, "\n[client]", sizeof(buffer)); 00190 if (opt_password) 00191 buffer_end= strxnmov(buffer, sizeof(buffer), 00192 "\npassword=", opt_password, NullS); 00193 error= my_write(defaults_file, buffer, (int) (buffer_end - buffer), 00194 MYF(MY_WME | MY_FNABP)); 00195 close_return: 00196 return my_close(defaults_file, MYF(MY_WME)) || error; 00197 } 00198 00199 00200 int main(int argc, char **argv) 00201 { 00202 char bindir[FN_REFLEN]; 00203 char *bindir_end, *buf_end; 00204 char datadir_buf[FN_REFLEN]; 00205 char mysqlcheck_line[FN_REFLEN], *mysqlcheck_end; 00206 char check_file_name[FN_REFLEN]; 00207 int check_file; 00208 char fix_priv_tables_cmd[FN_REFLEN], *fix_cmd_end; 00209 char script_line[FN_REFLEN]; 00210 int error; 00211 char *forced_defaults_file; 00212 char *forced_extra_defaults; 00213 char *defaults_group_suffix; 00214 char upgrade_defaults_path[FN_REFLEN], *defaults_to_use= 0; 00215 char port_socket[100], *port_socket_end; 00216 00217 MY_INIT(argv[0]); 00218 #ifdef __NETWARE__ 00219 setscreenmode(SCR_AUTOCLOSE_ON_EXIT); 00220 #endif 00221 00222 load_defaults("my", load_default_groups, &argc, &argv); 00223 00224 if ((error= handle_options(&argc, &argv, my_long_options, get_one_option))) 00225 exit(error); 00226 00227 if (tty_password) 00228 opt_password= get_tty_password(NullS); 00229 00230 /* Check if we want to force the use a specific default file */ 00231 get_defaults_options(argc, argv, 00232 &forced_defaults_file, &forced_extra_defaults, 00233 &defaults_group_suffix); 00234 00235 port_socket_end= port_socket; 00236 if (opt_mysql_port) 00237 port_socket_end= strxnmov(port_socket, sizeof(port_socket) - 1, " --port=", 00238 opt_mysql_port, NullS); 00239 if (opt_mysql_unix_port) 00240 port_socket_end= strxnmov(port_socket_end, 00241 sizeof(port_socket) - 00242 (int)(port_socket_end - port_socket) - 1, 00243 " --socket=", opt_mysql_unix_port, NullS); 00244 *port_socket_end= 0; 00245 00246 if (basedir) 00247 { 00248 bindir_end= strmake(bindir, basedir, sizeof(bindir)-1); 00249 } 00250 else 00251 { 00252 if (test_file_exists("./share/mysql/english", "errmsg.sys") 00253 && (test_file_exists("./bin", "mysqld") || 00254 test_file_exists("./libexec", "mysqld"))) 00255 { 00256 my_getwd(bindir, sizeof(bindir), MYF(0)); 00257 bindir_end= bindir + strlen(bindir); 00258 } 00259 else 00260 { 00261 bindir_end= strmake(bindir, DEFAULT_MYSQL_HOME, sizeof(bindir)-1); 00262 } 00263 } 00264 00265 if (!datadir) 00266 { 00267 datadir= datadir_buf; 00268 if (test_file_exists(bindir, "data/mysql")) 00269 { 00270 *strxnmov(datadir_buf, sizeof(datadir_buf)-1, bindir, "/data", NullS)= 0; 00271 } 00272 else if (test_file_exists(bindir, "var/mysql")) 00273 { 00274 *strxnmov(datadir_buf, sizeof(datadir_buf)-1, bindir, "/var", NullS)= 0; 00275 } 00276 else 00277 datadir= (char*) DATADIR; 00278 } 00279 00280 strmake(bindir_end, "/bin", sizeof(bindir) - (int) (bindir_end - bindir)-1); 00281 00282 if (!test_file_exists_res 00283 (bindir, mysqlcheck_name, mysqlcheck_line, &mysqlcheck_end)) 00284 { 00285 printf("Can't find program '%s'\n", mysqlcheck_line); 00286 puts("Please restart with --basedir=mysql-install-directory"); 00287 exit(1); 00288 } 00289 00290 if (!test_file_exists(datadir, "mysql/user.frm")) 00291 { 00292 puts 00293 ("Can't find data directory. Please restart with --datadir=path-to-data-dir"); 00294 exit(1); 00295 } 00296 00297 /* create the modified defaults file to be used by mysqlcheck */ 00298 /* and mysql tools */ 00299 *strxnmov(upgrade_defaults_path, sizeof(upgrade_defaults_path)-1, 00300 datadir, "/upgrade_defaults", NullS)= 0; 00301 unpack_filename(upgrade_defaults_path, upgrade_defaults_path); 00302 if ((error= 00303 create_defaults_file(upgrade_defaults_path, forced_extra_defaults))) 00304 goto err_exit; 00305 00306 defaults_to_use= upgrade_defaults_created ? 00307 upgrade_defaults_path : forced_extra_defaults; 00308 00309 if (test_file_exists_res(datadir, "mysql_upgrade_info", check_file_name, 00310 &buf_end) && !opt_force) 00311 { 00312 char chf_buffer[50]; 00313 int b_read; 00314 check_file= my_open(check_file_name, O_RDONLY, MYF(0)); 00315 b_read= my_read(check_file, chf_buffer, sizeof(chf_buffer)-1, MYF(0)); 00316 chf_buffer[b_read]= 0; 00317 my_close(check_file, MYF(0)); 00318 if (!strcmp(chf_buffer, MYSQL_SERVER_VERSION)) 00319 { 00320 if (opt_verbose) 00321 puts("mysql_upgrade already done for this version"); 00322 goto fix_priv_tables; 00323 } 00324 } 00325 00326 if (defaults_to_use) 00327 { 00328 mysqlcheck_end= strxnmov(mysqlcheck_end, 00329 sizeof(mysqlcheck_line) - (int) (mysqlcheck_end - 00330 mysqlcheck_line), 00331 " --defaults-extra-file=", defaults_to_use,NullS); 00332 } 00333 00334 mysqlcheck_end= strxnmov(mysqlcheck_end, 00335 sizeof(mysqlcheck_line) - 00336 (int) (mysqlcheck_end - mysqlcheck_line - 1), 00337 " --check-upgrade --all-databases --auto-repair --user=", 00338 user, port_socket, NullS); 00339 *mysqlcheck_end= 0; 00340 00341 if (opt_verbose) 00342 printf("Running %s\n", mysqlcheck_line); 00343 if ((error= system(mysqlcheck_line))) 00344 { 00345 printf("Error executing '%s'\n", mysqlcheck_line); 00346 goto err_exit; 00347 } 00348 00349 if ((error= create_check_file(check_file_name))) 00350 goto err_exit; 00351 00352 fix_priv_tables: 00353 if (!test_file_exists_res(bindir, mysql_name, 00354 fix_priv_tables_cmd, &fix_cmd_end)) 00355 { 00356 puts("Could not find MySQL command-line client (mysql)."); 00357 puts 00358 ("Please use --basedir to specify the directory where MySQL is installed."); 00359 error= 1; 00360 goto err_exit; 00361 } 00362 00363 if (!test_file_exists_res(basedir, 00364 "support_files/mysql_fix_privilege_tables.sql", 00365 script_line, &buf_end) 00366 && !test_file_exists_res(basedir, "share/mysql_fix_privilege_tables.sql", 00367 script_line, &buf_end) 00368 && !test_file_exists_res(basedir, 00369 "share/mysql/mysql_fix_privilege_tables.sql", 00370 script_line, &buf_end) 00371 && !test_file_exists_res(basedir, 00372 "scripts/mysql_fix_privilege_tables.sql", 00373 script_line, &buf_end) 00374 && !test_file_exists_res("/usr/local/mysql/share/mysql", 00375 "mysql_fix_privilege_tables.sql", script_line, 00376 &buf_end)) 00377 { 00378 puts("Could not find file mysql_fix_privilege_tables.sql"); 00379 puts 00380 ("Please use --basedir to specify the directory where MySQL is installed"); 00381 error= 1; 00382 goto err_exit; 00383 } 00384 00385 if (defaults_to_use) 00386 { 00387 fix_cmd_end= strxnmov(fix_cmd_end, 00388 sizeof(fix_priv_tables_cmd) - 00389 (int) (fix_cmd_end - fix_priv_tables_cmd - 1), 00390 " --defaults-extra-file=", defaults_to_use, NullS); 00391 } 00392 fix_cmd_end= strxnmov(fix_cmd_end, 00393 sizeof(fix_priv_tables_cmd) - (int) (fix_cmd_end - 00394 fix_priv_tables_cmd), 00395 " --user=", user, port_socket, " mysql < ", script_line, NullS); 00396 *fix_cmd_end= 0; 00397 00398 if ((error= system(fix_priv_tables_cmd))) 00399 { 00400 /* Problem is that the 'Duplicate column' error */ 00401 /* which is not a bug for the script makes 'mysql' return */ 00402 /* an error */ 00403 /* printf("Error executing '%s'\n", fix_priv_tables_cmd); */ 00404 } 00405 00406 err_exit: 00407 if (upgrade_defaults_created) 00408 my_delete(upgrade_defaults_path, MYF(0)); 00409 my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); 00410 return error; 00411 } /* main */
1.4.7

