From 3f619478f796eddbba6e39502fe941b285dd97b1 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 20:00:34 +0200 Subject: Adding upstream version 1:10.11.6. Signed-off-by: Daniel Baumann --- scripts/mysqld_multi.sh | 960 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 960 insertions(+) create mode 100644 scripts/mysqld_multi.sh (limited to 'scripts/mysqld_multi.sh') diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh new file mode 100644 index 00000000..9a1f3920 --- /dev/null +++ b/scripts/mysqld_multi.sh @@ -0,0 +1,960 @@ +#!@PERL_PATH@ + +# Copyright (c) 2000, 2017, Oracle and/or its affiliates. +# Copyright (c) 2010, 2017, MariaDB Corporation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1335 USA + +use Getopt::Long; +use POSIX qw(strftime getcwd); +use File::Path qw(mkpath); + +$|=1; +$VER="3.0"; + +my @defaults_options; # Leading --no-defaults, --defaults-file, etc. + +$opt_example = 0; +$opt_help = 0; +$opt_log = undef(); +$opt_mysqladmin = "@bindir@/mariadb-admin"; +$opt_mysqld = "@sbindir@/mariadbd"; +$opt_no_log = 0; +$opt_password = undef(); +$opt_tcp_ip = 0; +$opt_user = "root"; +$opt_version = 0; +$opt_silent = 0; +$opt_verbose = 0; +$opt_wsrep_new_cluster = 0; + +my $my_print_defaults_exists= 1; +my $logdir= undef(); + +my ($mysqld, $mysqladmin, $groupids, $homedir, $my_progname); + +$homedir = $ENV{HOME}; +$my_progname = $0; +$my_progname =~ s/.*[\/]//; + + +if (defined($ENV{UMASK})) { + my $UMASK = $ENV{UMASK}; + my $m; + my $fmode = "0640"; + + if(($UMASK =~ m/[^0246]/) || ($UMASK =~ m/^[^0]/) || (length($UMASK) != 4)) { + printf("UMASK must be a 3-digit mode with an additional leading 0 to indicate octal.\n"); + printf("The first digit will be corrected to 6, the others may be 0, 2, 4, or 6.\n"); } + else { + $fmode= substr $UMASK, 2, 2; + $fmode= "06${fmode}"; } + + if($fmode != $UMASK) { + printf("UMASK corrected from $UMASK to $fmode ...\n"); } + + $fmode= oct($fmode); + + umask($fmode); +} + + +main(); + +#### +#### main sub routine +#### + +sub main +{ + my $flag_exit= 0; + + if (!defined(my_which(my_print_defaults))) + { + # We can't throw out yet, since --version, --help, or --example may + # have been given + print "WARNING: my_print_defaults command not found.\n"; + print "Please make sure you have this command available and\n"; + print "in your path. The command is available from the latest\n"; + print "MariaDB distribution.\n"; + $my_print_defaults_exists= 0; + } + + # Remove leading defaults options from @ARGV + while (@ARGV > 0) + { + last unless $ARGV[0] =~ + /^--(?:no-defaults$|(?:defaults-file|defaults-extra-file)=)/; + push @defaults_options, (shift @ARGV); + } + + foreach (@defaults_options) + { + $_ = quote_shell_word($_); + } + + # Add [mysqld_multi] options to front of @ARGV, ready for GetOptions() + unshift @ARGV, defaults_for_group('mysqld_multi'); + + # We've already handled --no-defaults, --defaults-file, etc. + if (!GetOptions("help", "example", "version", "mysqld=s", "mysqladmin=s", + "user=s", "password=s", "log=s", "no-log", + "tcp-ip", "silent", "verbose", "wsrep-new-cluster")) + { + $flag_exit= 1; + } + usage() if ($opt_help); + + if ($opt_verbose && $opt_silent) + { + print "Both --verbose and --silent have been given. Some of the warnings "; + print "will be disabled\nand some will be enabled.\n\n"; + } + + init_log() if (!defined($opt_log)); + $groupids = $ARGV[1]; + if ($opt_version) + { + print "$my_progname version $VER by Jani Tolonen\n"; + exit(0); + } + example() if ($opt_example); + if ($flag_exit) + { + print "Error with an option, see $my_progname --help for more info.\n"; + exit(1); + } + if (!defined(my_which(my_print_defaults))) + { + print "ABORT: Can't find command 'my_print_defaults'.\n"; + print "This command is available from the latest MariaDB\n"; + print "distribution. Please make sure you have the command\n"; + print "in your PATH.\n"; + exit(1); + } + usage() if (!defined($ARGV[0]) || + (!($ARGV[0] =~ m/^start$/i) && + !($ARGV[0] =~ m/^stop$/i) && + !($ARGV[0] =~ m/^reload$/i) && + !($ARGV[0] =~ m/^report$/i))); + + if (!$opt_no_log) + { + w2log("$my_progname log file version $VER; run: ", + "$opt_log", 1, 0); + } + else + { + print "$my_progname log file version $VER; run: "; + print strftime "%a %b %e %H:%M:%S %Y", localtime; + print "\n"; + } + if (($ARGV[0] =~ m/^start$/i) || ($ARGV[0] =~ m/^reload$/i)) + { + if (!defined(($mysqld= my_which($opt_mysqld))) && $opt_verbose) + { + print "WARNING: Couldn't find the default mysqld binary.\n"; + print "Tried: $opt_mysqld\n"; + print "This is OK, if you are using option \"mysqld=...\" in "; + print "groups [mysqldN] separately for each.\n\n"; + } + if ($ARGV[0] =~ m/^start$/i) { + start_mysqlds(); + } elsif ($ARGV[0] =~ m/^reload$/i) { + reload_mysqlds(); + } + } + else + { + if (!defined(($mysqladmin= my_which($opt_mysqladmin))) && $opt_verbose) + { + print "WARNING: Couldn't find the default mysqladmin binary.\n"; + print "Tried: $opt_mysqladmin\n"; + print "This is OK, if you are using option \"mysqladmin=...\" in "; + print "groups [mysqldN] separately for each.\n\n"; + } + if ($ARGV[0] =~ m/^report$/i) + { + report_mysqlds(); + } + else + { + stop_mysqlds(); + } + } +} + +# +# Quote word for shell +# + +sub quote_shell_word +{ + my ($option)= @_; + + $option =~ s!([^\w=./-])!\\$1!g; + return $option; +} + +#### +#### get options for a group +#### + +sub defaults_for_group +{ + my ($group) = @_; + + return () unless $my_print_defaults_exists; + + my $com= join ' ', 'my_print_defaults', @defaults_options, $group; + my @defaults = `$com`; + chomp @defaults; + return @defaults; +} + +#### +#### Init log file. Check for appropriate place for log file, in the following +#### order: my_print_defaults mysqld datadir, @localstatedir@ +#### + +sub init_log +{ + foreach my $opt (defaults_for_group('--mysqld')) + { + if ($opt =~ m/^--datadir=(.*)/ && -d "$1" && -w "$1") + { + $logdir= $1; + } + } + if (!defined($logdir)) + { + $logdir= "@localstatedir@" if (-d "@localstatedir@" && -w "@localstatedir@"); + } + if (!defined($logdir)) + { + # Log file was not specified and we could not log to a standard place, + # so log file be disabled for now. + if (!$opt_silent) + { + print "WARNING: Log file disabled. Maybe directory or file isn't writable?\n"; + } + $opt_no_log= 1; + } + else + { + $opt_log= "$logdir/mysqld_multi.log"; + } +} + +#### +#### Report living and not running MariaDB servers +#### + +sub report_mysqlds +{ + my (@groups, $com, $i, @options, $pec); + + print "Reporting MariaDB servers\n"; + if (!$opt_no_log) + { + w2log("\nReporting MariaDB servers","$opt_log",0,0); + } + @groups = &find_groups($groupids); + for ($i = 0; defined($groups[$i]); $i++) + { + $com= get_mysqladmin_options($i, @groups); + $com.= " ping >> /dev/null 2>&1"; + system($com); + $pec = $? >> 8; + if ($pec) + { + print "MariaDB server from group: $groups[$i] is not running\n"; + if (!$opt_no_log) + { + w2log("MariaDB server from group: $groups[$i] is not running", + "$opt_log", 0, 0); + } + } + else + { + print "MariaDB server from group: $groups[$i] is running\n"; + if (!$opt_no_log) + { + w2log("MariaDB server from group: $groups[$i] is running", + "$opt_log", 0, 0); + } + } + } + if (!$i) + { + print "No groups to be reported (check your GNRs)\n"; + if (!$opt_no_log) + { + w2log("No groups to be reported (check your GNRs)", "$opt_log", 0, 0); + } + } +} + +#### +#### start multiple servers +#### + +sub start_mysqlds() +{ + my (@groups, $com, $tmp, $i, @options, $j, $mysqld_found, $suffix_found, $info_sent); + + $suffix_found= 0; + + if (!$opt_no_log) + { + w2log("\nStarting MariaDB servers\n","$opt_log",0,0); + } + else + { + print "\nStarting MariaDB servers\n"; + } + @groups = &find_groups($groupids); + for ($i = 0; defined($groups[$i]); $i++) + { + @options = defaults_for_group($groups[$i]); + + $basedir_found= 0; # The default + $mysqld_found= 1; # The default + $mysqld_found= 0 if (!length($mysqld)); + $com= "$mysqld"; + + for ($j = 0, $tmp= ""; defined($options[$j]); $j++) + { + if ("--datadir=" eq substr($options[$j], 0, 10)) { + $datadir = $options[$j]; + $datadir =~ s/\-\-datadir\=//; + eval { mkpath($datadir) }; + if ($@) { + print "FATAL ERROR: Cannot create data directory $datadir: $!\n"; + exit(1); + } + if (! -d $datadir."/mysql") { + if (-w $datadir) { + print "\n\nInstalling new database in $datadir\n\n"; + $install_cmd="@bindir@/mysql_install_db "; + $install_cmd.="--user=mysql "; + $install_cmd.="--datadir=$datadir"; + system($install_cmd); + } else { + print "\n"; + print "FATAL ERROR: Tried to create mysqld under group [$groups[$i]],\n"; + print "but the data directory is not writable.\n"; + print "data directory used: $datadir\n"; + exit(1); + } + } + + if (! -d $datadir."/mysql") { + print "\n"; + print "FATAL ERROR: Tried to start mysqld under group [$groups[$i]],\n"; + print "but no data directory was found or could be created.\n"; + print "data directory used: $datadir\n"; + exit(1); + } + } + + if ("--mysqladmin=" eq substr($options[$j], 0, 13)) + { + # catch this and ignore + } + elsif ("--mysqld=" eq substr($options[$j], 0, 9)) + { + $options[$j]=~ s/\-\-mysqld\=//; + $com= $options[$j]; + $mysqld_found= 1; + } + elsif ("--basedir=" eq substr($options[$j], 0, 10)) + { + $basedir= $options[$j]; + $basedir =~ s/^--basedir=//; + $basedir_found= 1; + $options[$j]= quote_shell_word($options[$j]); + $tmp.= " $options[$j]"; + } + elsif ("--defaults-group-suffix=" eq substr($options[$j], 0, 24)) + { + $suffix_found= 1; + } + else + { + $options[$j]= quote_shell_word($options[$j]); + $tmp.= " $options[$j]"; + } + } + if ($opt_verbose && $com =~ m/\/(mariadbd-safe)$/ && !$info_sent) + { + print "WARNING: $1 is being used to start mariadbd. In this case you "; + print "may need to pass\n\"ledir=...\" under groups [mysqldN] to "; + print "$1 in order to find the actual mysqld binary.\n"; + print "ledir (library executable directory) should be the path to the "; + print "wanted mysqld binary.\n\n"; + $info_sent= 1; + } + + if (!$suffix_found) + { + $com.= " --defaults-group-suffix="; + $com.= substr($groups[$i],6); + } + + $com.= $tmp; + + if ($opt_wsrep_new_cluster) { + $com.= " --wsrep-new-cluster"; + } + + $com.= " >> $opt_log 2>&1" if (!$opt_no_log); + $com.= " &"; + if (!$mysqld_found) + { + print "\n"; + print "FATAL ERROR: Tried to start mysqld under group [$groups[$i]], "; + print "but no mysqld binary was found.\n"; + print "Please add \"mysqld=...\" in group [mysqld_multi], or add it to "; + print "group [$groups[$i]] separately.\n"; + exit(1); + } + if ($basedir_found) + { + $curdir=getcwd(); + chdir($basedir) or die "Can't change to datadir $basedir"; + } + system($com); + if ($basedir_found) + { + chdir($curdir) or die "Can't change back to original dir $curdir"; + } + } + if (!$i && !$opt_no_log) + { + w2log("No MariaDB servers to be started (check your GNRs)", + "$opt_log", 0, 0); + } +} + +#### +#### reload multiple servers +#### + +sub reload_mysqlds() +{ + my (@groups, $com, $tmp, $i, @options, $j); + + if (!$opt_no_log) + { + w2log("\nReloading MySQL servers\n","$opt_log",0,0); + } + else + { + print "\nReloading MySQL servers\n"; + } + @groups = &find_groups($groupids); + for ($i = 0; defined($groups[$i]); $i++) + { + $mysqld_server = $mysqld; + @options = defaults_for_group($groups[$i]); + + for ($j = 0, $tmp= ""; defined($options[$j]); $j++) + { + if ("--mysqladmin=" eq substr($options[$j], 0, 13)) + { + # catch this and ignore + } + elsif ("--mysqld=" eq substr($options[$j], 0, 9)) + { + $options[$j] =~ s/\-\-mysqld\=//; + $mysqld_server = $options[$j]; + } + elsif ("--pid-file=" eq substr($options[$j], 0, 11)) + { + $options[$j] =~ s/\-\-pid-file\=//; + $pid_file = $options[$j]; + } + } + $com = "killproc -p $pid_file -HUP $mysqld_server"; + system($com); + + $com = "touch $pid_file"; + system($com); + } + if (!$i && !$opt_no_log) + { + w2log("No MySQL servers to be reloaded (check your GNRs)", + "$opt_log", 0, 0); + } +} + +### +#### stop multiple servers +#### + +sub stop_mysqlds() +{ + my (@groups, $com, $i, @options); + + if (!$opt_no_log) + { + w2log("\nStopping MariaDB servers\n","$opt_log",0,0); + } + else + { + print "\nStopping MariaDB servers\n"; + } + @groups = &find_groups($groupids); + for ($i = 0; defined($groups[$i]); $i++) + { + $com= get_mysqladmin_options($i, @groups); + $com.= " shutdown"; + $com.= " >> $opt_log 2>&1" if (!$opt_no_log); + $com.= " &"; + system($com); + } + if (!$i && !$opt_no_log) + { + w2log("No MariaDB servers to be stopped (check your GNRs)", + "$opt_log", 0, 0); + } +} + +#### +#### Sub function for mysqladmin option parsing +#### + +sub get_mysqladmin_options +{ + my ($i, @groups)= @_; + my ($mysqladmin_found, $com, $tmp, $j); + + @options = defaults_for_group($groups[$i]); + + $mysqladmin_found= 1; # The default + $mysqladmin_found= 0 if (!length($mysqladmin)); + $com = "$mysqladmin"; + $tmp = " -u $opt_user"; + if (defined($opt_password)) { + my $pw= $opt_password; + # Protect single quotes in password + $pw =~ s/'/'"'"'/g; + $tmp.= " -p'$pw'"; + } + $tmp.= $opt_tcp_ip ? " -h 127.0.0.1" : ""; + for ($j = 0; defined($options[$j]); $j++) + { + if ("--mysqladmin=" eq substr($options[$j], 0, 13)) + { + $options[$j]=~ s/\-\-mysqladmin\=//; + $com= $options[$j]; + $mysqladmin_found= 1; + } + elsif ((($options[$j] =~ m/^(\-\-socket\=)(.*)$/) && !$opt_tcp_ip) || + ($options[$j] =~ m/^(\-\-port\=)(.*)$/)) + { + $tmp.= " $options[$j]"; + } + } + if (!$mysqladmin_found) + { + print "\n"; + print "FATAL ERROR: Tried to use mysqladmin in group [$groups[$i]], "; + print "but no mysqladmin binary was found.\n"; + print "Please add \"mysqladmin=...\" in group [mysqld_multi], or "; + print "in group [$groups[$i]].\n"; + exit(1); + } + $com.= $tmp; + return $com; +} + +# Return a list of option files which can be opened. Similar, but not +# identical, to behavior of my_search_option_files() +# TODO implement and use my_print_defaults --list-groups instead +sub list_defaults_files +{ + my %opt; + foreach (@defaults_options) + { + return () if /^--no-defaults$/; + $opt{$1} = $2 if /^--defaults-(extra-file|file)=(.*)$/; + } + + return ($opt{file}) if exists $opt{file}; + + my @dirs; + + # same rule as in mysys/my_default.c + if ('@sysconfdir@') { + push @dirs, '@sysconfdir@/my.cnf'; + } else { + push @dirs, '/etc/my.cnf', '/etc/mysql/my.cnf'; + } + push @dirs, "$ENV{MYSQL_HOME}/my.cnf" if $ENV{MYSQL_HOME}; + push @dirs, $opt{'extra-file'} if $opt{'extra-file'}; + push @dirs, "$ENV{HOME}/.my.cnf" if $ENV{HOME}; + + return @dirs; +} + + +# Takes a specification of GNRs (see --help), and returns a list of matching +# groups which actually are mentioned in a relevant config file +sub find_groups +{ + my ($raw_gids) = @_; + + my %gids; + my @groups; + + if (defined($raw_gids)) + { + # Make a hash of the wanted group ids + foreach my $raw_gid (split ',', $raw_gids) + { + # Match 123 or 123-456 + my ($start, $end) = ($raw_gid =~ /^\s*(\d+)(?:\s*-\s*(\d+))?\s*$/); + $end = $start if not defined $end; + if (not defined $start or $end < $start or $start < 0) + { + print "ABORT: Bad GNR: $raw_gid; see $my_progname --help\n"; + exit(1); + } + + foreach my $i ($start .. $end) + { + # Use $i + 0 to normalize numbers (002 + 0 -> 2) + $gids{$i + 0}= 1; + } + } + } + + my %seen; + my @defaults_files = list_defaults_files(); + while (@defaults_files) + { + my $file = shift @defaults_files; + next unless defined $file and not $seen{$file}++ and open CONF, '<', $file; + + while () + { + if (/^\s*\[\s*(mysqld)(\d+)\s*\]\s*$/) + { + #warn "Found a group: $1$2\n"; + # Use $2 + 0 to normalize numbers (002 + 0 -> 2) + if (not defined($raw_gids) or $gids{$2 + 0}) + { + push @groups, "$1$2"; + } + } + elsif (/^\s*!include\s+(\S.*?)\s*$/) + { + push @defaults_files, $1; + } + elsif (/^\s*!includedir\s+(\S.*?)\s*$/) + { + push @defaults_files, <$1/*.cnf>; + } + } + + close CONF; + } + return @groups; +} + +#### +#### w2log: Write to a logfile. +#### 1.arg: append to the log file (given string, or from a file. if a file, +#### file will be read from $opt_logdir) +#### 2.arg: logfile -name (w2log assumes that the logfile is in $opt_logdir). +#### 3.arg. 0 | 1, if true, print current date to the logfile. 3. arg will +#### be ignored, if 1. arg is a file. +#### 4.arg. 0 | 1, if true, first argument is a file, else a string +#### + +sub w2log +{ + my ($msg, $file, $date_flag, $is_file)= @_; + my (@data); + + open (LOGFILE, ">>$opt_log") + or die "FATAL: w2log: Couldn't open log file: $opt_log\n"; + + if ($is_file) + { + open (FROMFILE, "<$msg") && (@data=) && + close(FROMFILE) + or die "FATAL: w2log: Couldn't open file: $msg\n"; + foreach my $line (@data) + { + print LOGFILE "$line"; + } + } + else + { + print LOGFILE "$msg"; + print LOGFILE strftime "%a %b %e %H:%M:%S %Y", localtime if ($date_flag); + print LOGFILE "\n"; + } + close (LOGFILE); + return; +} + +#### +#### my_which is used, because we can't assume that every system has the +#### which -command. my_which can take only one argument at a time. +#### Return values: requested system command with the first found path, +#### or undefined, if not found. +#### + +sub my_which +{ + my ($command) = @_; + my (@paths, $path); + + # If the argument is not 'my_print_defaults' then it would be of the format + # / + return $command if ($command ne 'my_print_defaults' && -f $command && + -x $command); + + @paths = split(':', $ENV{'PATH'}); + foreach $path (@paths) + { + $path .= "/$command"; + return $path if (-f $path && -x $path); + } + return undef(); +} + + +#### +#### example +#### + +sub example +{ + print <