1#!@PERL_PATH@
2
3# Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License, version 2.0,
7# as published by the Free Software Foundation.
8#
9# This program is also distributed with certain software (including
10# but not limited to OpenSSL) that is licensed under separate terms,
11# as designated in a particular file or component or in included license
12# documentation.  The authors of MySQL hereby grant you an additional
13# permission to link the program and your derivative works with the
14# separately licensed software that they have included with MySQL.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19# GNU General Public License, version 2.0, for more details.
20#
21# You should have received a copy of the GNU Library General Public
22# License along with this library; if not, write to the Free
23# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
24# MA 02110-1301, USA
25
26use Getopt::Long;
27use POSIX qw(strftime getcwd);
28use File::Path qw(mkpath);
29
30$|=1;
31$VER="2.16";
32
33my @defaults_options;   #  Leading --no-defaults, --defaults-file, etc.
34
35$opt_example       = 0;
36$opt_help          = 0;
37$opt_log           = undef();
38$opt_mysqladmin    = "@bindir@/mysqladmin";
39$opt_mysqld        = "@libexecdir@/mysqld";
40$opt_no_log        = 0;
41$opt_password      = undef();
42$opt_tcp_ip        = 0;
43$opt_user          = "root";
44$opt_version       = 0;
45$opt_silent        = 0;
46$opt_verbose       = 0;
47
48my $my_print_defaults_exists= 1;
49my $logdir= undef();
50
51my ($mysqld, $mysqladmin, $groupids, $homedir, $my_progname);
52
53$homedir = $ENV{HOME};
54$my_progname = $0;
55$my_progname =~ s/.*[\/]//;
56
57
58if (defined($ENV{UMASK})) {
59  my $UMASK = $ENV{UMASK};
60  my $m;
61  my $fmode = "0640";
62
63  if(($UMASK =~ m/[^0246]/) || ($UMASK =~ m/^[^0]/) || (length($UMASK) != 4)) {
64    printf("UMASK must be a 3-digit mode with an additional leading 0 to indicate octal.\n");
65    printf("The first digit will be corrected to 6, the others may be 0, 2, 4, or 6.\n"); }
66  else {
67    $fmode= substr $UMASK, 2, 2;
68    $fmode= "06${fmode}"; }
69
70  if($fmode != $UMASK) {
71    printf("UMASK corrected from $UMASK to $fmode ...\n"); }
72
73  $fmode= oct($fmode);
74
75  umask($fmode);
76}
77
78
79main();
80
81####
82#### main sub routine
83####
84
85sub main
86{
87  my $flag_exit= 0;
88
89  if (!defined(my_which(my_print_defaults)))
90  {
91    # We can't throw out yet, since --version, --help, or --example may
92    # have been given
93    print "WARNING: my_print_defaults command not found.\n";
94    print "Please make sure you have this command available and\n";
95    print "in your path. The command is available from the latest\n";
96    print "MySQL distribution.\n";
97    $my_print_defaults_exists= 0;
98  }
99
100  # Remove leading defaults options from @ARGV
101  while (@ARGV > 0)
102  {
103    last unless $ARGV[0] =~
104      /^--(?:no-defaults$|(?:defaults-file|defaults-extra-file)=)/;
105    push @defaults_options, (shift @ARGV);
106  }
107
108  foreach (@defaults_options)
109  {
110    $_ = quote_shell_word($_);
111  }
112
113  # Add [mysqld_multi] options to front of @ARGV, ready for GetOptions()
114  unshift @ARGV, defaults_for_group('mysqld_multi');
115
116  # We've already handled --no-defaults, --defaults-file, etc.
117  if (!GetOptions("help", "example", "version", "mysqld=s", "mysqladmin=s",
118                  "user=s", "password=s", "log=s", "no-log",
119                  "tcp-ip",  "silent", "verbose"))
120  {
121    $flag_exit= 1;
122  }
123  usage() if ($opt_help);
124
125  if ($opt_verbose && $opt_silent)
126  {
127    print "Both --verbose and --silent have been given. Some of the warnings ";
128    print "will be disabled\nand some will be enabled.\n\n";
129  }
130
131  init_log() if (!defined($opt_log));
132  $groupids = $ARGV[1];
133  if ($opt_version)
134  {
135    print "$my_progname version $VER by Jani Tolonen\n";
136    exit(0);
137  }
138  example() if ($opt_example);
139  if ($flag_exit)
140  {
141    print "Error with an option, see $my_progname --help for more info.\n";
142    exit(1);
143  }
144  if (!defined(my_which(my_print_defaults)))
145  {
146    print "ABORT: Can't find command 'my_print_defaults'.\n";
147    print "This command is available from the latest MySQL\n";
148    print "distribution. Please make sure you have the command\n";
149    print "in your PATH.\n";
150    exit(1);
151  }
152  usage() if (!defined($ARGV[0]) ||
153	      (!($ARGV[0] =~ m/^start$/i) &&
154	       !($ARGV[0] =~ m/^stop$/i) &&
155	       !($ARGV[0] =~ m/^reload$/i) &&
156	       !($ARGV[0] =~ m/^report$/i)));
157
158  if (!$opt_no_log)
159  {
160    w2log("$my_progname log file version $VER; run: ",
161	  "$opt_log", 1, 0);
162  }
163  else
164  {
165    print "$my_progname log file version $VER; run: ";
166    print strftime "%a %b %e %H:%M:%S %Y", localtime;
167    print "\n";
168  }
169  if (($ARGV[0] =~ m/^start$/i) || ($ARGV[0] =~ m/^reload$/i))
170  {
171    if (!defined(($mysqld= my_which($opt_mysqld))) && $opt_verbose)
172    {
173      print "WARNING: Couldn't find the default mysqld binary.\n";
174      print "Tried: $opt_mysqld\n";
175      print "This is OK, if you are using option \"mysqld=...\" in ";
176      print "groups [mysqldN] separately for each.\n\n";
177    }
178    if ($ARGV[0] =~ m/^start$/i) {
179      start_mysqlds();
180    } elsif ($ARGV[0] =~ m/^reload$/i) {
181      reload_mysqlds();
182    }
183  }
184  else
185  {
186    if (!defined(($mysqladmin= my_which($opt_mysqladmin))) && $opt_verbose)
187    {
188      print "WARNING: Couldn't find the default mysqladmin binary.\n";
189      print "Tried: $opt_mysqladmin\n";
190      print "This is OK, if you are using option \"mysqladmin=...\" in ";
191      print "groups [mysqldN] separately for each.\n\n";
192    }
193    if ($ARGV[0] =~ m/^report$/i)
194    {
195      report_mysqlds();
196    }
197    else
198    {
199      stop_mysqlds();
200    }
201  }
202}
203
204#
205# Quote word for shell
206#
207
208sub quote_shell_word
209{
210  my ($option)= @_;
211
212  $option =~ s!([^\w=./-])!\\$1!g;
213  return $option;
214}
215
216sub defaults_for_group
217{
218  my ($group) = @_;
219
220  return () unless $my_print_defaults_exists;
221
222  my $com= join ' ', 'my_print_defaults', @defaults_options, $group;
223  my @defaults = `$com`;
224  chomp @defaults;
225  return @defaults;
226}
227
228####
229#### Init log file. Check for appropriate place for log file, in the following
230#### order:  my_print_defaults mysqld datadir, @datadir@
231####
232
233sub init_log
234{
235  foreach my $opt (defaults_for_group('mysqld'))
236  {
237    if ($opt =~ m/^--datadir=(.*)/ && -d "$1" && -w "$1")
238    {
239      $logdir= $1;
240    }
241  }
242  if (!defined($logdir))
243  {
244    $logdir= "@datadir@" if (-d "@datadir@" && -w "@datadir@");
245  }
246  if (!defined($logdir))
247  {
248    # Log file was not specified and we could not log to a standard place,
249    # so log file be disabled for now.
250    if (!$opt_silent)
251    {
252      print "WARNING: Log file disabled. Maybe directory or file isn't writable?\n";
253    }
254    $opt_no_log= 1;
255  }
256  else
257  {
258    $opt_log= "$logdir/mysqld_multi.log";
259  }
260}
261
262####
263#### Report living and not running MySQL servers
264####
265
266sub report_mysqlds
267{
268  my (@groups, $com, $i, @options, $pec);
269
270  print "Reporting MySQL (Percona Server) servers\n";
271  if (!$opt_no_log)
272  {
273    w2log("\nReporting MySQL (Percona Server) servers","$opt_log",0,0);
274  }
275  @groups = &find_groups($groupids);
276  for ($i = 0; defined($groups[$i]); $i++)
277  {
278    $com= get_mysqladmin_options($i, @groups);
279    $com.= " ping >> /dev/null 2>&1";
280    system($com);
281    $pec = $? >> 8;
282    if ($pec)
283    {
284      print "MySQL (Percona Server) from group: $groups[$i] is not running\n";
285      if (!$opt_no_log)
286      {
287	w2log("MySQL (Percona Server) from group: $groups[$i] is not running",
288	      "$opt_log", 0, 0);
289      }
290    }
291    else
292    {
293      print "MySQL (Percona Server) from group: $groups[$i] is running\n";
294      if (!$opt_no_log)
295      {
296	w2log("MySQL (Percona Server) from group: $groups[$i] is running",
297	      "$opt_log", 0, 0);
298      }
299    }
300  }
301  if (!$i)
302  {
303    print "No groups to be reported (check your GNRs)\n";
304    if (!$opt_no_log)
305    {
306      w2log("No groups to be reported (check your GNRs)", "$opt_log", 0, 0);
307    }
308  }
309}
310
311####
312#### start multiple servers
313####
314
315sub start_mysqlds()
316{
317  my (@groups, $com, $tmp, $i, @options, $j, $mysqld_found, $info_sent);
318
319  if (!$opt_no_log)
320  {
321    w2log("\nStarting MySQL (Percona Server) servers\n","$opt_log",0,0);
322  }
323  else
324  {
325    print "\nStarting MySQL (Percona Server) servers\n";
326  }
327  @groups = &find_groups($groupids);
328  for ($i = 0; defined($groups[$i]); $i++)
329  {
330    @options = defaults_for_group($groups[$i]);
331
332    $basedir_found= 0; # The default
333    $mysqld_found= 1; # The default
334    $mysqld_found= 0 if (!length($mysqld));
335    $com= "$mysqld";
336    for ($j = 0, $tmp= ""; defined($options[$j]); $j++)
337    {
338      if ("--datadir=" eq substr($options[$j], 0, 10)) {
339        $datadir = $options[$j];
340        $datadir =~ s/\-\-datadir\=//;
341        eval { mkpath($datadir) };
342        if ($@) {
343          print "FATAL ERROR: Cannot create data directory $datadir: $!\n";
344          exit(1);
345        }
346        if (! -d $datadir."/mysql") {
347          if (-w $datadir) {
348            print "\n\nInstalling new database in $datadir\n\n";
349            $install_cmd="@bindir@/mysql_install_db ";
350            $install_cmd.="--user=mysql ";
351            $install_cmd.="--datadir=$datadir";
352            system($install_cmd);
353          } else {
354            print "\n";
355            print "FATAL ERROR: Tried to create mysqld under group [$groups[$i]],\n";
356            print "but the data directory is not writable.\n";
357            print "data directory used: $datadir\n";
358            exit(1);
359          }
360        }
361
362        if (! -d $datadir."/mysql") {
363          print "\n";
364          print "FATAL ERROR: Tried to start mysqld under group [$groups[$i]],\n";
365          print "but no data directory was found or could be created.\n";
366          print "data directory used: $datadir\n";
367          exit(1);
368        }
369      }
370
371      if ("--mysqladmin=" eq substr($options[$j], 0, 13))
372      {
373	# catch this and ignore
374      }
375      elsif ("--mysqld=" eq substr($options[$j], 0, 9))
376      {
377	$options[$j]=~ s/\-\-mysqld\=//;
378	$com= $options[$j];
379        $mysqld_found= 1;
380      }
381      elsif ("--basedir=" eq substr($options[$j], 0, 10))
382      {
383        $basedir= $options[$j];
384        $basedir =~ s/^--basedir=//;
385        $basedir_found= 1;
386        $options[$j]= quote_shell_word($options[$j]);
387        $tmp.= " $options[$j]";
388      }
389      else
390      {
391	$options[$j]= quote_shell_word($options[$j]);
392	$tmp.= " $options[$j]";
393      }
394    }
395    if ($opt_verbose && $com =~ m/\/(safe_mysqld|mysqld_safe)$/ && !$info_sent)
396    {
397      print "WARNING: $1 is being used to start mysqld. In this case you ";
398      print "may need to pass\n\"ledir=...\" under groups [mysqldN] to ";
399      print "$1 in order to find the actual mysqld binary.\n";
400      print "ledir (library executable directory) should be the path to the ";
401      print "wanted mysqld binary.\n\n";
402      $info_sent= 1;
403    }
404    $com.= $tmp;
405    $com.= " >> $opt_log 2>&1" if (!$opt_no_log);
406    $com.= " &";
407    if (!$mysqld_found)
408    {
409      print "\n";
410      print "FATAL ERROR: Tried to start mysqld under group [$groups[$i]], ";
411      print "but no mysqld binary was found.\n";
412      print "Please add \"mysqld=...\" in group [mysqld_multi], or add it to ";
413      print "group [$groups[$i]] separately.\n";
414      exit(1);
415    }
416    if ($basedir_found)
417    {
418      $curdir=getcwd();
419      chdir($basedir) or die "Can't change to datadir $basedir";
420    }
421    system($com);
422    if ($basedir_found)
423    {
424      chdir($curdir) or die "Can't change back to original dir $curdir";
425    }
426  }
427  if (!$i && !$opt_no_log)
428  {
429    w2log("No MySQL (Percona Server) servers to be started (check your GNRs)",
430	  "$opt_log", 0, 0);
431  }
432}
433
434####
435#### reload multiple servers
436####
437
438sub reload_mysqlds()
439{
440  my (@groups, $com, $tmp, $i, @options, $j);
441
442  if (!$opt_no_log)
443  {
444    w2log("\nReloading MySQL servers\n","$opt_log",0,0);
445  }
446  else
447  {
448    print "\nReloading MySQL servers\n";
449  }
450  @groups = &find_groups($groupids);
451  for ($i = 0; defined($groups[$i]); $i++)
452  {
453    $mysqld_server = $mysqld;
454    @options = defaults_for_group($groups[$i]);
455
456    for ($j = 0, $tmp= ""; defined($options[$j]); $j++)
457    {
458      if ("--mysqladmin=" eq substr($options[$j], 0, 13))
459      {
460        # catch this and ignore
461      }
462      elsif ("--mysqld=" eq substr($options[$j], 0, 9))
463      {
464        $options[$j] =~ s/\-\-mysqld\=//;
465        $mysqld_server = $options[$j];
466      }
467      elsif ("--pid-file=" eq substr($options[$j], 0, 11))
468      {
469        $options[$j] =~ s/\-\-pid-file\=//;
470        $pid_file = $options[$j];
471      }
472    }
473    $com = "killproc -p $pid_file -HUP $mysqld_server";
474    system($com);
475
476    $com = "touch $pid_file";
477    system($com);
478  }
479  if (!$i && !$opt_no_log)
480  {
481    w2log("No MySQL servers to be reloaded (check your GNRs)",
482         "$opt_log", 0, 0);
483  }
484}
485
486###
487#### stop multiple servers
488####
489
490sub stop_mysqlds()
491{
492  my (@groups, $com, $i, @options);
493
494  if (!$opt_no_log)
495  {
496    w2log("\nStopping MySQL (Percona Server) servers\n","$opt_log",0,0);
497  }
498  else
499  {
500    print "\nStopping MySQL (Percona Server) servers\n";
501  }
502  @groups = &find_groups($groupids);
503  for ($i = 0; defined($groups[$i]); $i++)
504  {
505    $com= get_mysqladmin_options($i, @groups);
506    $com.= " shutdown";
507    $com.= " >> $opt_log 2>&1" if (!$opt_no_log);
508    $com.= " &";
509    system($com);
510  }
511  if (!$i && !$opt_no_log)
512  {
513    w2log("No MySQL (Percona Server) servers to be stopped (check your GNRs)",
514	  "$opt_log", 0, 0);
515  }
516}
517
518####
519#### Sub function for mysqladmin option parsing
520####
521
522sub get_mysqladmin_options
523{
524  my ($i, @groups)= @_;
525  my ($mysqladmin_found, $com, $tmp, $j);
526
527  @options = defaults_for_group($groups[$i]);
528
529  $mysqladmin_found= 1; # The default
530  $mysqladmin_found= 0 if (!length($mysqladmin));
531  $com = "$mysqladmin";
532  $tmp = " -u $opt_user";
533  if (defined($opt_password)) {
534    my $pw= $opt_password;
535    # Protect single quotes in password
536    $pw =~ s/'/'"'"'/g;
537    $tmp.= " -p'$pw'";
538  }
539  $tmp.= $opt_tcp_ip ? " -h 127.0.0.1" : "";
540  for ($j = 0; defined($options[$j]); $j++)
541  {
542    if ("--mysqladmin=" eq substr($options[$j], 0, 13))
543    {
544      $options[$j]=~ s/\-\-mysqladmin\=//;
545      $com= $options[$j];
546      $mysqladmin_found= 1;
547    }
548    elsif ((($options[$j] =~ m/^(\-\-socket\=)(.*)$/) && !$opt_tcp_ip) ||
549	   ($options[$j] =~ m/^(\-\-port\=)(.*)$/))
550    {
551      $tmp.= " $options[$j]";
552    }
553  }
554  if (!$mysqladmin_found)
555  {
556    print "\n";
557    print "FATAL ERROR: Tried to use mysqladmin in group [$groups[$i]], ";
558    print "but no mysqladmin binary was found.\n";
559    print "Please add \"mysqladmin=...\" in group [mysqld_multi], or ";
560    print "in group [$groups[$i]].\n";
561    exit(1);
562  }
563  $com.= $tmp;
564  return $com;
565}
566
567# Return a list of option files which can be opened.  Similar, but not
568# identical, to behavior of my_search_option_files()
569sub list_defaults_files
570{
571  my %opt;
572  foreach (@defaults_options)
573  {
574    return () if /^--no-defaults$/;
575    $opt{$1} = $2 if /^--defaults-(extra-file|file)=(.*)$/;
576  }
577
578  return ($opt{file}) if exists $opt{file};
579
580  my %seen;  # Don't list the same file more than once
581  return grep { defined $_ and not $seen{$_}++ and -f $_ and -r $_ }
582              ('/etc/my.cnf',
583               '/etc/mysql/my.cnf',
584               '@sysconfdir@/my.cnf',
585               ($ENV{MYSQL_HOME} ? "$ENV{MYSQL_HOME}/my.cnf" : undef),
586               $opt{'extra-file'},
587               ($ENV{HOME} ? "$ENV{HOME}/.my.cnf" : undef));
588}
589
590
591# Takes a specification of GNRs (see --help), and returns a list of matching
592# groups which actually are mentioned in a relevant config file
593sub find_groups
594{
595  my ($raw_gids) = @_;
596
597  my %gids;
598  my @groups;
599
600  if (defined($raw_gids))
601  {
602    # Make a hash of the wanted group ids
603    foreach my $raw_gid (split ',', $raw_gids)
604    {
605      # Match 123 or 123-456
606      my ($start, $end) = ($raw_gid =~ /^\s*(\d+)(?:\s*-\s*(\d+))?\s*$/);
607      $end = $start if not defined $end;
608      if (not defined $start or $end < $start or $start < 0)
609      {
610        print "ABORT: Bad GNR: $raw_gid; see $my_progname --help\n";
611        exit(1);
612      }
613
614      foreach my $i ($start .. $end)
615      {
616        # Use $i + 0 to normalize numbers (002 + 0 -> 2)
617        $gids{$i + 0}= 1;
618      }
619    }
620  }
621
622  my @defaults_files = list_defaults_files();
623  #warn "@{[sort keys %gids]} -> @defaults_files\n";
624  foreach my $file (@defaults_files)
625  {
626    next unless open CONF, "< $file";
627
628    while (<CONF>)
629    {
630      if (/^\s*\[\s*(mysqld)(\d+)\s*\]\s*$/)
631      {
632        #warn "Found a group: $1$2\n";
633        # Use $2 + 0 to normalize numbers (002 + 0 -> 2)
634        if (not defined($raw_gids) or $gids{$2 + 0})
635        {
636          push @groups, "$1$2";
637        }
638      }
639    }
640
641    close CONF;
642  }
643  return @groups;
644}
645
646####
647#### w2log: Write to a logfile.
648#### 1.arg: append to the log file (given string, or from a file. if a file,
649####        file will be read from $opt_logdir)
650#### 2.arg: logfile -name (w2log assumes that the logfile is in $opt_logdir).
651#### 3.arg. 0 | 1, if true, print current date to the logfile. 3. arg will
652####        be ignored, if 1. arg is a file.
653#### 4.arg. 0 | 1, if true, first argument is a file, else a string
654####
655
656sub w2log
657{
658  my ($msg, $file, $date_flag, $is_file)= @_;
659  my (@data);
660
661  open (LOGFILE, ">>$opt_log")
662    or die "FATAL: w2log: Couldn't open log file: $opt_log\n";
663
664  if ($is_file)
665  {
666    open (FROMFILE, "<$msg") && (@data=<FROMFILE>) &&
667      close(FROMFILE)
668	or die "FATAL: w2log: Couldn't open file: $msg\n";
669    foreach my $line (@data)
670    {
671      print LOGFILE "$line";
672    }
673  }
674  else
675  {
676    print LOGFILE "$msg";
677    print LOGFILE strftime "%a %b %e %H:%M:%S %Y", localtime if ($date_flag);
678    print LOGFILE "\n";
679  }
680  close (LOGFILE);
681  return;
682}
683
684####
685#### my_which is used, because we can't assume that every system has the
686#### which -command. my_which can take only one argument at a time.
687#### Return values: requested system command with the first found path,
688#### or undefined, if not found.
689####
690
691sub my_which
692{
693  my ($command) = @_;
694  my (@paths, $path);
695
696 # If the argument is not 'my_print_defaults' then it would be of the format
697 # <absolute_path>/<program>
698 return $command if ($command ne 'my_print_defaults' && -f $command &&
699                     -x $command);
700
701  @paths = split(':', $ENV{'PATH'});
702  foreach $path (@paths)
703  {
704    $path .= "/$command";
705    return $path if (-f $path && -x $path);
706  }
707  return undef();
708}
709
710
711####
712#### example
713####
714
715sub example
716{
717  print <<EOF;
718# This is an example of a my.cnf file for $my_progname.
719# Usually this file is located in home dir ~/.my.cnf or /etc/my.cnf
720#
721# SOME IMPORTANT NOTES FOLLOW:
722#
723# 1.COMMON USER
724#
725#   Make sure that the MySQL user, who is stopping the mysqld services, has
726#   the same password to all MySQL servers being accessed by $my_progname.
727#   This user needs to have the 'Shutdown_priv' -privilege, but for security
728#   reasons should have no other privileges. It is advised that you create a
729#   common 'multi_admin' user for all MySQL servers being controlled by
730#   $my_progname. Here is an example how to do it:
731#
732#   GRANT SHUTDOWN ON *.* TO multi_admin\@localhost IDENTIFIED BY 'password'
733#
734#   You will need to apply the above to all MySQL servers that are being
735#   controlled by $my_progname. 'multi_admin' will shutdown the servers
736#   using 'mysqladmin' -binary, when '$my_progname stop' is being called.
737#
738# 2.PID-FILE
739#
740#   If you are using mysqld_safe to start mysqld, make sure that every
741#   MySQL server has a separate pid-file. In order to use mysqld_safe
742#   via $my_progname, you need to use two options:
743#
744#   mysqld=/path/to/mysqld_safe
745#   ledir=/path/to/mysqld-binary/
746#
747#   ledir (library executable directory), is an option that only mysqld_safe
748#   accepts, so you will get an error if you try to pass it to mysqld directly.
749#   For this reason you might want to use the above options within [mysqld#]
750#   group directly.
751#
752# 3.DATA DIRECTORY
753#
754#   It is NOT advised to run many MySQL servers within the same data directory.
755#   You can do so, but please make sure to understand and deal with the
756#   underlying caveats. In short they are:
757#   - Speed penalty
758#   - Risk of table/data corruption
759#   - Data synchronising problems between the running servers
760#   - Heavily media (disk) bound
761#   - Relies on the system (external) file locking
762#   - Is not applicable with all table types. (Such as InnoDB)
763#     Trying so will end up with undesirable results.
764#
765# 4.TCP/IP Port
766#
767#   Every server requires one and it must be unique.
768#
769# 5.[mysqld#] Groups
770#
771#   In the example below the first and the fifth mysqld group was
772#   intentionally left out. You may have 'gaps' in the config file. This
773#   gives you more flexibility.
774#
775# 6.MySQL Server User
776#
777#   You can pass the user=... option inside [mysqld#] groups. This
778#   can be very handy in some cases, but then you need to run $my_progname
779#   as UNIX root.
780#
781# 7.A Start-up Manage Script for $my_progname
782#
783#   In the recent MySQL distributions you can find a file called
784#   mysqld_multi.server.sh. It is a wrapper for $my_progname. This can
785#   be used to start and stop multiple servers during boot and shutdown.
786#
787#   You can place the file in /etc/init.d/mysqld_multi.server.sh and
788#   make the needed symbolic links to it from various run levels
789#   (as per Linux/Unix standard). You may even replace the
790#   /etc/init.d/mysql.server script with it.
791#
792#   Before using, you must create a my.cnf file either in @sysconfdir@/my.cnf
793#   or /root/.my.cnf and add the [mysqld_multi] and [mysqld#] groups.
794#
795#   The script can be found from support-files/mysqld_multi.server.sh
796#   in MySQL distribution. (Verify the script before using)
797#
798
799[mysqld_multi]
800mysqld     = @bindir@/mysqld_safe
801mysqladmin = @bindir@/mysqladmin
802user       = multi_admin
803password   = my_password
804
805[mysqld2]
806socket     = /tmp/mysql.sock2
807port       = 3307
808pid-file   = @localstatedir@2/hostname.pid2
809datadir    = @localstatedir@2
810language   = @datadir@/mysql/english
811user       = unix_user1
812
813[mysqld3]
814mysqld     = /path/to/mysqld_safe
815ledir      = /path/to/mysqld-binary/
816mysqladmin = /path/to/mysqladmin
817socket     = /tmp/mysql.sock3
818port       = 3308
819pid-file   = @localstatedir@3/hostname.pid3
820datadir    = @localstatedir@3
821language   = @datadir@/mysql/swedish
822user       = unix_user2
823
824[mysqld4]
825socket     = /tmp/mysql.sock4
826port       = 3309
827pid-file   = @localstatedir@4/hostname.pid4
828datadir    = @localstatedir@4
829language   = @datadir@/mysql/estonia
830user       = unix_user3
831 
832[mysqld6]
833socket     = /tmp/mysql.sock6
834port       = 3311
835pid-file   = @localstatedir@6/hostname.pid6
836datadir    = @localstatedir@6
837language   = @datadir@/mysql/japanese
838user       = unix_user4
839EOF
840  exit(0);
841}
842
843####
844#### usage
845####
846
847sub usage
848{
849  print <<EOF;
850$my_progname version $VER by Jani Tolonen
851
852Description:
853$my_progname can be used to start, reload, or stop any number of separate
854mysqld processes running in different TCP/IP ports and UNIX sockets.
855
856$my_progname can read group [mysqld_multi] from my.cnf file. You may
857want to put options mysqld=... and mysqladmin=... there.  Since
858version 2.10 these options can also be given under groups [mysqld#],
859which gives more control over different versions.  One can have the
860default mysqld and mysqladmin under group [mysqld_multi], but this is
861not mandatory. Please note that if mysqld or mysqladmin is missing
862from both [mysqld_multi] and [mysqld#], a group that is tried to be
863used, $my_progname will abort with an error.
864
865$my_progname will search for groups named [mysqld#] from my.cnf (or
866the given --defaults-extra-file=...), where '#' can be any positive 
867integer starting from 1. These groups should be the same as the regular
868[mysqld] group, but with those port, socket and any other options
869that are to be used with each separate mysqld process. The number
870in the group name has another function; it can be used for starting,
871reloading, stopping, or reporting any specific mysqld server.
872
873Usage: $my_progname [OPTIONS] {start|reload|stop|report} [GNR,GNR,GNR...]
874or     $my_progname [OPTIONS] {start|reload|stop|report} [GNR-GNR,GNR,GNR-GNR,...]
875
876The GNR means the group number. You can start, reload, stop or report any GNR,
877or several of them at the same time. (See --example) The GNRs list can
878be comma separated or a dash combined. The latter means that all the
879GNRs between GNR1-GNR2 will be affected. Without GNR argument all the
880groups found will either be started, reloaded, stopped, or reported. Note that
881syntax for specifying GNRs must appear without spaces.
882
883Options:
884
885These options must be given before any others:
886--no-defaults      Do not read any defaults file
887--defaults-file=...  Read only this configuration file, do not read the
888                   standard system-wide and user-specific files
889--defaults-extra-file=...  Read this configuration file in addition to the
890                   standard system-wide and user-specific files
891Using:  @{[join ' ', @defaults_options]}
892
893--example          Give an example of a config file with extra information.
894--help             Print this help and exit.
895--log=...          Log file. Full path to and the name for the log file. NOTE:
896                   If the file exists, everything will be appended.
897                   Using: $opt_log
898--mysqladmin=...   mysqladmin binary to be used for a server shutdown.
899                   Since version 2.10 this can be given within groups [mysqld#]
900                   Using: $mysqladmin
901--mysqld=...       mysqld binary to be used. Note that you can give mysqld_safe
902                   to this option also. The options are passed to mysqld. Just
903                   make sure you have mysqld in your PATH or fix mysqld_safe.
904                   Using: $mysqld
905                   Please note: Since mysqld_multi version 2.3 you can also
906                   give this option inside groups [mysqld#] in ~/.my.cnf,
907                   where '#' stands for an integer (number) of the group in
908                   question. This will be recognised as a special option and
909                   will not be passed to the mysqld. This will allow one to
910                   start different mysqld versions with mysqld_multi.
911--no-log           Print to stdout instead of the log file. By default the log
912                   file is turned on.
913--password=...     Password for mysqladmin user.
914--silent           Disable warnings.
915--tcp-ip           Connect to the MySQL server(s) via the TCP/IP port instead
916                   of the UNIX socket. This affects stopping and reporting.
917                   If a socket file is missing, the server may still be
918                   running, but can be accessed only via the TCP/IP port.
919                   By default connecting is done via the UNIX socket.
920--user=...         mysqladmin user. Using: $opt_user
921--verbose          Be more verbose.
922--version          Print the version number and exit.
923EOF
924  exit(0);
925}
926