4
use POSIX qw(strftime);
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";
74
foreach (@defaults_options)
76
$_ = quote_shell_word($_);
79
# Add [mysqld_multi] options to front of @ARGV, ready for GetOptions()
80
unshift @ARGV, defaults_for_group('mysqld_multi');
82
# The --config-file option can be ignored; if passed on the command
83
# line, it's already handled; if specified in the configuration file,
84
# it's redundant and not useful
85
@ARGV= grep { not /^--config-file=/ } @ARGV;
87
# We've already handled --no-defaults, --defaults-file, etc.
88
if (!GetOptions("help", "example", "version", "mysqld=s", "mysqladmin=s",
89
"user=s", "password=s", "log=s", "no-log",
90
"tcp-ip", "silent", "verbose"))
94
usage() if ($opt_help);
96
if ($opt_verbose && $opt_silent)
98
print "Both --verbose and --silent have been given. Some of the warnings ";
99
print "will be disabled\nand some will be enabled.\n\n";
102
init_log() if (!defined($opt_log));
103
$groupids = $ARGV[1];
106
print "$my_progname version $VER by Jani Tolonen\n";
109
example() if ($opt_example);
112
print "Error with an option, see $my_progname --help for more info.\n";
115
if (!defined(my_which(my_print_defaults)))
117
print "ABORT: Can't find command 'my_print_defaults'.\n";
118
print "This command is available from the latest MySQL\n";
119
print "distribution. Please make sure you have the command\n";
120
print "in your PATH.\n";
123
usage() if (!defined($ARGV[0]) ||
124
(!($ARGV[0] =~ m/^start$/i) &&
125
!($ARGV[0] =~ m/^stop$/i) &&
126
!($ARGV[0] =~ m/^report$/i)));
130
w2log("$my_progname log file version $VER; run: ",
135
print "$my_progname log file version $VER; run: ";
136
print strftime "%a %b %e %H:%M:%S %Y", localtime;
139
if ($ARGV[0] =~ m/^start$/i)
141
if (!defined(($mysqld= my_which($opt_mysqld))) && $opt_verbose)
143
print "WARNING: Couldn't find the default mysqld binary.\n";
144
print "Tried: $opt_mysqld\n";
145
print "This is OK, if you are using option \"mysqld=...\" in ";
146
print "groups [mysqldN] separately for each.\n\n";
152
if (!defined(($mysqladmin= my_which($opt_mysqladmin))) && $opt_verbose)
154
print "WARNING: Couldn't find the default mysqladmin binary.\n";
155
print "Tried: $opt_mysqladmin\n";
156
print "This is OK, if you are using option \"mysqladmin=...\" in ";
157
print "groups [mysqldN] separately for each.\n\n";
159
if ($ARGV[0] =~ m/^report$/i)
171
# Quote word for shell
178
$option =~ s!([^\w=./-])!\\$1!g;
182
sub defaults_for_group
186
return () unless $my_print_defaults_exists;
188
my $com= join ' ', 'my_print_defaults', @defaults_options, $group;
189
my @defaults = `$com`;
195
#### Init log file. Check for appropriate place for log file, in the following
196
#### order: my_print_defaults mysqld datadir, @datadir@
201
foreach my $opt (defaults_for_group('mysqld'))
203
if ($opt =~ m/^--datadir=(.*)/ && -d "$1" && -w "$1")
208
if (!defined($logdir))
210
$logdir= "@datadir@" if (-d "@datadir@" && -w "@datadir@");
212
if (!defined($logdir))
214
# Log file was not specified and we could not log to a standard place,
215
# so log file be disabled for now.
218
print "WARNING: Log file disabled. Maybe directory or file isn't writable?\n";
224
$opt_log= "$logdir/mysqld_multi.log";
229
#### Report living and not running MySQL servers
234
my (@groups, $com, $i, @options, $pec);
236
print "Reporting MySQL servers\n";
239
w2log("\nReporting MySQL servers","$opt_log",0,0);
241
@groups = &find_groups($groupids);
242
for ($i = 0; defined($groups[$i]); $i++)
244
$com= get_mysqladmin_options($i, @groups);
245
$com.= " ping >> /dev/null 2>&1";
250
print "MySQL server from group: $groups[$i] is not running\n";
253
w2log("MySQL server from group: $groups[$i] is not running",
259
print "MySQL server from group: $groups[$i] is running\n";
262
w2log("MySQL server from group: $groups[$i] is running",
269
print "No groups to be reported (check your GNRs)\n";
272
w2log("No groups to be reported (check your GNRs)", "$opt_log", 0, 0);
278
#### start multiple servers
283
my (@groups, $com, $tmp, $i, @options, $j, $mysqld_found, $info_sent);
287
w2log("\nStarting MySQL servers\n","$opt_log",0,0);
291
print "\nStarting MySQL servers\n";
293
@groups = &find_groups($groupids);
294
for ($i = 0; defined($groups[$i]); $i++)
296
@options = defaults_for_group($groups[$i]);
298
$mysqld_found= 1; # The default
299
$mysqld_found= 0 if (!length($mysqld));
301
for ($j = 0, $tmp= ""; defined($options[$j]); $j++)
303
if ("--mysqladmin=" eq substr($options[$j], 0, 13))
305
# catch this and ignore
307
elsif ("--mysqld=" eq substr($options[$j], 0, 9))
309
$options[$j]=~ s/\-\-mysqld\=//;
315
$options[$j]= quote_shell_word($options[$j]);
316
$tmp.= " $options[$j]";
319
if ($opt_verbose && $com =~ m/\/safe_mysqld$/ && !$info_sent)
321
print "WARNING: safe_mysqld is being used to start mysqld. In this case you ";
322
print "may need to pass\n\"ledir=...\" under groups [mysqldN] to ";
323
print "safe_mysqld in order to find the actual mysqld binary.\n";
324
print "ledir (library executable directory) should be the path to the ";
325
print "wanted mysqld binary.\n\n";
329
$com.= " >> $opt_log 2>&1" if (!$opt_no_log);
334
print "FATAL ERROR: Tried to start mysqld under group [$groups[$i]], ";
335
print "but no mysqld binary was found.\n";
336
print "Please add \"mysqld=...\" in group [mysqld_multi], or add it to ";
337
print "group [$groups[$i]] separately.\n";
342
if (!$i && !$opt_no_log)
344
w2log("No MySQL servers to be started (check your GNRs)",
350
#### stop multiple servers
355
my (@groups, $com, $i, @options);
359
w2log("\nStopping MySQL servers\n","$opt_log",0,0);
363
print "\nStopping MySQL servers\n";
365
@groups = &find_groups($groupids);
366
for ($i = 0; defined($groups[$i]); $i++)
368
$com= get_mysqladmin_options($i, @groups);
370
$com.= " >> $opt_log 2>&1" if (!$opt_no_log);
374
if (!$i && !$opt_no_log)
376
w2log("No MySQL servers to be stopped (check your GNRs)",
382
#### Sub function for mysqladmin option parsing
385
sub get_mysqladmin_options
387
my ($i, @groups)= @_;
388
my ($mysqladmin_found, $com, $tmp, $j);
390
@options = defaults_for_group($groups[$i]);
392
$mysqladmin_found= 1; # The default
393
$mysqladmin_found= 0 if (!length($mysqladmin));
394
$com = "$mysqladmin";
395
$tmp = " -u $opt_user";
396
if (defined($opt_password)) {
397
my $pw= $opt_password;
398
# Protect single quotes in password
402
$tmp.= $opt_tcp_ip ? " -h 127.0.0.1" : "";
403
for ($j = 0; defined($options[$j]); $j++)
405
if ("--mysqladmin=" eq substr($options[$j], 0, 13))
407
$options[$j]=~ s/\-\-mysqladmin\=//;
409
$mysqladmin_found= 1;
411
elsif ((($options[$j] =~ m/^(\-\-socket\=)(.*)$/) && !$opt_tcp_ip) ||
412
($options[$j] =~ m/^(\-\-port\=)(.*)$/))
414
$tmp.= " $options[$j]";
417
if (!$mysqladmin_found)
420
print "FATAL ERROR: Tried to use mysqladmin in group [$groups[$i]], ";
421
print "but no mysqladmin binary was found.\n";
422
print "Please add \"mysqladmin=...\" in group [mysqld_multi], or ";
423
print "in group [$groups[$i]].\n";
430
# Return a list of option files which can be opened. Similar, but not
431
# identical, to behavior of my_search_option_files()
432
sub list_defaults_files
435
foreach (@defaults_options)
437
return () if /^--no-defaults$/;
438
$opt{$1} = $2 if /^--defaults-(extra-file|file)=(.*)$/;
441
return ($opt{file}) if exists $opt{file};
443
my %seen; # Don't list the same file more than once
444
return grep { defined $_ and not $seen{$_}++ and -f $_ and -r $_ }
447
'@sysconfdir@/my.cnf',
448
($ENV{MYSQL_HOME} ? "$ENV{MYSQL_HOME}/my.cnf" : undef),
450
($ENV{HOME} ? "$ENV{HOME}/.my.cnf" : undef));
454
# Takes a specification of GNRs (see --help), and returns a list of matching
455
# groups which actually are mentioned in a relevant config file
463
if (defined($raw_gids))
465
# Make a hash of the wanted group ids
466
foreach my $raw_gid (split ',', $raw_gids)
468
# Match 123 or 123-456
469
my ($start, $end) = ($raw_gid =~ /^\s*(\d+)(?:\s*-\s*(\d+))?\s*$/);
470
$end = $start if not defined $end;
471
if (not defined $start or $end < $start or $start < 0)
473
print "ABORT: Bad GNR: $raw_gid; see $my_progname --help\n";
477
foreach my $i ($start .. $end)
479
# Use $i + 0 to normalize numbers (002 + 0 -> 2)
485
my @defaults_files = list_defaults_files();
486
#warn "@{[sort keys %gids]} -> @defaults_files\n";
487
foreach my $file (@defaults_files)
489
next unless open CONF, "< $file";
493
if (/^\s*\[\s*(mysqld)(\d+)\s*\]\s*$/)
495
#warn "Found a group: $1$2\n";
496
# Use $2 + 0 to normalize numbers (002 + 0 -> 2)
497
if (not defined($raw_gids) or $gids{$2 + 0})
499
push @groups, "$1$2";
510
#### w2log: Write to a logfile.
511
#### 1.arg: append to the log file (given string, or from a file. if a file,
512
#### file will be read from $opt_logdir)
513
#### 2.arg: logfile -name (w2log assumes that the logfile is in $opt_logdir).
514
#### 3.arg. 0 | 1, if true, print current date to the logfile. 3. arg will
515
#### be ignored, if 1. arg is a file.
516
#### 4.arg. 0 | 1, if true, first argument is a file, else a string
521
my ($msg, $file, $date_flag, $is_file)= @_;
524
open (LOGFILE, ">>$opt_log")
525
or die "FATAL: w2log: Couldn't open log file: $opt_log\n";
529
open (FROMFILE, "<$msg") && (@data=<FROMFILE>) &&
531
or die "FATAL: w2log: Couldn't open file: $msg\n";
532
foreach my $line (@data)
534
print LOGFILE "$line";
539
print LOGFILE "$msg";
540
print LOGFILE strftime "%a %b %e %H:%M:%S %Y", localtime if ($date_flag);
548
#### my_which is used, because we can't assume that every system has the
549
#### which -command. my_which can take only one argument at a time.
550
#### Return values: requested system command with the first found path,
551
#### or undefined, if not found.
559
return $command if (-f $command && -x $command);
560
@paths = split(':', $ENV{'PATH'});
561
foreach $path (@paths)
563
$path .= "/$command";
564
return $path if (-f $path && -x $path);
577
# This is an example of a my.cnf file for $my_progname.
578
# Usually this file is located in home dir ~/.my.cnf or /etc/my.cnf
580
# SOME IMPORTANT NOTES FOLLOW:
584
# Make sure that the MySQL user, who is stopping the mysqld services, has
585
# the same password to all MySQL servers being accessed by $my_progname.
586
# This user needs to have the 'Shutdown_priv' -privilege, but for security
587
# reasons should have no other privileges. It is advised that you create a
588
# common 'multi_admin' user for all MySQL servers being controlled by
589
# $my_progname. Here is an example how to do it:
591
# GRANT SHUTDOWN ON *.* TO multi_admin\@localhost IDENTIFIED BY 'password'
593
# You will need to apply the above to all MySQL servers that are being
594
# controlled by $my_progname. 'multi_admin' will shutdown the servers
595
# using 'mysqladmin' -binary, when '$my_progname stop' is being called.
599
# If you are using mysqld_safe to start mysqld, make sure that every
600
# MySQL server has a separate pid-file. In order to use mysqld_safe
601
# via $my_progname, you need to use two options:
603
# mysqld=/path/to/mysqld_safe
604
# ledir=/path/to/mysqld-binary/
606
# ledir (library executable directory), is an option that only mysqld_safe
607
# accepts, so you will get an error if you try to pass it to mysqld directly.
608
# For this reason you might want to use the above options within [mysqld#]
613
# It is NOT advised to run many MySQL servers within the same data directory.
614
# You can do so, but please make sure to understand and deal with the
615
# underlying caveats. In short they are:
617
# - Risk of table/data corruption
618
# - Data synchronising problems between the running servers
619
# - Heavily media (disk) bound
620
# - Relies on the system (external) file locking
621
# - Is not applicable with all table types. (Such as InnoDB)
622
# Trying so will end up with undesirable results.
626
# Every server requires one and it must be unique.
630
# In the example below the first and the fifth mysqld group was
631
# intentionally left out. You may have 'gaps' in the config file. This
632
# gives you more flexibility.
634
# 6.MySQL Server User
636
# You can pass the user=... option inside [mysqld#] groups. This
637
# can be very handy in some cases, but then you need to run $my_progname
640
# 7.A Start-up Manage Script for $my_progname
642
# In the recent MySQL distributions you can find a file called
643
# mysqld_multi.server.sh. It is a wrapper for $my_progname. This can
644
# be used to start and stop multiple servers during boot and shutdown.
646
# You can place the file in /etc/init.d/mysqld_multi.server.sh and
647
# make the needed symbolic links to it from various run levels
648
# (as per Linux/Unix standard). You may even replace the
649
# /etc/init.d/mysql.server script with it.
651
# Before using, you must create a my.cnf file either in @sysconfdir@/my.cnf
652
# or /root/.my.cnf and add the [mysqld_multi] and [mysqld#] groups.
654
# The script can be found from support-files/mysqld_multi.server.sh
655
# in MySQL distribution. (Verify the script before using)
659
mysqld = @bindir@/mysqld_safe
660
mysqladmin = @bindir@/mysqladmin
662
password = my_password
665
socket = /tmp/mysql.sock2
667
pid-file = @localstatedir@2/hostname.pid2
668
datadir = @localstatedir@2
669
language = @datadir@/mysql/english
673
mysqld = /path/to/safe_mysqld/safe_mysqld
674
ledir = /path/to/mysqld-binary/
675
mysqladmin = /path/to/mysqladmin/mysqladmin
676
socket = /tmp/mysql.sock3
678
pid-file = @localstatedir@3/hostname.pid3
679
datadir = @localstatedir@3
680
language = @datadir@/mysql/swedish
684
socket = /tmp/mysql.sock4
686
pid-file = @localstatedir@4/hostname.pid4
687
datadir = @localstatedir@4
688
language = @datadir@/mysql/estonia
692
socket = /tmp/mysql.sock6
694
pid-file = @localstatedir@6/hostname.pid6
695
datadir = @localstatedir@6
696
language = @datadir@/mysql/japanese
709
$my_progname version $VER by Jani Tolonen
712
$my_progname can be used to start, or stop any number of separate
713
mysqld processes running in different TCP/IP ports and UNIX sockets.
715
$my_progname can read group [mysqld_multi] from my.cnf file. You may
716
want to put options mysqld=... and mysqladmin=... there. Since
717
version 2.10 these options can also be given under groups [mysqld#],
718
which gives more control over different versions. One can have the
719
default mysqld and mysqladmin under group [mysqld_multi], but this is
720
not mandatory. Please note that if mysqld or mysqladmin is missing
721
from both [mysqld_multi] and [mysqld#], a group that is tried to be
722
used, $my_progname will abort with an error.
724
$my_progname will search for groups named [mysqld#] from my.cnf (or
725
the given --config-file=...), where '#' can be any positive integer
726
starting from 1. These groups should be the same as the regular
727
[mysqld] group, but with those port, socket and any other options
728
that are to be used with each separate mysqld process. The number
729
in the group name has another function; it can be used for starting,
730
stopping, or reporting any specific mysqld server.
732
Usage: $my_progname [OPTIONS] {start|stop|report} [GNR,GNR,GNR...]
733
or $my_progname [OPTIONS] {start|stop|report} [GNR-GNR,GNR,GNR-GNR,...]
735
The GNR means the group number. You can start, stop or report any GNR,
736
or several of them at the same time. (See --example) The GNRs list can
737
be comma separated or a dash combined. The latter means that all the
738
GNRs between GNR1-GNR2 will be affected. Without GNR argument all the
739
groups found will either be started, stopped, or reported. Note that
740
syntax for specifying GNRs must appear without spaces.
744
These options must be given before any others:
745
--no-defaults Do not read any defaults file
746
--defaults-file=... Read only this configuration file, do not read the
747
standard system-wide and user-specific files
748
--defaults-extra-file=... Read this configuration file in addition to the
749
standard system-wide and user-specific files
750
Using: @{[join ' ', @defaults_options]}
752
--config-file=... Deprecated, please use --defaults-extra-file instead
753
--example Give an example of a config file with extra information.
754
--help Print this help and exit.
755
--log=... Log file. Full path to and the name for the log file. NOTE:
756
If the file exists, everything will be appended.
758
--mysqladmin=... mysqladmin binary to be used for a server shutdown.
759
Since version 2.10 this can be given within groups [mysqld#]
761
--mysqld=... mysqld binary to be used. Note that you can give mysqld_safe
762
to this option also. The options are passed to mysqld. Just
763
make sure you have mysqld in your PATH or fix mysqld_safe.
765
Please note: Since mysqld_multi version 2.3 you can also
766
give this option inside groups [mysqld#] in ~/.my.cnf,
767
where '#' stands for an integer (number) of the group in
768
question. This will be recognised as a special option and
769
will not be passed to the mysqld. This will allow one to
770
start different mysqld versions with mysqld_multi.
771
--no-log Print to stdout instead of the log file. By default the log
773
--password=... Password for mysqladmin user.
774
--silent Disable warnings.
775
--tcp-ip Connect to the MySQL server(s) via the TCP/IP port instead
776
of the UNIX socket. This affects stopping and reporting.
777
If a socket file is missing, the server may still be
778
running, but can be accessed only via the TCP/IP port.
779
By default connecting is done via the UNIX socket.
780
--user=... mysqladmin user. Using: $opt_user
781
--verbose Be more verbose.
782
--version Print the version number and exit.