1#!@PERL_PATH@ 2# -*- cperl -*- 3# 4# Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. 5# 6# This program is free software; you can redistribute it and/or modify 7# it under the terms of the GNU General Public License, version 2.0, 8# as published by the Free Software Foundation. 9# 10# This program is also distributed with certain software (including 11# but not limited to OpenSSL) that is licensed under separate terms, 12# as designated in a particular file or component or in included license 13# documentation. The authors of MySQL hereby grant you an additional 14# permission to link the program and your derivative works with the 15# separately licensed software that they have included with MySQL. 16# 17# This program is distributed in the hope that it will be useful, 18# but WITHOUT ANY WARRANTY; without even the implied warranty of 19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20# GNU General Public License, version 2.0, for more details. 21# 22# You should have received a copy of the GNU General Public License 23# along with this program; if not, write to the Free Software 24# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 25 26############################################################################## 27# 28# This scripts creates the MySQL Server system tables. 29# 30# This script try to match the shell script version as close as possible, 31# but in addition being compatible with ActiveState Perl on Windows. 32# 33# All unrecognized arguments to this script are passed to mysqld. 34# 35# NOTE: This script in 5.0 doesn't really match the shell script 36# version 100%, it is more close to the 5.1 version. 37# 38# NOTE: This script was deliberately written to be as close to the shell 39# script as possible, to make the maintenance of both in parallel 40# easier. 41# 42############################################################################## 43 44use strict; 45use warnings; 46 47############################################################################# 48# 49# Check if all needed modules are available, exit if something is missing. 50############################################################################# 51# 52 53BEGIN { 54 my @req_mods = ('Fcntl', 'File::Basename', 'File::Copy', 'Getopt::Long', 55 'Sys::Hostname', 'Data::Dumper'); 56 my @missing_mods; 57 my $req; 58 foreach $req (@req_mods) { 59 eval 'require ' . $req; 60 if ($@) { 61 push(@missing_mods, $req); 62 } else { 63 $req->import(); 64 } 65 } 66 # this avoids the confusing "BEGIN failed--compilation aborted" message 67 local $SIG{__DIE__} = sub {warn @_; exit 1}; 68 69 if (@missing_mods) { 70 my $msg = "FATAL ERROR: please install the following Perl modules " . 71 "before executing $0:\n" . join("\n",@missing_mods)."\n"; 72 die $msg; 73 } 74} 75 76Getopt::Long::Configure("pass_through"); 77 78my @args; # Argument list filled in 79my $basedir; 80 81############################################################################## 82# 83# Usage information 84# 85############################################################################## 86 87sub usage 88{ 89 print <<EOF1; 90Usage: $0 [OPTIONS] 91 --basedir=path The path to the MySQL installation directory. 92 --builddir=path If using --srcdir with out-of-directory builds, you 93 will need to set this to the location of the build 94 directory where built files reside. 95 --cross-bootstrap For internal use. Used when building the MySQL system 96 tables on a different host than the target. 97 --datadir=path The path to the MySQL data directory. 98 If missing, the directory will be created, but its 99 parent directory must already exist and be writable. 100 --defaults-extra-file=name 101 Read this file after the global files are read. 102 --defaults-file=name Only read default options from the given file name. 103 --force Causes mysql_install_db to run even if DNS does not 104 work. In that case, grant table entries that 105 normally use hostnames will use IP addresses. 106 --help Display this help and exit. 107 --ldata=path The path to the MySQL data directory. Same as --datadir. 108 --no-defaults Don't read default options from any option file. 109 --keep-my-cnf This option is enabled by default in Percona Server and 110 is kept only for compatibility: don't try to create 111 my.cnf based on template. 112 Useful for systems with working, updated my.cnf. 113 Deprecated, will be removed in future version. 114EOF1 115 if ( $^O !~ m/^(MSWin32|cygwin)$/ ) { 116 print <<EOF2; 117 --random-passwords Create and set a random password for all root accounts 118 and set the "password expired" flag, 119 also remove the anonymous accounts. 120EOF2 121 } 122 print <<EOF3; 123 --rpm For internal use. This option is used by RPM files 124 during the MySQL installation process. 125 --skip-name-resolve Use IP addresses rather than hostnames when creating 126 grant table entries. This option can be useful if 127 your DNS does not work. 128 --srcdir=path The path to the MySQL source directory. This option 129 uses the compiled binaries and support files within the 130 source tree, useful for if you don't want to install 131 MySQL yet and just want to create the system tables. 132EOF3 133 if ( $^O !~ m/^(MSWin32|cygwin)$/ ) { 134 print <<EOF4; 135 --user=user_name The login username to use for running mysqld. Files 136 and directories created by mysqld will be owned by this 137 user. You must be root to use this option. By default 138 mysqld runs using your current login name and files and 139 directories that it creates will be owned by you. 140EOF4 141 } 142 print <<EOF5; 143Any other options are passed to the mysqld program. 144 145EOF5 146 exit 1; 147} 148 149############################################################################## 150# 151# Parse an argument list 152# 153# We only need to pass arguments through to the server if we don't 154# handle them here. So, we collect unrecognized options (passed on 155# the command line) into the args variable. 156# 157############################################################################## 158 159sub parse_arguments 160{ 161 my $opt = shift; 162 163 my @saved_ARGV = @ARGV; 164 @ARGV = @_; # Set ARGV so GetOptions works 165 166 my $pick_args; 167 if (@ARGV and $ARGV[0] eq 'PICK-ARGS-FROM-ARGV') 168 { 169 $pick_args = 1; 170 shift @ARGV; 171 } 172 173 GetOptions( 174 $opt, 175 "force", 176 "basedir=s", 177 "builddir=s", # FIXME not documented 178 "srcdir=s", 179 "ldata|datadir=s", 180 181 # Note that the user will be passed to mysqld so that it runs 182 # as 'user' (crucial e.g. if log-bin=/some_other_path/ 183 # where a chown of datadir won't help) 184 "user=s", 185 186 "skip-name-resolve", 187 "verbose", 188 "keep-my-cnf", 189 "rpm", 190 "help", 191 "random-passwords", 192 193 # These options will also be pased to mysqld. 194 "defaults-file=s", 195 "defaults-extra-file=s", 196 "no-defaults", 197 198 # Used when building the MySQL system tables on a different host than 199 # the target. The platform-independent files that are created in 200 # --datadir on the host can be copied to the target system. 201 # 202 # The most common use for this feature is in the Windows installer 203 # which will take the files from datadir and include them as part of 204 # the install package. See top-level 'dist-hook' make target. 205 # 206 # --windows is a deprecated alias 207 "cross-bootstrap|windows", 208 ) or usage(); 209 210 usage() if $opt->{help}; 211 212 if ( $opt->{'no-defaults'} && ( $opt->{'defaults-extra-file'} || 213 $opt->{'defaults-file'} ) ) 214 { 215 error($opt, 216 "Cannot use both --no-defaults and --defaults-[extra-]file"); 217 } 218 219 @args = @ARGV if $pick_args; 220 221 @ARGV = @saved_ARGV; # Set back ARGV 222} 223 224############################################################################## 225# 226# Try to find a specific file within --basedir which can either be a binary 227# release or installed source directory and return the path. 228# 229############################################################################## 230 231sub find_in_basedir 232{ 233 my $opt = shift; 234 my $mode = shift; # "dir" or "file" 235 my $files = shift; 236 237 foreach my $file ( @{ref($files) ? $files : [$files]} ) 238 { 239 foreach my $dir ( @_ ) 240 { 241 foreach my $part ( "$file","$file.exe","release/$file.exe", 242 "debug/$file.exe","relwithdebinfo/$file.exe" ) 243 { 244 my $path = "$basedir/$dir/$part"; 245 if ( -f $path ) 246 { 247 return $mode eq "dir" ? dirname($path) : $path; 248 } 249 } 250 } 251 } 252} 253 254############################################################################## 255# 256# Just a function to write out an error report 257# 258############################################################################## 259 260sub cannot_find_file 261{ 262 my $file = shift; 263 264 print "FATAL ERROR: Could not find $file\n"; 265 print "\n"; 266 print "If you compiled from source, you need to run 'make install' to\n"; 267 print "copy the software into the correct location ready for operation.\n"; 268 print "\n"; 269 print "If you are using a binary release, you must either be at the top\n"; 270 print "level of the extracted archive, or pass the --basedir option\n"; 271 print "pointing to that location.\n"; 272 print "\n"; 273 274 exit 1; 275} 276 277############################################################################## 278# 279# Form a command line that can handle spaces in paths and arguments 280# 281############################################################################## 282 283# FIXME this backslash escaping needed if using '"..."' ? 284# This regexp makes sure that any special chars are quoted, 285# so the arg gets passed exactly to the server. 286# XXX: This is broken; true fix requires using eval and proper 287# quoting of every single arg ($opt->{basedir}, $opt->{ldata}, etc.) 288# join(" ", map {s/([^\w\_\.\-])/\\$1/g} 289 290sub quote_options { 291 my @cmd; 292 foreach my $opt ( @_ ) 293 { 294 next unless $opt; # If undefined or empty, just skip 295 push(@cmd, "\"$opt\""); # Quote argument 296 } 297 return join(" ", @cmd); 298} 299 300############################################################################## 301# 302# Simple escape mechanism (\-escape any ' and \), suitable for two contexts: 303# - single-quoted SQL strings 304# - single-quoted option values on the right hand side of = in my.cnf 305# 306############################################################################## 307 308# (Function and comment copied from 'mysql_secure_installation') 309 310# These two contexts don't handle escapes identically. SQL strings allow 311# quoting any character (\C => C, for any C), but my.cnf parsing allows 312# quoting only \, ' or ". For example, password='a\b' quotes a 3-character 313# string in my.cnf, but a 2-character string in SQL. 314# 315# This simple escape works correctly in both places. 316 317# FIXME: What about double quote in password? Not handled here - not needed? 318 319sub basic_single_escape { 320 my ($str) = @_; 321 # Inside a character class, \ is not special; this escapes both \ and ' 322 $str =~ s/([\'])/\\$1/g; 323 return $str; 324} 325 326############################################################################## 327# 328# Handle the files with confidential contents 329# 330############################################################################## 331 332my $secret_file; # full path name of the confidential file 333my $escaped_password; # the password, with special characters escaped 334 335sub ensure_secret_file { 336 $secret_file = $ENV{HOME} . "/.mysql_secret"; 337 338 # Create safe files to avoid leaking info to other users 339 # Loop may be extended if we need more ... 340 foreach my $file ( $secret_file ) { 341 next if -f $file; # Already exists 342 local *FILE; 343 sysopen(FILE, $file, O_CREAT, 0600) 344 or die "ERROR: can't create $file: $!"; 345 close FILE; 346 } 347} 348 349############################################################################## 350# 351# Append an arbitrary number of lines to an existing file 352# 353############################################################################## 354 355sub append_file { 356 my $file = shift; 357 -f $file or die "ERROR: file is missing \"$file\": $!"; 358 open(FILE, ">>$file") or die "ERROR: can't append to file \"$file\": $!"; 359 foreach my $line ( @_ ) { 360 print FILE $line, "\n"; # Add EOL char 361 } 362 close FILE; 363} 364 365############################################################################## 366# 367# Inform the user about the generated random password 368# 369############################################################################## 370 371sub tell_root_password { 372 my $now = localtime(); # scalar context = printable string 373 374 # Now, we need to tell the user the new root password. 375 # We use "append_file" to protect the user in case they are doing multiple 376 # installations intermixed with backups and restores. 377 # While this would be really bad practice, it still might happen. 378 # As long as this file is not destroyed, the time stamps may rescue them. 379 # Having the comment and the password on the same line makes it easier 380 # to automatically extract the password (automated testing!), and the final 381 # empty line is for better redability. 382 append_file($secret_file, 383 "# The random password set for the root user at $now (local time): " . 384 $escaped_password, 385 ""); 386 print "A random root password has been set. You will find it in '$secret_file'.\n"; 387} 388 389############################################################################## 390# 391# Generate a random password 392# 393############################################################################## 394 395sub generate_random_password { 396 # On Linux, Solaris, Max OS X and FreeBSD we have a random device available. 397 my $randfile = "/dev/urandom"; 398 open(FD, $randfile) || return ""; 399 my $password = ""; 400 my $pass_len = 16; 401 my $c; 402 while (length($password) < $pass_len) { 403 $c = getc(FD); 404 if ($c =~ /\w/) { 405 $password .= $c; 406 } 407 } 408 close(FD); 409 return $password; 410} 411 412 413############################################################################## 414# 415# Ok, let's go. We first need to parse arguments which are required by 416# my_print_defaults so that we can execute it first, then later re-parse 417# the command line to add any extra bits that we need. 418# 419############################################################################## 420 421my $opt = {}; 422parse_arguments($opt, 'PICK-ARGS-FROM-ARGV', @ARGV); 423 424# ---------------------------------------------------------------------- 425# Actual basedir, not to be confused with --basedir option 426# ---------------------------------------------------------------------- 427 428if ( $opt->{srcdir} ) { 429 $basedir= $opt->{builddir}; 430} else { 431 $basedir= $opt->{basedir}; 432} 433$basedir= "@prefix@" if ! $basedir; # Default 434 435# ---------------------------------------------------------------------- 436# We can now find my_print_defaults. This script supports: 437# 438# --srcdir=path pointing to compiled source tree 439# --basedir=path pointing to installed binary location 440# 441# or default to compiled-in locations. 442# ---------------------------------------------------------------------- 443 444my $print_defaults; 445 446if ( $opt->{srcdir} and $opt->{basedir} ) 447{ 448 error($opt,"Specify either --basedir or --srcdir, not both"); 449} 450if ( $opt->{srcdir} ) 451{ 452 $opt->{builddir} = $opt->{srcdir} unless $opt->{builddir}; 453 $print_defaults = "$opt->{builddir}/extra/my_print_defaults"; 454} 455else 456{ 457 $print_defaults = find_in_basedir($opt,"file","my_print_defaults","bin","extra"); 458} 459if ( ! $print_defaults ) 460{ 461 $print_defaults='@bindir@/my_print_defaults'; 462} 463 464-x $print_defaults or -f "$print_defaults.exe" 465 or cannot_find_file($print_defaults); 466 467# Next block is commented because of bug1225189 468# Except for the line that defines variable $cnfext which is needed 469# my $config_file; 470# my $copy_cfg_file; 471 472# # ---------------------------------------------------------------------- 473# # This will be the default config file 474# # ---------------------------------------------------------------------- 475 476my $cnfext = ( $^O =~ m/^(MSWin32|cygwin)$/ ) ? "ini" : "cnf"; 477 478# $config_file= "$basedir/my.$cnfext"; 479 480# my $cfg_template= find_in_basedir($opt,"file","my-default.$cnfext", 481# ".", "share","share/mysql","support-files"); 482# -e $cfg_template or cannot_find_file("my-default.$cnfext"); 483 484# $copy_cfg_file= $config_file; 485# my $failed_write_cfg= 0; 486# if (-e $copy_cfg_file) 487# { 488# $copy_cfg_file =~ s/my.$cnfext/my-new.$cnfext/; 489# # Too early to print warning here, the user may not notice 490# } 491# open (TEMPL, $cfg_template) or error($opt, "Could not open config template $cfg_template"); 492# if (open (CFG, "> $copy_cfg_file")) 493# { 494# while (<TEMPL>) 495# { 496# # Remove lines beginning with # *** which are template comments 497# print CFG $_ unless /^# \*\*\*/; 498# } 499# close CFG; 500# } 501# else 502# { 503# warning($opt,"Could not write to config file $copy_cfg_file: $!"); 504# $failed_write_cfg= 1; 505# } 506# close TEMPL; 507 508# ---------------------------------------------------------------------- 509# Now we can get arguments from the groups [mysqld] and [mysql_install_db] 510# in the my.cfg file, then re-run to merge with command line arguments. 511# ---------------------------------------------------------------------- 512 513my $cmd; 514my @default_options; 515if ( $opt->{'defaults-file'} ) 516{ 517 $cmd = quote_options($print_defaults, 518 "--defaults-file=$opt->{'defaults-file'}", 519 "mysqld", "mysql_install_db"); 520} 521else 522{ 523 $cmd = quote_options($print_defaults, "mysqld", "mysql_install_db"); 524} 525 526open(PIPE, "$cmd |") or error($opt,"can't run $cmd: $!"); 527while ( <PIPE> ) 528{ 529 chomp; 530 next unless /\S/; 531 push(@default_options, $_); 532} 533close PIPE; 534$opt = {}; # Reset the arguments FIXME ? 535parse_arguments($opt, @default_options); 536parse_arguments($opt, 'PICK-ARGS-FROM-ARGV', @ARGV); 537 538# ---------------------------------------------------------------------- 539# Create a random password for root, if requested and implemented 540# ---------------------------------------------------------------------- 541 542if ( $opt->{'random-passwords'} ) { 543 # Add other non-working OS like this: $^O =~ m/^(solaris|linux|freebsd|darwin)$/ 544 # and maintain "usage()". 545 # Issue 1: random password creation 546 # Issue 2: confidential file 547 if ( $^O =~ m/^(MSWin32|cygwin)$/ ) { 548 print "Random password not yet implemented for $^O - option will be ignored\n"; 549 delete $opt->{'random-passwords'}; 550 } else { 551 ensure_secret_file(); 552 my $password = generate_random_password(); 553 if ( $password ) { 554 # "true" means "string is non-empty" 555 $escaped_password = basic_single_escape($password); 556 } else { 557 # Whatever the reason (missing "/dev/urandom"), an empty password is bad 558 print "Could not generate a random password - not setting one\n"; 559 delete $opt->{'random-passwords'}; 560 } 561 } 562} 563 564# ---------------------------------------------------------------------- 565# Configure paths to support files 566# ---------------------------------------------------------------------- 567 568# FIXME $extra_bindir is not used 569my ($bindir,$extra_bindir,$mysqld,$pkgdatadir,$mysqld_opt,$scriptdir); 570 571if ( $opt->{srcdir} ) 572{ 573 $bindir = "$basedir/client"; 574 $extra_bindir = "$basedir/extra"; 575 $mysqld = "$basedir/sql/mysqld"; 576 $mysqld_opt = "--language=$opt->{srcdir}/sql/share/english"; 577 $pkgdatadir = "$opt->{srcdir}/scripts"; 578 $scriptdir = "$opt->{srcdir}/scripts"; 579} 580elsif ( $opt->{basedir} ) 581{ 582 $bindir = "$opt->{basedir}/bin"; 583 $extra_bindir = $bindir; 584 $mysqld = find_in_basedir($opt,"file",["mysqld-nt","mysqld"], 585 "libexec","sbin","bin") || # ,"sql" 586 find_in_basedir($opt,"file","mysqld-nt", 587 "bin"); # ,"sql" 588 $pkgdatadir = find_in_basedir($opt,"dir","fill_help_tables.sql", 589 "share","share/percona-server","share/mysql"); # ,"scripts" 590 $scriptdir = "$opt->{basedir}/scripts"; 591} 592else 593{ 594 $bindir = '@bindir@'; 595 $extra_bindir = $bindir; 596 $mysqld = '@libexecdir@/mysqld'; 597 $pkgdatadir = '@pkgdatadir@'; 598 $scriptdir = '@scriptdir@'; 599} 600 601unless ( $opt->{ldata} ) 602{ 603 $opt->{ldata} = '@localstatedir@'; 604} 605 606if ( $opt->{srcdir} ) 607{ 608 $pkgdatadir = "$opt->{srcdir}/scripts"; 609} 610 611# ---------------------------------------------------------------------- 612# Set up paths to SQL scripts required for bootstrap 613# ---------------------------------------------------------------------- 614 615my $fill_help_tables = "$pkgdatadir/fill_help_tables.sql"; 616my $create_system_tables = "$pkgdatadir/mysql_system_tables.sql"; 617my $fill_system_tables = "$pkgdatadir/mysql_system_tables_data.sql"; 618my $security_commands = "$pkgdatadir/mysql_security_commands.sql"; 619 620foreach my $f ( $fill_help_tables, $create_system_tables, $fill_system_tables, $security_commands ) 621{ 622 -f $f or cannot_find_file($f); 623} 624 625-x $mysqld or -f "$mysqld.exe" or cannot_find_file($mysqld); 626# Try to determine the hostname 627my $hostname = hostname(); 628 629# ---------------------------------------------------------------------- 630# Check if hostname is valid 631# ---------------------------------------------------------------------- 632 633my $resolved; 634if ( !$opt->{'cross-bootstrap'} and !$opt->{rpm} and !$opt->{force} ) 635{ 636 my $resolveip = "$extra_bindir/resolveip"; 637 638 $resolved = `$resolveip $hostname 2>&1`; 639 if ( $? != 0 ) 640 { 641 $resolved=`$resolveip localhost 2>&1`; 642 if ( $? != 0 ) 643 { 644 error($opt, 645 "Neither host '$hostname' nor 'localhost' could be looked up with", 646 "$resolveip", 647 "Please configure the 'hostname' command to return a correct", 648 "hostname.", 649 "If you want to solve this at a later stage, restart this script", 650 "with the --force option"); 651 } 652 warning($opt, 653 "The host '$hostname' could not be looked up with $resolveip.", 654 "This probably means that your libc libraries are not 100 % compatible", 655 "with this binary MySQL version. The MySQL daemon, mysqld, should work", 656 "normally with the exception that host name resolving will not work.", 657 "This means that you should use IP addresses instead of hostnames", 658 "when specifying MySQL privileges !"); 659 } 660} 661 662# FIXME what does this really mean.... 663if ( $opt->{'skip-name-resolve'} and $resolved and $resolved =~ /\s/ ) 664{ 665 $hostname = (split(' ', $resolved))[5]; 666} 667 668# ---------------------------------------------------------------------- 669# Create database directories mysql & test 670# ---------------------------------------------------------------------- 671 672# FIXME The shell variant uses "mkdir -p": 673# - because it is silent if the target exists, or 674# - because it will cerate the path? 675# Path creation is demanded by testers in bug# 14731457, but that might be risky 676# in case of typos as this is run by root. 677# For now, give an error message: 678my $parent = dirname ( $opt->{ldata} ); 679if ( ! -d $parent ) { 680 error($opt, 681 "The parent directory for the data directory '$opt->{ldata}' does not exist.", 682 "If that path was really intended, please create that directory path and then", 683 "restart this script.", 684 "If some other path was intended, please use the correct path when restarting this script."); 685} 686 687my $opt_user= $opt->{user}; 688my @pwnam; 689if ($opt_user) 690{ 691 if ( $^O =~ m/^(MSWin32|cygwin)$/ ) 692 { 693 warning($opt, "The --user option is not supported on Windows, ignoring"); 694 $opt_user= undef; 695 } 696 else 697 { 698 @pwnam= getpwnam($opt_user); 699 } 700} 701 702foreach my $dir ( $opt->{ldata}, "$opt->{ldata}/mysql", "$opt->{ldata}/test" ) 703{ 704 mkdir($dir, 0700) unless -d $dir; 705 if ($opt_user and -w "/") 706 { 707 chown($pwnam[2], $pwnam[3], $dir) 708 or error($opt, "Could not chown directory $dir"); 709 } 710} 711 712push(@args, "--user=$opt->{user}") if $opt->{user}; 713 714# ---------------------------------------------------------------------- 715# Configure mysqld command line 716# ---------------------------------------------------------------------- 717 718# FIXME use --init-file instead of --bootstrap ?! 719 720my $defaults_option = ""; 721if ( $opt->{'no-defaults'} ) 722{ 723 $defaults_option= "--no-defaults"; 724} 725elsif ( $opt->{'defaults-file'} ) 726{ 727 $defaults_option= "--defaults-file=$opt->{'defaults-file'}"; 728} 729 730my $defaults_extra= "--defaults-extra-file=$opt->{'defaults-extra-file'}" 731 if $opt->{'defaults-extra-file'}; 732 733my $mysqld_bootstrap = $ENV{MYSQLD_BOOTSTRAP} || $mysqld; 734my $mysqld_install_cmd_line = quote_options($mysqld_bootstrap, 735 $defaults_option, 736 $defaults_extra, 737 $mysqld_opt, 738 "--bootstrap", 739 "--basedir=$basedir", 740 "--datadir=$opt->{ldata}", 741 "--log-warnings=0", 742 "--loose-skip-ndbcluster", 743 "--max_allowed_packet=8M", 744 "--default-storage-engine=MyISAM", 745 "--net_buffer_length=16K", 746 @args, 747 ); 748 749# ---------------------------------------------------------------------- 750# Create the system and help tables by passing them to "mysqld --bootstrap" 751# ---------------------------------------------------------------------- 752 753report_verbose_wait($opt,"Installing MySQL system tables..."); 754 755open(SQL, $create_system_tables) 756 or error($opt,"can't open $create_system_tables for reading: $!"); 757open(SQL2, $fill_system_tables) 758 or error($opt,"can't open $fill_system_tables for reading: $!"); 759# FIXME > /dev/null ? 760if ( open(PIPE, "| $mysqld_install_cmd_line") ) 761{ 762 print PIPE "use mysql;\n"; 763 while ( <SQL> ) 764 { 765 # When doing a "cross bootstrap" install, no reference to the current 766 # host should be added to the system tables. So we filter out any 767 # lines which contain the current host name. 768 next if $opt->{'cross-bootstrap'} and /\@current_hostname/; 769 770 print PIPE $_; 771 } 772 while ( <SQL2> ) 773 { 774 # When doing a "cross bootstrap" install, no reference to the current 775 # host should be added to the system tables. So we filter out any 776 # lines which contain the current host name. 777 next if $opt->{'cross-bootstrap'} and /\@current_hostname/; 778 779 print PIPE $_; 780 } 781 782 if ( $opt->{'random-passwords'} ) 783 { 784 open(SQL3, $security_commands) 785 or error($opt,"can't open $security_commands for reading: $!"); 786 while ( <SQL3> ) 787 { 788 # using the implicit variable $_ ! 789 s/ABC123xyz/$escaped_password/e ; # Replace placeholder by random password 790 print PIPE $_; 791 } 792 close SQL3; 793 tell_root_password(); 794 } 795 796 if (!close PIPE) 797 { 798 if ($!) 799 { 800 error($opt, "Error closing mysqld pipe: $!"); 801 } 802 else 803 { 804 error($opt, 805 "Installation of system tables failed!", 806 "mysqld returned $? exit status", 807 "Examine the logs in $opt->{ldata} for more information."); 808 } 809 }; 810 811 close SQL; 812 close SQL2; 813 814 report_verbose($opt,"OK"); 815 816 # ---------------------------------------------------------------------- 817 # Pipe fill_help_tables.sql to "mysqld --bootstrap" 818 # ---------------------------------------------------------------------- 819 820 report_verbose_wait($opt,"Filling help tables..."); 821 open(SQL, $fill_help_tables) 822 or error($opt,"can't open $fill_help_tables for reading: $!"); 823 # FIXME > /dev/null ? 824 if ( open(PIPE, "| $mysqld_install_cmd_line") ) 825 { 826 print PIPE "use mysql;\n"; 827 while ( <SQL> ) 828 { 829 print PIPE $_; 830 } 831 if (!close PIPE) 832 { 833 if ($!) 834 { 835 error($opt, "Error closing mysqld pipe: $!"); 836 } 837 else 838 { 839 error($opt, 840 "Installation of system tables failed!", 841 "mysqld returned $? exit status", 842 "Examine the logs in $opt->{ldata} for more information."); 843 } 844 }; 845 close SQL; 846 847 report_verbose($opt,"OK"); 848 } 849 else 850 { 851 warning($opt,"HELP FILES ARE NOT COMPLETELY INSTALLED!", 852 "The \"HELP\" command might not work properly"); 853 } 854 855 report_verbose($opt,"To start mysqld at boot time you have to copy", 856 "support-files/mysql.server to the right place " . 857 "for your system"); 858 859 if ( !$opt->{'cross-bootstrap'} ) 860 { 861 # This is not a true installation on a running system. The end user must 862 # set a password after installing the data files on the real host system. 863 # At this point, there is no end user, so it does not make sense to print 864 # this reminder. 865 if ( $opt->{'random-passwords'} ) { 866 report($opt, 867 "A RANDOM PASSWORD HAS BEEN SET FOR THE MySQL root USER !", 868 "You will find that password in '$secret_file'.", 869 "", 870 "You must change that password on your first connect,", 871 "no other statement but 'SET PASSWORD' will be accepted.", 872 "See the manual for the semantics of the 'password expired' flag.", 873 "", 874 "Also, the account for the anonymous user has been removed.", 875 "", 876 "In addition, you can run:", 877 "", 878 " $bindir/mysql_secure_installation", 879 "", 880 "which will also give you the option of removing the test database.", 881 "This is strongly recommended for production servers.", 882 "", 883 "See the manual for more instructions."); 884 } else { 885 report($opt, 886 "PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !", 887 "To do so, start the server, then issue the following commands:", 888 "", 889 " $bindir/mysqladmin -u root password 'new-password'", 890 " $bindir/mysqladmin -u root -h $hostname password 'new-password'", 891 "", 892 "Alternatively you can run:", 893 "", 894 " $bindir/mysql_secure_installation", 895 "", 896 "which will also give you the option of removing the test", 897 "databases and anonymous user created by default. This is", 898 "strongly recommended for production servers.", 899 "", 900 "See the manual for more instructions."); 901 } 902 903 if ( !$opt->{rpm} ) 904 { 905 report($opt, 906 "You can start the MySQL daemon with:", 907 "", 908 " cd " . '@prefix@' . " ; $bindir/mysqld_safe &", 909 "", 910 "You can test the MySQL daemon with mysql-test-run.pl", 911 "", 912 " cd mysql-test ; perl mysql-test-run.pl"); 913 } 914 report($opt, 915 "Please report any problems at", 916 " https://jira.percona.com/projects/PS", 917 "", 918 "The latest information about Percona Server is available on the web at", 919 " http://www.percona.com/software/percona-server", 920 "", 921 "Support Percona by buying support at", 922 " http://www.percona.com/products/mysql-support"); 923 924# Next block is commented because of bug1225189 925# if ($copy_cfg_file eq $config_file and !$failed_write_cfg) 926# { 927# report($opt, 928# "New default config file was created as $config_file and", 929# "will be used by default by the server when you start it.", 930# "You may edit this file to change server settings"); 931# } 932# elsif ($failed_write_cfg) 933# { 934# warning($opt, 935# "Could not copy config file template $cfg_template to", 936# "$copy_cfg_file, may not have access rights to do so.", 937# "You may want to copy the file manually, or create your own,", 938# "it will then be used by default by the server when you start it."); 939# } 940# else 941# { 942# warning($opt, 943# "Found existing config file $config_file on the system.", 944# "Because this file might be in use, it was not replaced,", 945# "but was used in bootstrap (unless you used --defaults-file)", 946# "and when you later start the server.", 947# "The new default config file was created as $copy_cfg_file,", 948# "please compare it with your file and take the changes you need."); 949# } 950 951 foreach my $cfg ( "/etc/my.$cnfext", "/etc/mysql/my.$cnfext" ) 952 { 953 check_sys_cfg_file ($opt, $cfg); 954 } 955 } 956 exit 0 957} 958else 959{ 960 error($opt, 961 "Installation of system tables failed!", 962 "", 963 "Examine the logs in $opt->{ldata} for more information.", 964 "You can try to start the mysqld daemon with:", 965 "$mysqld --skip-grant-tables &", 966 "and use the command line tool", 967 "$bindir/mysql to connect to the mysql", 968 "database and look at the grant tables:", 969 "", 970 "shell> $bindir/mysql -u root mysql", 971 "mysql> show tables", 972 "", 973 "Try 'mysqld --help' if you have problems with paths. Using --log", 974 "gives you a log in $opt->{ldata} that may be helpful.", 975 "", 976 "The latest information about Percona Server is available on the web at", 977 " http://www.percona.com/software/percona-server", 978 "", 979 "Please consult the MySQL manual section: 'Problems running mysql_install_db',", 980 "and the manual section that describes problems on your OS.", 981 "Another information source is the MySQL email archive.", 982 "", 983 "Please check all of the above before submitting a bug report at", 984 " https://jira.percona.com/projects/PS") 985} 986 987############################################################################## 988# 989# Misc 990# 991############################################################################## 992 993sub check_sys_cfg_file 994{ 995 my $opt= shift; 996 my $fname= shift; 997 998 if ( -e $fname ) 999 { 1000 warning($opt, 1001 "Default config file $fname exists on the system", 1002 "This file will be read by default by the MySQL server", 1003 "If you do not want to use this, either remove it, or use the", 1004 "--defaults-file argument to mysqld_safe when starting the server"); 1005 } 1006} 1007 1008sub report_verbose 1009{ 1010 my $opt = shift; 1011 my $text = shift; 1012 1013 report_verbose_wait($opt, $text, @_); 1014 print "\n\n"; 1015} 1016 1017sub report_verbose_wait 1018{ 1019 my $opt = shift; 1020 my $text = shift; 1021 1022 if ( $opt->{verbose} or (!$opt->{rpm} and !$opt->{'cross-bootstrap'}) ) 1023 { 1024 print "$text"; 1025 map {print "\n$_"} @_; 1026 } 1027} 1028 1029sub report 1030{ 1031 my $opt = shift; 1032 my $text = shift; 1033 1034 print "$text\n"; 1035 map {print "$_\n"} @_; 1036 print "\n"; 1037} 1038 1039sub error 1040{ 1041 my $opt = shift; 1042 my $text = shift; 1043 1044 print "FATAL ERROR: $text\n"; 1045 map {print "$_\n"} @_; 1046 exit 1; 1047} 1048 1049sub warning 1050{ 1051 my $opt = shift; 1052 my $text = shift; 1053 1054 print "WARNING: $text\n"; 1055 map {print "$_\n"} @_; 1056 print "\n"; 1057} 1058 1059# Include dummy lines with patterns that generalized pkgadd script expects 1060 1061my $_pkgadd_fodder= " 1062basedir=foo 1063datadir=bar 1064"; 1065