mysql_upgrade.c 19.7 KB
Newer Older
1 2 3 4
/* Copyright (C) 2000 MySQL AB

   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
unknown's avatar
unknown committed
5
   the Free Software Foundation; version 2 of the License.
6 7 8 9 10 11 12 13 14 15 16

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include "client_priv.h"
17
#include <sslopt-vars.h>
18
#include "../scripts/mysql_fix_privilege_tables_sql.c"
19

unknown's avatar
unknown committed
20 21 22 23 24 25 26 27 28 29 30 31
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif

#ifndef WEXITSTATUS
# ifdef __WIN__
#  define WEXITSTATUS(stat_val) (stat_val)
# else
#  define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
# endif
#endif

32 33
static char mysql_path[FN_REFLEN];
static char mysqlcheck_path[FN_REFLEN];
34

35 36 37
static my_bool opt_force, opt_verbose;
static char *opt_user= (char*)"root";

unknown's avatar
unknown committed
38
static DYNAMIC_STRING ds_args;
39 40 41

static char *opt_password= 0;
static my_bool tty_password= 0;
42

43 44 45
#ifndef DBUG_OFF
static char *default_dbug_option= (char*) "d:t:O,/tmp/mysql_upgrade.trace";
#endif
46

47 48
static char **defaults_argv;

49 50 51 52
static my_bool not_used; /* Can't use GET_BOOL without a value pointer */

#include <help_start.h>

53 54 55 56
static struct my_option my_long_options[]=
{
  {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
   NO_ARG, 0, 0, 0, 0, 0, 0},
57 58 59 60 61
  {"basedir", 'b', "Not used by mysql_upgrade. Only for backward compatibilty",
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  {"datadir", 'd',
   "Not used by mysql_upgrade. Only for backward compatibilty",
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
62 63 64 65 66 67 68
#ifdef DBUG_OFF
  {"debug", '#', "This is a non-debug version. Catch this and exit",
   0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
#else
  {"debug", '#', "Output debug log", (gptr *) & default_dbug_option,
   (gptr *) & default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
#endif
69
  {"default-character-set", OPT_DEFAULT_CHARSET,
70 71
   "Set the default character set.", 0,
   0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
72
  {"character-sets-dir", OPT_CHARSETS_DIR,
73 74
   "Directory where character sets are.", 0,
   0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
75
  {"compress", OPT_COMPRESS, "Use compression in server/client protocol.",
76 77 78 79 80 81 82
   (gptr*)&not_used, (gptr*)&not_used, 0, GET_BOOL, NO_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},
  {"host",'h', "Connect to host.", 0,
   0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
83
  {"password", 'p',
84
   "Password to use when connecting to server. If password is not given"
85 86
   " it's solicited on the tty.", (gptr*) &opt_password,(gptr*) &opt_password,
   0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
87
#ifdef __WIN__
88
  {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0,
89 90
   GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
91 92
  {"port", 'P', "Port number to use for connection.", 0,
   0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
93 94 95
  {"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},
96 97
#ifdef HAVE_SMEM
  {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
98 99
   "Base name of shared memory.", 0,
   0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
100
#endif
101
  {"socket", 'S', "Socket file to use for connection.",
102 103 104
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  {"user", 'u', "User for login if not current user.", (gptr*) &opt_user,
   (gptr*) &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
105
#include <sslopt-longopts.h>
106 107 108
  {"verbose", 'v', "Display more output about the process",
   (gptr*) &opt_verbose, (gptr*) &opt_verbose, 0,
   GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
109 110
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
111

112 113 114 115
#include <help_end.h>


static void free_used_memory(void)
116
{
117 118 119
  /* Free memory allocated by 'load_defaults' */
  free_defaults(defaults_argv);

unknown's avatar
unknown committed
120
  dynstr_free(&ds_args);
121
}
122

123

124
static void die(const char *fmt, ...)
125
{
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
  va_list args;
  DBUG_ENTER("die");

  /* Print the error message */
  va_start(args, fmt);
  if (fmt)
  {
    fprintf(stderr, "FATAL ERROR: ");
    vfprintf(stderr, fmt, args);
    fprintf(stderr, "\n");
    fflush(stderr);
  }
  va_end(args);

  free_used_memory();
  my_end(MY_CHECK_ERROR);
  exit(1);
}


static void verbose(const char *fmt, ...)
147
{
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
  va_list args;

  if (!opt_verbose)
    return;

  /* Print the verbose message */
  va_start(args, fmt);
  if (fmt)
  {
    vfprintf(stdout, fmt, args);
    fprintf(stdout, "\n");
    fflush(stdout);
  }
  va_end(args);
}


/*
  Add one option - passed to mysql_upgrade on command line
unknown's avatar
unknown committed
167 168
  or by defaults file(my.cnf) - to a dynamic string, in
  this way we pass the same arguments on to mysql and mysql_check
169 170 171 172 173
*/

static void add_one_option(DYNAMIC_STRING* ds,
                           const struct my_option *opt,
                           const char* argument)
174

unknown's avatar
unknown committed
175 176 177
{
  const char* eq= NullS;
  const char* arg= NullS;
178 179
  if (opt->arg_type != NO_ARG)
  {
unknown's avatar
unknown committed
180
    eq= "=";
181 182
    switch (opt->var_type & GET_TYPE_MASK) {
    case GET_STR:
unknown's avatar
unknown committed
183
      arg= argument;
184 185 186
      break;
    default:
      die("internal error at %s: %d",__FILE__, __LINE__);
187 188
    }
  }
unknown's avatar
unknown committed
189 190
  dynstr_append_os_quoted(ds, "--", opt->name, eq, arg, NullS);
  dynstr_append(&ds_args, " ");
191 192 193
}


194
static my_bool
195
get_one_option(int optid, const struct my_option *opt,
196 197
               char *argument)
{
198 199
  my_bool add_option= TRUE;

200
  switch (optid) {
201

202
  case '?':
203 204
    printf("MySQL utility for upgrading database to MySQL version %s\n",
           MYSQL_SERVER_VERSION);
205 206
    my_print_help(my_long_options);
    exit(0);
207 208
    break;

209 210
  case '#':
    DBUG_PUSH(argument ? argument : default_dbug_option);
211
    add_option= FALSE;
212
    break;
213

214 215
  case 'p':
    tty_password= 1;
216
    add_option= FALSE;
217 218
    if (argument)
    {
unknown's avatar
unknown committed
219 220
      /* Add password to ds_args before overwriting the arg with x's */
      add_one_option(&ds_args, opt, argument);
221 222 223 224 225
      while (*argument)
        *argument++= 'x';                       /* Destroy argument */
      tty_password= 0;
    }
    break;
226 227 228 229 230 231

  case 'b': /* --basedir   */
  case 'v': /* --verbose   */
  case 'd': /* --datadir   */
  case 'f': /* --force     */
    add_option= FALSE;
232
    break;
233 234 235 236 237 238 239
  }

  if (add_option)
  {
    /*
      This is an option that is accpted by mysql_upgrade just so
      it can be passed on to "mysql" and "mysqlcheck"
unknown's avatar
unknown committed
240
      Save it in the ds_args string
241
    */
unknown's avatar
unknown committed
242
    add_one_option(&ds_args, opt, argument);
243 244 245 246 247 248 249 250 251 252
  }
  return 0;
}


static int run_command(char* cmd,
                       DYNAMIC_STRING *ds_res)
{
  char buf[512]= {0};
  FILE *res_file;
253
  int error;
254 255 256 257 258 259 260 261

  if (!(res_file= popen(cmd, "r")))
    die("popen(\"%s\", \"r\") failed", cmd);

  while (fgets(buf, sizeof(buf), res_file))
  {
    DBUG_PRINT("info", ("buf: %s", buf));
    if(ds_res)
262
    {
263 264
      /* Save the output of this command in the supplied string */
      dynstr_append(ds_res, buf);
265
    }
266
    else
267
    {
268 269
      /* Print it directly on screen */
      fprintf(stdout, "%s", buf);
270 271
    }
  }
272

273 274
  error= pclose(res_file);
  return WEXITSTATUS(error);
275 276 277
}


278
static int run_tool(char *tool_path, DYNAMIC_STRING *ds_res, ...)
279
{
280
  int ret;
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
  const char* arg;
  va_list args;
  DYNAMIC_STRING ds_cmdline;

  DBUG_ENTER("run_tool");
  DBUG_PRINT("enter", ("tool_path: %s", tool_path));

  if (init_dynamic_string(&ds_cmdline, IF_WIN("\"", ""), FN_REFLEN, FN_REFLEN))
    die("Out of memory");

  dynstr_append_os_quoted(&ds_cmdline, tool_path, NullS);
  dynstr_append(&ds_cmdline, " ");

  va_start(args, ds_res);

  while ((arg= va_arg(args, char *)))
  {
    /* Options should be os quoted */
    if (strncmp(arg, "--", 2) == 0)
      dynstr_append_os_quoted(&ds_cmdline, arg, NullS);
    else
      dynstr_append(&ds_cmdline, arg);
    dynstr_append(&ds_cmdline, " ");
304
  }
305 306 307

  va_end(args);

unknown's avatar
unknown committed
308 309 310 311
#ifdef __WIN__
  dynstr_append(&ds_cmdline, "\"");
#endif

312 313 314 315 316
  DBUG_PRINT("info", ("Running: %s", ds_cmdline.str));
  ret= run_command(ds_cmdline.str, ds_res);
  DBUG_PRINT("exit", ("ret: %d", ret));
  dynstr_free(&ds_cmdline);
  DBUG_RETURN(ret);
317 318 319
}


320 321 322 323 324 325 326 327
/*
  Try to get the full path to this exceutable

  Return 0 if path found

*/

static my_bool get_full_path_to_executable(char* path)
328
{
329 330
  my_bool ret;
  DBUG_ENTER("get_full_path_to_executable");
unknown's avatar
unknown committed
331 332
#ifdef __WIN__
  ret= (GetModuleFileName(NULL, path, FN_REFLEN) == 0);
333 334
#else
  /* my_readlink returns 0 if a symlink was read */
unknown's avatar
unknown committed
335
  ret= (my_readlink(path, "/proc/self/exe", MYF(0)) != 0);
336 337 338 339 340
  /* Might also want to try with /proc/$$/exe if the above fails */
#endif
  DBUG_PRINT("exit", ("path: %s", path));
  DBUG_RETURN(ret);
}
341 342


343 344
/*
  Look for the tool in the same directory as mysql_upgrade.
345

346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
  When running in a not yet installed build the the program
  will exist but it need to be invoked via it's libtool wrapper.
  Check if the found tool can executed and if not look in the
  directory one step higher up where the libtool wrapper normally
  is found
*/

static void find_tool(char *tool_path, const char *tool_name)
{
  char path[FN_REFLEN];
  DYNAMIC_STRING ds_tmp;
  DBUG_ENTER("find_tool");
  DBUG_PRINT("enter", ("progname: %s", my_progname));

  if (init_dynamic_string(&ds_tmp, "", 32, 32))
    die("Out of memory");
362

363 364
  /* Initialize path with the full path to this program */
  if (get_full_path_to_executable(path))
unknown's avatar
unknown committed
365
  {
366 367 368 369 370
    /*
      Easy way to get full executable path failed, try
      other methods
    */
    if (my_progname[0] == FN_LIBCHAR)
unknown's avatar
unknown committed
371
    {
372 373
      /* 1. my_progname contains full path */
      strmake(path, my_progname, FN_REFLEN);
unknown's avatar
unknown committed
374
    }
375
    else if (my_progname[0] == '.')
376
    {
377 378 379
      /* 2. my_progname contains relative path, prepend wd */
      char buf[FN_REFLEN];
      my_getwd(buf, FN_REFLEN, MYF(0));
380
      my_snprintf(path, FN_REFLEN, "%s%s", buf, my_progname);
381
    }
382
    else
383
    {
384 385
      /* 3. Just go for it and hope tool is in path */
      path[0]= 0;
386 387
    }
  }
388
  do
389
  {
390 391 392
    DBUG_PRINT("enter", ("path: %s", path));

    /* Chop off last char(since it might be a /) */
unknown's avatar
unknown committed
393
    path[max((strlen(path)-1), 0)]= 0;
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411

    /* Chop off last dir part */
    dirname_part(path, path);

    /* Format name of the tool to search for */
    fn_format(tool_path, tool_name,
              path, "", MYF(MY_REPLACE_DIR));

    verbose("Looking for '%s' in: %s", tool_name, tool_path);

    /* Make sure the tool exists */
    if (my_access(tool_path, F_OK) != 0)
      die("Can't find '%s'", tool_path);

    /*
      Make sure it can be executed, otherwise try again
      in higher level directory
    */
412
  }
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
  while(run_tool(tool_path,
                 &ds_tmp, /* Get output from command, discard*/
                 "--help",
                 "2>&1",
                 IF_WIN("> NUL", "> /dev/null"),
                 NULL));

  dynstr_free(&ds_tmp);

  DBUG_VOID_RETURN;
}


/*
  Run query using "mysql"
*/

static int run_query(const char *query, DYNAMIC_STRING *ds_res,
                     my_bool force)
{
  int ret;
  File fd;
  char query_file_path[FN_REFLEN];
  DBUG_ENTER("run_query");
  DBUG_PRINT("enter", ("query: %s", query));
  if ((fd= create_temp_file(query_file_path, NULL,
unknown's avatar
unknown committed
439
                            "sql", O_CREAT | O_SHARE | O_RDWR,
440 441 442 443 444 445 446 447 448
                            MYF(MY_WME))) < 0)
    die("Failed to create temporary file for defaults");

  if (my_write(fd, query, strlen(query),
               MYF(MY_FNABP | MY_WME)))
    die("Failed to write to '%s'", query_file_path);

  ret= run_tool(mysql_path,
                ds_res,
unknown's avatar
unknown committed
449
                ds_args.str,
450 451 452 453 454 455 456 457 458 459
                "--database=mysql",
                "--batch", /* Turns off pager etc. */
                force ? "--force": "--skip-force",
                ds_res ? "--silent": "",
                "<",
                query_file_path,
                "2>&1",
                NULL);

  my_close(fd, MYF(0));
460
  my_delete(query_file_path, MYF(0));
461

462
  DBUG_RETURN(ret);
463 464 465
}


466 467 468 469 470
/*
  Extract the value returned from result of "show variable like ..."
*/

static int extract_variable_from_show(DYNAMIC_STRING* ds, char* value)
471
{
472 473 474 475 476 477 478 479 480 481
  char *value_start, *value_end;
  /*
    The query returns "datadir\t<datadir>\n", skip past
    the tab
  */
  if ((value_start= strchr(ds->str, '\t')) == NULL)
    return 1; /* Unexpected result */
  value_start++;

  /* Don't copy the ending newline */
482
  if ((value_end= strchr(value_start, '\n')) == NULL)
483 484 485 486
    return 1; /* Unexpected result */

  strncpy(value, value_start, min(FN_REFLEN, value_end-value_start));
  return 0;
487 488 489
}


490
static int get_upgrade_info_file_name(char* name)
491
{
492 493 494 495 496 497 498 499 500
  DYNAMIC_STRING ds_datadir;
  DBUG_ENTER("get_upgrade_info_file_name");

  if (init_dynamic_string(&ds_datadir, NULL, 32, 32))
    die("Out of memory");

  if (run_query("show variables like 'datadir'",
                &ds_datadir, FALSE) ||
      extract_variable_from_show(&ds_datadir, name))
501
  {
502 503
    dynstr_free(&ds_datadir);
    DBUG_RETURN(1); /* Query failed */
504
  }
505 506 507 508 509 510

  dynstr_free(&ds_datadir);

  fn_format(name, "mysql_upgrade_info", name, "", MYF(0));
  DBUG_PRINT("exit", ("name: %s", name));
  DBUG_RETURN(0);
511 512 513
}


514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
/*
  Read the content of mysql_upgrade_info file and
  compare the version number form file against
  version number wich mysql_upgrade was compiled for

  NOTE
  This is an optimization to avoid running mysql_upgrade
  when it's already been performed for the particular
  version of MySQL.

  In case the MySQL server can't return the upgrade info
  file it's always better to report that the upgrade hasn't
  been performed.

*/

static int upgrade_already_done(void)
531
{
532 533 534
  FILE *in;
  char upgrade_info_file[FN_REFLEN]= {0};
  char buf[sizeof(MYSQL_SERVER_VERSION)+1];
535

536 537
  if (get_upgrade_info_file_name(upgrade_info_file))
    return 0; /* Could not get filename => not sure */
538

539 540
  if (!(in= my_fopen(upgrade_info_file, O_RDONLY, MYF(0))))
    return 0; /* Could not open file => not sure */
541

542 543 544 545 546 547
  /*
    Read from file, don't care if it fails since it
    will be detected by the strncmp
  */
  bzero(buf, sizeof(buf));
  fgets(buf, sizeof(buf), in);
unknown's avatar
unknown committed
548

549
  my_fclose(in, MYF(0));
550

551 552 553
  return (strncmp(buf, MYSQL_SERVER_VERSION,
                  sizeof(MYSQL_SERVER_VERSION)-1)==0);
}
554 555


556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
/*
  Write mysql_upgrade_info file in servers data dir indicating that
  upgrade has been done for this version

  NOTE
  This might very well fail but since it's just an optimization
  to run mysql_upgrade only when necessary the error can be
  ignored.

*/

static void create_mysql_upgrade_info_file(void)
{
  FILE *out;
  char upgrade_info_file[FN_REFLEN]= {0};

  if (get_upgrade_info_file_name(upgrade_info_file))
    return; /* Could not get filename => skip */

  if (!(out= my_fopen(upgrade_info_file, O_TRUNC | O_WRONLY, MYF(0))))
576
  {
577
    fprintf(stderr,
578 579 580 581
            "Could not create the upgrade info file '%s' in "
            "the MySQL Servers datadir, errno: %d\n",
            upgrade_info_file, errno);
    return;
582 583
  }

584 585 586 587 588 589 590 591 592
  /* Write new version to file */
  fputs(MYSQL_SERVER_VERSION, out);
  my_fclose(out, MYF(0));

  /*
    Check if the upgrad_info_file was properly created/updated
    It's not a fatal error -> just print a message if it fails
  */
  if (!upgrade_already_done())
593 594 595 596
    fprintf(stderr,
            "Could not write to the upgrade info file '%s' in "
            "the MySQL Servers datadir, errno: %d\n",
            upgrade_info_file, errno);
597
  return;
598
}
599

600

601 602 603 604
/*
  Check and upgrade(if neccessary) all tables
  in the server using "mysqlcheck --check-upgrade .."
*/
605

606 607 608 609 610
static int run_mysqlcheck_upgrade(void)
{
  verbose("Running 'mysqlcheck'...");
  return run_tool(mysqlcheck_path,
                  NULL, /* Send output from mysqlcheck directly to screen */
unknown's avatar
unknown committed
611
                  ds_args.str,
612 613 614 615 616
                  "--check-upgrade",
                  "--all-databases",
                  "--auto-repair",
                  NULL);
}
617

618 619 620 621 622 623 624 625 626 627 628 629 630 631

static const char *expected_errors[]=
{
  "ERROR 1060", /* Duplicate column name */
  "ERROR 1061", /* Duplicate key name */
  "ERROR 1054", /* Unknown column */
  0
};


static my_bool is_expected_error(const char* line)
{
  const char** error= expected_errors;
  while (*error)
632
  {
633 634 635 636 637 638 639 640
    /*
      Check if lines starting with ERROR
      are in the list of expected errors
    */
    if (strncmp(line, "ERROR", 5) != 0 ||
        strncmp(line, *error, strlen(*error)) == 0)
      return 1; /* Found expected error */
    error++;
641
  }
642 643
  return 0;
}
644

645 646 647 648 649 650 651 652 653 654 655 656 657 658 659

static char* get_line(char* line)
{
  while (*line && *line != '\n')
    line++;
  if (*line)
    line++;
  return line;
}


/* Print the current line to stderr */
static void print_line(char* line)
{
  while (*line && *line != '\n')
660
  {
661 662
    fputc(*line, stderr);
    line++;
663
  }
664 665
  fputc('\n', stderr);
}
666 667


668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
/*
  Update all system tables in MySQL Server to current
  version using "mysql" to execute all the SQL commands
  compiled into the mysql_fix_privilege_tables array
*/

static int run_sql_fix_privilege_tables(void)
{
  int found_real_errors= 0;
  DYNAMIC_STRING ds_result;
  DBUG_ENTER("run_sql_fix_privilege_tables");

  if (init_dynamic_string(&ds_result, "", 512, 512))
    die("Out of memory");

  verbose("Running 'mysql_fix_privilege_tables'...");
  run_query(mysql_fix_privilege_tables,
            &ds_result, /* Collect result */
            TRUE);

688
  {
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
    /*
      Scan each line of the result for real errors
      and ignore the expected one(s) like "Duplicate column name",
      "Unknown column" and "Duplicate key name" since they just
      indicate the system tables are already up to date
    */
    char *line= ds_result.str;
    do
    {
      if (!is_expected_error(line))
      {
        /* Something unexpected failed, dump error line to screen */
        found_real_errors++;
        print_line(line);
      }
    } while ((line= get_line(line)) && *line);
705
  }
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726

  dynstr_free(&ds_result);
  return found_real_errors;
}


static const char *load_default_groups[]=
{
  "client", /* Read settings how to connect to server */
  "mysql_upgrade", /* Read special settings for mysql_upgrade*/
  0
};


int main(int argc, char **argv)
{
  MY_INIT(argv[0]);
#ifdef __NETWARE__
  setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
#endif

unknown's avatar
unknown committed
727
  if (init_dynamic_string(&ds_args, "", 512, 256))
728 729 730 731 732 733 734 735 736
    die("Out of memory");

  load_defaults("my", load_default_groups, &argc, &argv);
  defaults_argv= argv; /* Must be freed by 'free_defaults' */

  if (handle_options(&argc, &argv, my_long_options, get_one_option))
    die(NULL);

  if (tty_password)
737
  {
738 739
    opt_password= get_tty_password(NullS);
    /* add password to defaults file */
unknown's avatar
unknown committed
740 741
    dynstr_append_os_quoted(&ds_args, "--password=", opt_password, NullS);
    dynstr_append(&ds_args, " ");
742
  }
743
  /* add user to defaults file */
unknown's avatar
unknown committed
744 745
  dynstr_append_os_quoted(&ds_args, "--user=", opt_user, NullS);
  dynstr_append(&ds_args, " ");
746 747 748 749 750 751

  /* Find mysql */
  find_tool(mysql_path, IF_WIN("mysql.exe", "mysql"));

  /* Find mysqlcheck */
  find_tool(mysqlcheck_path, IF_WIN("mysqlcheck.exe", "mysqlcheck"));
752

753 754 755 756 757
  /*
    Read the mysql_upgrade_info file to check if mysql_upgrade
    already has been run for this installation of MySQL
  */
  if (!opt_force && upgrade_already_done())
758
  {
759 760 761 762
    printf("This installation of MySQL is already upgraded to %s, "
           "use --force if you still need to run mysql_upgrade\n",
           MYSQL_SERVER_VERSION);
    die(NULL);
763 764
  }

765
  /*
766
    Run "mysqlcheck" and "mysql_fix_privilege_tables.sql"
767
  */
768 769 770 771 772 773 774 775 776 777
  if (run_mysqlcheck_upgrade() ||
      run_sql_fix_privilege_tables())
  {
    /*
      The upgrade failed to complete in some way or another,
      significant error message should have been printed to the screen
    */
    die("Upgrade failed" );
  }
  verbose("OK");
778

779 780
  /* Create a file indicating upgrade has been performed */
  create_mysql_upgrade_info_file();
781

782 783 784
  free_used_memory();
  my_end(MY_CHECK_ERROR);
  exit(0);
785 786
}