4
use POSIX qw(strftime getcwd);
9
my @defaults_options; # Leading --no-defaults, --defaults-file, etc.
14
$opt_mysqladmin = "@bindir@/mysqladmin";
15
$opt_mysqld = "@libexecdir@/mysqld";
17
$opt_password = undef();
24
my $my_print_defaults_exists= 1;
27
my ($mysqld, $mysqladmin, $groupids, $homedir, $my_progname);
29
$homedir = $ENV{HOME};
31
$my_progname =~ s/.*[\/]//;
43
if (!defined(my_which(my_print_defaults)))
45
# We can't throw out yet, since --version, --help, or --example may
47
print "WARNING: my_print_defaults command not found.\n";
48
print "Please make sure you have this command available and\n";
49
print "in your path. The command is available from the latest\n";
50
print "MySQL distribution.\n";
51
$my_print_defaults_exists= 0;
54
# Remove leading defaults options from @ARGV
57
last unless $ARGV[0] =~
58
/^--(?:no-defaults$|(?:defaults-file|defaults-extra-file)=)/;
59
push @defaults_options, (shift @ARGV);
62
# Handle deprecated --config-file option: convert to --defaults-extra-file
63
foreach my $arg (@ARGV)
65
if ($arg =~ m/^--config-file=(.*)/)
67
# Put it at the beginning of the list, so it has lower precedence
68
# than a correct --defaults-extra-file option
70
unshift @defaults_options, "--defaults-extra-file=$1";
71
print "WARNING: --config-file is deprecated and will be removed\n";
72
print "in MySQL 5.6. Please use --defaults-extra-file instead\n";
76
foreach (@defaults_options)
78
$_ = quote_shell_word($_);
81
# Add [mysqld_multi] options to front of @ARGV, ready for GetOptions()
82
unshift @ARGV, defaults_for_group('mysqld_multi');
84
# The --config-file option can be ignored; if passed on the command
85
# line, it's already handled; if specified in the configuration file,
86
# it's redundant and not useful
87
@ARGV= grep { not /^--config-file=/ } @ARGV;
89
# We've already handled --no-defaults, --defaults-file, etc.
90
if (!GetOptions("help", "example", "version", "mysqld=s", "mysqladmin=s",
91
"user=s", "password=s", "log=s", "no-log",
92
"tcp-ip", "silent", "verbose"))
96
usage() if ($opt_help);
98
if ($opt_verbose && $opt_silent)
100
print "Both --verbose and --silent have been given. Some of the warnings ";
101
print "will be disabled\nand some will be enabled.\n\n";
104
init_log() if (!defined($opt_log));
105
$groupids = $ARGV[1];
108
print "$my_progname version $VER by Jani Tolonen\n";
111
example() if ($opt_example);
114
print "Error with an option, see $my_progname --help for more info.\n";
117
if (!defined(my_which(my_print_defaults)))
119
print "ABORT: Can't find command 'my_print_defaults'.\n";
120
print "This command is available from the latest MySQL\n";
121
print "distribution. Please make sure you have the command\n";
122
print "in your PATH.\n";
125
usage() if (!defined($ARGV[0]) ||
126
(!($ARGV[0] =~ m/^start$/i) &&
127
!($ARGV[0] =~ m/^stop$/i) &&
128
!($ARGV[0] =~ m/^report$/i)));
132
w2log("$my_progname log file version $VER; run: ",
137
print "$my_progname log file version $VER; run: ";
138
print strftime "%a %b %e %H:%M:%S %Y", localtime;
141
if ($ARGV[0] =~ m/^start$/i)
143
if (!defined(($mysqld= my_which($opt_mysqld))) && $opt_verbose)
145
print "WARNING: Couldn't find the default mysqld binary.\n";
146
print "Tried: $opt_mysqld\n";
147
print "This is OK, if you are using option \"mysqld=...\" in ";
148
print "groups [mysqldN] separately for each.\n\n";
154
if (!defined(($mysqladmin= my_which($opt_mysqladmin))) && $opt_verbose)
156
print "WARNING: Couldn't find the default mysqladmin binary.\n";
157
print "Tried: $opt_mysqladmin\n";
158
print "This is OK, if you are using option \"mysqladmin=...\" in ";
159
print "groups [mysqldN] separately for each.\n\n";
161
if ($ARGV[0] =~ m/^report$/i)
173
# Quote word for shell
180
$option =~ s!([^\w=./-])!\\$1!g;
184
sub defaults_for_group
188
return () unless $my_print_defaults_exists;
190
my $com= join ' ', 'my_print_defaults', @defaults_options, $group;
191
my @defaults = `$com`;
197
#### Init log file. Check for appropriate place for log file, in the following
198
#### order: my_print_defaults mysqld datadir, @datadir@
203
foreach my $opt (defaults_for_group('mysqld'))
205
if ($opt =~ m/^--datadir=(.*)/ && -d "$1" && -w "$1")
210
if (!defined($logdir))
212
$logdir= "@datadir@" if (-d "@datadir@" && -w "@datadir@");
214
if (!defined($logdir))
216
# Log file was not specified and we could not log to a standard place,
217
# so log file be disabled for now.
220
print "WARNING: Log file disabled. Maybe directory or file isn't writable?\n";
226
$opt_log= "$logdir/mysqld_multi.log";
231
#### Report living and not running MySQL servers
236
my (@groups, $com, $i, @options, $pec);
238
print "Reporting MySQL servers\n";
241
w2log("\nReporting MySQL servers","$opt_log",0,0);
243
@groups = &find_groups($groupids);
244
for ($i = 0; defined($groups[$i]); $i++)
246
$com= get_mysqladmin_options($i, @groups);
247
$com.= " ping >> /dev/null 2>&1";
252
print "MySQL server from group: $groups[$i] is not running\n";
255
w2log("MySQL server from group: $groups[$i] is not running",
261
print "MySQL server from group: $groups[$i] is running\n";
264
w2log("MySQL server from group: $groups[$i] is running",
271
print "No groups to be reported (check your GNRs)\n";
274
w2log("No groups to be reported (check your GNRs)", "$opt_log", 0, 0);
280
#### start multiple servers
285
my (@groups, $com, $tmp, $i, @options, $j, $mysqld_found, $info_sent);
289
w2log("\nStarting MySQL servers\n","$opt_log",0,0);
293
print "\nStarting MySQL servers\n";
295
@groups = &find_groups($groupids);
296
for ($i = 0; defined($groups[$i]); $i++)
298
@options = defaults_for_group($groups[$i]);
300
$basedir_found= 0; # The default
301
$mysqld_found= 1; # The default
302
$mysqld_found= 0 if (!length($mysqld));
304
for ($j = 0, $tmp= ""; defined($options[$j]); $j++)
306
if ("--mysqladmin=" eq substr($options[$j], 0, 13))
308
# catch this and ignore
310
elsif ("--mysqld=" eq substr($options[$j], 0, 9))
312
$options[$j]=~ s/\-\-mysqld\=//;
316
elsif ("--basedir=" eq substr($options[$j], 0, 10))
318
$basedir= $options[$j];
319
$basedir =~ s/^--basedir=//;
321
$options[$j]= quote_shell_word($options[$j]);
322
$tmp.= " $options[$j]";
326
$options[$j]= quote_shell_word($options[$j]);
327
$tmp.= " $options[$j]";
330
if ($opt_verbose && $com =~ m/\/(safe_mysqld|mysqld_safe)$/ && !$info_sent)
332
print "WARNING: $1 is being used to start mysqld. In this case you ";
333
print "may need to pass\n\"ledir=...\" under groups [mysqldN] to ";
334
print "$1 in order to find the actual mysqld binary.\n";
335
print "ledir (library executable directory) should be the path to the ";
336
print "wanted mysqld binary.\n\n";
340
$com.= " >> $opt_log 2>&1" if (!$opt_no_log);
345
print "FATAL ERROR: Tried to start mysqld under group [$groups[$i]], ";
346
print "but no mysqld binary was found.\n";
347
print "Please add \"mysqld=...\" in group [mysqld_multi], or add it to ";
348
print "group [$groups[$i]] separately.\n";
354
chdir($basedir) or die "Can't change to datadir $basedir";
359
chdir($curdir) or die "Can't change back to original dir $curdir";
362
if (!$i && !$opt_no_log)
364
w2log("No MySQL servers to be started (check your GNRs)",
370
#### stop multiple servers
375
my (@groups, $com, $i, @options);
379
w2log("\nStopping MySQL servers\n","$opt_log",0,0);
383
print "\nStopping MySQL servers\n";
385
@groups = &find_groups($groupids);
386
for ($i = 0; defined($groups[$i]); $i++)
388
$com= get_mysqladmin_options($i, @groups);
390
$com.= " >> $opt_log 2>&1" if (!$opt_no_log);
394
if (!$i && !$opt_no_log)
396
w2log("No MySQL servers to be stopped (check your GNRs)",
402
#### Sub function for mysqladmin option parsing
405
sub get_mysqladmin_options
407
my ($i, @groups)= @_;
408
my ($mysqladmin_found, $com, $tmp, $j);
410
@options = defaults_for_group($groups[$i]);
412
$mysqladmin_found= 1; # The default
413
$mysqladmin_found= 0 if (!length($mysqladmin));
414
$com = "$mysqladmin";
415
$tmp = " -u $opt_user";
416
if (defined($opt_password)) {
417
my $pw= $opt_password;
418
# Protect single quotes in password
422
$tmp.= $opt_tcp_ip ? " -h 127.0.0.1" : "";
423
for ($j = 0; defined($options[$j]); $j++)
425
if ("--mysqladmin=" eq substr($options[$j], 0, 13))
427
$options[$j]=~ s/\-\-mysqladmin\=//;
429
$mysqladmin_found= 1;
431
elsif ((($options[$j] =~ m/^(\-\-socket\=)(.*)$/) && !$opt_tcp_ip) ||
432
($options[$j] =~ m/^(\-\-port\=)(.*)$/))
434
$tmp.= " $options[$j]";
437
if (!$mysqladmin_found)
440
print "FATAL ERROR: Tried to use mysqladmin in group [$groups[$i]], ";
441
print "but no mysqladmin binary was found.\n";
442
print "Please add \"mysqladmin=...\" in group [mysqld_multi], or ";
443
print "in group [$groups[$i]].\n";
450
# Return a list of option files which can be opened. Similar, but not
451
# identical, to behavior of my_search_option_files()
452
sub list_defaults_files
455
foreach (@defaults_options)
457
return () if /^--no-defaults$/;
458
$opt{$1} = $2 if /^--defaults-(extra-file|file)=(.*)$/;
461
return ($opt{file}) if exists $opt{file};
463
my %seen; # Don't list the same file more than once
464
return grep { defined $_ and not $seen{$_}++ and -f $_ and -r $_ }
467
'@sysconfdir@/my.cnf',
468
($ENV{MYSQL_HOME} ? "$ENV{MYSQL_HOME}/my.cnf" : undef),
470
($ENV{HOME} ? "$ENV{HOME}/.my.cnf" : undef));
474
# Takes a specification of GNRs (see --help), and returns a list of matching
475
# groups which actually are mentioned in a relevant config file
483
if (defined($raw_gids))
485
# Make a hash of the wanted group ids
486
foreach my $raw_gid (split ',', $raw_gids)
488
# Match 123 or 123-456
489
my ($start, $end) = ($raw_gid =~ /^\s*(\d+)(?:\s*-\s*(\d+))?\s*$/);
490
$end = $start if not defined $end;
491
if (not defined $start or $end < $start or $start < 0)
493
print "ABORT: Bad GNR: $raw_gid; see $my_progname --help\n";
497
foreach my $i ($start .. $end)
499
# Use $i + 0 to normalize numbers (002 + 0 -> 2)
505
my @defaults_files = list_defaults_files();
506
#warn "@{[sort keys %gids]} -> @defaults_files\n";
507
foreach my $file (@defaults_files)
509
next unless open CONF, "< $file";
513
if (/^\s*\[\s*(mysqld)(\d+)\s*\]\s*$/)
515
#warn "Found a group: $1$2\n";
516
# Use $2 + 0 to normalize numbers (002 + 0 -> 2)
517
if (not defined($raw_gids) or $gids{$2 + 0})
519
push @groups, "$1$2";
530
#### w2log: Write to a logfile.
531
#### 1.arg: append to the log file (given string, or from a file. if a file,
532
#### file will be read from $opt_logdir)
533
#### 2.arg: logfile -name (w2log assumes that the logfile is in $opt_logdir).
534
#### 3.arg. 0 | 1, if true, print current date to the logfile. 3. arg will
535
#### be ignored, if 1. arg is a file.
536
#### 4.arg. 0 | 1, if true, first argument is a file, else a string
541
my ($msg, $file, $date_flag, $is_file)= @_;
544
open (LOGFILE, ">>$opt_log")
545
or die "FATAL: w2log: Couldn't open log file: $opt_log\n";
549
open (FROMFILE, "<$msg") && (@data=<FROMFILE>) &&
551
or die "FATAL: w2log: Couldn't open file: $msg\n";
552
foreach my $line (@data)
554
print LOGFILE "$line";
559
print LOGFILE "$msg";
560
print LOGFILE strftime "%a %b %e %H:%M:%S %Y", localtime if ($date_flag);
568
#### my_which is used, because we can't assume that every system has the
569
#### which -command. my_which can take only one argument at a time.
570
#### Return values: requested system command with the first found path,
571
#### or undefined, if not found.
579
return $command if (-f $command && -x $command);
580
@paths = split(':', $ENV{'PATH'});
581
foreach $path (@paths)
583
$path .= "/$command";
584
return $path if (-f $path && -x $path);
597
# This is an example of a my.cnf file for $my_progname.
598
# Usually this file is located in home dir ~/.my.cnf or /etc/my.cnf
600
# SOME IMPORTANT NOTES FOLLOW:
604
# Make sure that the MySQL user, who is stopping the mysqld services, has
605
# the same password to all MySQL servers being accessed by $my_progname.
606
# This user needs to have the 'Shutdown_priv' -privilege, but for security
607
# reasons should have no other privileges. It is advised that you create a
608
# common 'multi_admin' user for all MySQL servers being controlled by
609
# $my_progname. Here is an example how to do it:
611
# GRANT SHUTDOWN ON *.* TO multi_admin\@localhost IDENTIFIED BY 'password'
613
# You will need to apply the above to all MySQL servers that are being
614
# controlled by $my_progname. 'multi_admin' will shutdown the servers
615
# using 'mysqladmin' -binary, when '$my_progname stop' is being called.
619
# If you are using mysqld_safe to start mysqld, make sure that every
620
# MySQL server has a separate pid-file. In order to use mysqld_safe
621
# via $my_progname, you need to use two options:
623
# mysqld=/path/to/mysqld_safe
624
# ledir=/path/to/mysqld-binary/
626
# ledir (library executable directory), is an option that only mysqld_safe
627
# accepts, so you will get an error if you try to pass it to mysqld directly.
628
# For this reason you might want to use the above options within [mysqld#]
633
# It is NOT advised to run many MySQL servers within the same data directory.
634
# You can do so, but please make sure to understand and deal with the
635
# underlying caveats. In short they are:
637
# - Risk of table/data corruption
638
# - Data synchronising problems between the running servers
639
# - Heavily media (disk) bound
640
# - Relies on the system (external) file locking
641
# - Is not applicable with all table types. (Such as InnoDB)
642
# Trying so will end up with undesirable results.
646
# Every server requires one and it must be unique.
650
# In the example below the first and the fifth mysqld group was
651
# intentionally left out. You may have 'gaps' in the config file. This
652
# gives you more flexibility.
654
# 6.MySQL Server User
656
# You can pass the user=... option inside [mysqld#] groups. This
657
# can be very handy in some cases, but then you need to run $my_progname
660
# 7.A Start-up Manage Script for $my_progname
662
# In the recent MySQL distributions you can find a file called
663
# mysqld_multi.server.sh. It is a wrapper for $my_progname. This can
664
# be used to start and stop multiple servers during boot and shutdown.
666
# You can place the file in /etc/init.d/mysqld_multi.server.sh and
667
# make the needed symbolic links to it from various run levels
668
# (as per Linux/Unix standard). You may even replace the
669
# /etc/init.d/mysql.server script with it.
671
# Before using, you must create a my.cnf file either in @sysconfdir@/my.cnf
672
# or /root/.my.cnf and add the [mysqld_multi] and [mysqld#] groups.
674
# The script can be found from support-files/mysqld_multi.server.sh
675
# in MySQL distribution. (Verify the script before using)
679
mysqld = @bindir@/mysqld_safe
680
mysqladmin = @bindir@/mysqladmin
682
password = my_password
685
socket = /tmp/mysql.sock2
687
pid-file = @localstatedir@2/hostname.pid2
688
datadir = @localstatedir@2
689
language = @datadir@/mysql/english
693
mysqld = /path/to/mysqld_safe
694
ledir = /path/to/mysqld-binary/
695
mysqladmin = /path/to/mysqladmin
696
socket = /tmp/mysql.sock3
698
pid-file = @localstatedir@3/hostname.pid3
699
datadir = @localstatedir@3
700
language = @datadir@/mysql/swedish
704
socket = /tmp/mysql.sock4
706
pid-file = @localstatedir@4/hostname.pid4
707
datadir = @localstatedir@4
708
language = @datadir@/mysql/estonia
712
socket = /tmp/mysql.sock6
714
pid-file = @localstatedir@6/hostname.pid6
715
datadir = @localstatedir@6
716
language = @datadir@/mysql/japanese
729
$my_progname version $VER by Jani Tolonen
732
$my_progname can be used to start, or stop any number of separate
733
mysqld processes running in different TCP/IP ports and UNIX sockets.
735
$my_progname can read group [mysqld_multi] from my.cnf file. You may
736
want to put options mysqld=... and mysqladmin=... there. Since
737
version 2.10 these options can also be given under groups [mysqld#],
738
which gives more control over different versions. One can have the
739
default mysqld and mysqladmin under group [mysqld_multi], but this is
740
not mandatory. Please note that if mysqld or mysqladmin is missing
741
from both [mysqld_multi] and [mysqld#], a group that is tried to be
742
used, $my_progname will abort with an error.
744
$my_progname will search for groups named [mysqld#] from my.cnf (or
745
the given --config-file=...), where '#' can be any positive integer
746
starting from 1. These groups should be the same as the regular
747
[mysqld] group, but with those port, socket and any other options
748
that are to be used with each separate mysqld process. The number
749
in the group name has another function; it can be used for starting,
750
stopping, or reporting any specific mysqld server.
752
Usage: $my_progname [OPTIONS] {start|stop|report} [GNR,GNR,GNR...]
753
or $my_progname [OPTIONS] {start|stop|report} [GNR-GNR,GNR,GNR-GNR,...]
755
The GNR means the group number. You can start, stop or report any GNR,
756
or several of them at the same time. (See --example) The GNRs list can
757
be comma separated or a dash combined. The latter means that all the
758
GNRs between GNR1-GNR2 will be affected. Without GNR argument all the
759
groups found will either be started, stopped, or reported. Note that
760
syntax for specifying GNRs must appear without spaces.
764
These options must be given before any others:
765
--no-defaults Do not read any defaults file
766
--defaults-file=... Read only this configuration file, do not read the
767
standard system-wide and user-specific files
768
--defaults-extra-file=... Read this configuration file in addition to the
769
standard system-wide and user-specific files
770
Using: @{[join ' ', @defaults_options]}
772
--config-file=... Deprecated, please use --defaults-extra-file instead
773
--example Give an example of a config file with extra information.
774
--help Print this help and exit.
775
--log=... Log file. Full path to and the name for the log file. NOTE:
776
If the file exists, everything will be appended.
778
--mysqladmin=... mysqladmin binary to be used for a server shutdown.
779
Since version 2.10 this can be given within groups [mysqld#]
781
--mysqld=... mysqld binary to be used. Note that you can give mysqld_safe
782
to this option also. The options are passed to mysqld. Just
783
make sure you have mysqld in your PATH or fix mysqld_safe.
785
Please note: Since mysqld_multi version 2.3 you can also
786
give this option inside groups [mysqld#] in ~/.my.cnf,
787
where '#' stands for an integer (number) of the group in
788
question. This will be recognised as a special option and
789
will not be passed to the mysqld. This will allow one to
790
start different mysqld versions with mysqld_multi.
791
--no-log Print to stdout instead of the log file. By default the log
793
--password=... Password for mysqladmin user.
794
--silent Disable warnings.
795
--tcp-ip Connect to the MySQL server(s) via the TCP/IP port instead
796
of the UNIX socket. This affects stopping and reporting.
797
If a socket file is missing, the server may still be
798
running, but can be accessed only via the TCP/IP port.
799
By default connecting is done via the UNIX socket.
800
--user=... mysqladmin user. Using: $opt_user
801
--verbose Be more verbose.
802
--version Print the version number and exit.