1#!@PERL_PATH@
2
3# Copyright (c) 2000, 2021, Oracle and/or its affiliates.
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 servers\n";
271  if (!$opt_no_log)
272  {
273    w2log("\nReporting MySQL 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 server from group: $groups[$i] is not running\n";
285      if (!$opt_no_log)
286      {
287	w2log("MySQL server from group: $groups[$i] is not running",
288	      "$opt_log", 0, 0);
289      }
290    }
291    else
292    {
293      print "MySQL server from group: $groups[$i] is running\n";
294      if (!$opt_no_log)
295      {
296	w2log("MySQL 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 servers\n","$opt_log",0,0);
322  }
323  else
324  {
325    print "\nStarting MySQL 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@/mysqld ";
350            $install_cmd.="--initialize ";
351            $install_cmd.="--user=mysql ";
352            $install_cmd.="--datadir=$datadir";
353            system($install_cmd);
354          } else {
355            print "\n";
356            print "FATAL ERROR: Tried to create mysqld under group [$groups[$i]],\n";
357            print "but the data directory is not writable.\n";
358            print "data directory used: $datadir\n";
359            exit(1);
360          }
361        }
362
363        if (! -d $datadir."/mysql") {
364          print "\n";
365          print "FATAL ERROR: Tried to start mysqld under group [$groups[$i]],\n";
366          print "but no data directory was found or could be created.\n";
367          print "data directory used: $datadir\n";
368          exit(1);
369        }
370      }
371
372      if ("--mysqladmin=" eq substr($options[$j], 0, 13))
373      {
374	# catch this and ignore
375      }
376      elsif ("--mysqld=" eq substr($options[$j], 0, 9))
377      {
378	$options[$j]=~ s/\-\-mysqld\=//;
379	$com= $options[$j];
380        $mysqld_found= 1;
381      }
382      elsif ("--basedir=" eq substr($options[$j], 0, 10))
383      {
384        $basedir= $options[$j];
385        $basedir =~ s/^--basedir=//;
386        $basedir_found= 1;
387        $options[$j]= quote_shell_word($options[$j]);
388        $tmp.= " $options[$j]";
389      }
390      else
391      {
392	$options[$j]= quote_shell_word($options[$j]);
393	$tmp.= " $options[$j]";
394      }
395    }
396    if ($opt_verbose && $com =~ m/\/(safe_mysqld|mysqld_safe)$/ && !$info_sent)
397    {
398      print "WARNING: $1 is being used to start mysqld. In this case you ";
399      print "may need to pass\n\"ledir=...\" under groups [mysqldN] to ";
400      print "$1 in order to find the actual mysqld binary.\n";
401      print "ledir (library executable directory) should be the path to the ";
402      print "wanted mysqld binary.\n\n";
403      $info_sent= 1;
404    }
405    $com.= $tmp;
406    $com.= " >> $opt_log 2>&1" if (!$opt_no_log);
407    $com.= " &";
408    if (!$mysqld_found)
409    {
410      print "\n";
411      print "FATAL ERROR: Tried to start mysqld under group [$groups[$i]], ";
412      print "but no mysqld binary was found.\n";
413      print "Please add \"mysqld=...\" in group [mysqld_multi], or add it to ";
414      print "group [$groups[$i]] separately.\n";
415      exit(1);
416    }
417    if ($basedir_found)
418    {
419      $curdir=getcwd();
420      chdir($basedir) or die "Can't change to datadir $basedir";
421    }
422    system($com);
423    if ($basedir_found)
424    {
425      chdir($curdir) or die "Can't change back to original dir $curdir";
426    }
427  }
428  if (!$i && !$opt_no_log)
429  {
430    w2log("No MySQL servers to be started (check your GNRs)",
431	  "$opt_log", 0, 0);
432  }
433}
434
435####
436#### reload multiple servers
437####
438
439sub reload_mysqlds()
440{
441  my (@groups, $com, $tmp, $i, @options, $j);
442
443  if (!$opt_no_log)
444  {
445    w2log("\nReloading MySQL servers\n","$opt_log",0,0);
446  }
447  else
448  {
449    print "\nReloading MySQL servers\n";
450  }
451  @groups = &find_groups($groupids);
452  for ($i = 0; defined($groups[$i]); $i++)
453  {
454    $mysqld_server = $mysqld;
455    @options = defaults_for_group($groups[$i]);
456
457    for ($j = 0, $tmp= ""; defined($options[$j]); $j++)
458    {
459      if ("--mysqladmin=" eq substr($options[$j], 0, 13))
460      {
461        # catch this and ignore
462      }
463      elsif ("--mysqld=" eq substr($options[$j], 0, 9))
464      {
465        $options[$j] =~ s/\-\-mysqld\=//;
466        $mysqld_server = $options[$j];
467      }
468      elsif ("--pid-file=" eq substr($options[$j], 0, 11))
469      {
470        $options[$j] =~ s/\-\-pid-file\=//;
471        $pid_file = $options[$j];
472      }
473    }
474    $com = "killproc -p $pid_file -HUP $mysqld_server";
475    system($com);
476
477    $com = "touch $pid_file";
478    system($com);
479  }
480  if (!$i && !$opt_no_log)
481  {
482    w2log("No MySQL servers to be reloaded (check your GNRs)",
483         "$opt_log", 0, 0);
484  }
485}
486
487###
488#### stop multiple servers
489####
490
491sub stop_mysqlds()
492{
493  my (@groups, $com, $i, @options);
494
495  if (!$opt_no_log)
496  {
497    w2log("\nStopping MySQL servers\n","$opt_log",0,0);
498  }
499  else
500  {
501    print "\nStopping MySQL servers\n";
502  }
503  @groups = &find_groups($groupids);
504  for ($i = 0; defined($groups[$i]); $i++)
505  {
506    $com= get_mysqladmin_options($i, @groups);
507    $com.= " shutdown";
508    $com.= " >> $opt_log 2>&1" if (!$opt_no_log);
509    $com.= " &";
510    system($com);
511  }
512  if (!$i && !$opt_no_log)
513  {
514    w2log("No MySQL servers to be stopped (check your GNRs)",
515	  "$opt_log", 0, 0);
516  }
517}
518
519####
520#### Sub function for mysqladmin option parsing
521####
522
523sub get_mysqladmin_options
524{
525  my ($i, @groups)= @_;
526  my ($mysqladmin_found, $com, $tmp, $j);
527
528  @options = defaults_for_group($groups[$i]);
529
530  $mysqladmin_found= 1; # The default
531  $mysqladmin_found= 0 if (!length($mysqladmin));
532  $com = "$mysqladmin";
533  $tmp = " -u $opt_user";
534  if (defined($opt_password)) {
535    my $pw= $opt_password;
536    # Protect single quotes in password
537    $pw =~ s/'/'"'"'/g;
538    $tmp.= " -p'$pw'";
539  }
540  $tmp.= $opt_tcp_ip ? " -h 127.0.0.1" : "";
541  for ($j = 0; defined($options[$j]); $j++)
542  {
543    if ("--mysqladmin=" eq substr($options[$j], 0, 13))
544    {
545      $options[$j]=~ s/\-\-mysqladmin\=//;
546      $com= $options[$j];
547      $mysqladmin_found= 1;
548    }
549    elsif ((($options[$j] =~ m/^(\-\-socket\=)(.*)$/) && !$opt_tcp_ip) ||
550	   ($options[$j] =~ m/^(\-\-port\=)(.*)$/))
551    {
552      $tmp.= " $options[$j]";
553    }
554  }
555  if (!$mysqladmin_found)
556  {
557    print "\n";
558    print "FATAL ERROR: Tried to use mysqladmin in group [$groups[$i]], ";
559    print "but no mysqladmin binary was found.\n";
560    print "Please add \"mysqladmin=...\" in group [mysqld_multi], or ";
561    print "in group [$groups[$i]].\n";
562    exit(1);
563  }
564  $com.= $tmp;
565  return $com;
566}
567
568# Return a list of option files which can be opened.  Similar, but not
569# identical, to behavior of my_search_option_files()
570sub list_defaults_files
571{
572  my %opt;
573  foreach (@defaults_options)
574  {
575    return () if /^--no-defaults$/;
576    $opt{$1} = $2 if /^--defaults-(extra-file|file)=(.*)$/;
577  }
578
579  return ($opt{file}) if exists $opt{file};
580
581  my %seen;  # Don't list the same file more than once
582  return grep { defined $_ and not $seen{$_}++ and -f $_ and -r $_ }
583              ('/etc/my.cnf',
584               '/etc/mysql/my.cnf',
585               '@sysconfdir@/my.cnf',
586               ($ENV{MYSQL_HOME} ? "$ENV{MYSQL_HOME}/my.cnf" : undef),
587               $opt{'extra-file'},
588               ($ENV{HOME} ? "$ENV{HOME}/.my.cnf" : undef));
589}
590
591
592# Takes a specification of GNRs (see --help), and returns a list of matching
593# groups which actually are mentioned in a relevant config file
594sub find_groups
595{
596  my ($raw_gids) = @_;
597
598  my %gids;
599  my @groups;
600
601  if (defined($raw_gids))
602  {
603    # Make a hash of the wanted group ids
604    foreach my $raw_gid (split ',', $raw_gids)
605    {
606      # Match 123 or 123-456
607      my ($start, $end) = ($raw_gid =~ /^\s*(\d+)(?:\s*-\s*(\d+))?\s*$/);
608      $end = $start if not defined $end;
609      if (not defined $start or $end < $start or $start < 0)
610      {
611        print "ABORT: Bad GNR: $raw_gid; see $my_progname --help\n";
612        exit(1);
613      }
614
615      foreach my $i ($start .. $end)
616      {
617        # Use $i + 0 to normalize numbers (002 + 0 -> 2)
618        $gids{$i + 0}= 1;
619      }
620    }
621  }
622
623  my @defaults_files = list_defaults_files();
624  #warn "@{[sort keys %gids]} -> @defaults_files\n";
625  foreach my $file (@defaults_files)
626  {
627    next unless open CONF, "< $file";
628
629    while (<CONF>)
630    {
631      if (/^\s*\[\s*(mysqld)(\d+)\s*\]\s*$/)
632      {
633        #warn "Found a group: $1$2\n";
634        # Use $2 + 0 to normalize numbers (002 + 0 -> 2)
635        if (not defined($raw_gids) or $gids{$2 + 0})
636        {
637          push @groups, "$1$2";
638        }
639      }
640    }
641
642    close CONF;
643  }
644  return @groups;
645}
646
647####
648#### w2log: Write to a logfile.
649#### 1.arg: append to the log file (given string, or from a file. if a file,
650####        file will be read from $opt_logdir)
651#### 2.arg: logfile -name (w2log assumes that the logfile is in $opt_logdir).
652#### 3.arg. 0 | 1, if true, print current date to the logfile. 3. arg will
653####        be ignored, if 1. arg is a file.
654#### 4.arg. 0 | 1, if true, first argument is a file, else a string
655####
656
657sub w2log
658{
659  my ($msg, $file, $date_flag, $is_file)= @_;
660  my (@data);
661
662  open (LOGFILE, ">>$opt_log")
663    or die "FATAL: w2log: Couldn't open log file: $opt_log\n";
664
665  if ($is_file)
666  {
667    open (FROMFILE, "<$msg") && (@data=<FROMFILE>) &&
668      close(FROMFILE)
669	or die "FATAL: w2log: Couldn't open file: $msg\n";
670    foreach my $line (@data)
671    {
672      print LOGFILE "$line";
673    }
674  }
675  else
676  {
677    print LOGFILE "$msg";
678    print LOGFILE strftime "%a %b %e %H:%M:%S %Y", localtime if ($date_flag);
679    print LOGFILE "\n";
680  }
681  close (LOGFILE);
682  return;
683}
684
685####
686#### my_which is used, because we can't assume that every system has the
687#### which -command. my_which can take only one argument at a time.
688#### Return values: requested system command with the first found path,
689#### or undefined, if not found.
690####
691
692sub my_which
693{
694  my ($command) = @_;
695  my (@paths, $path);
696
697 # If the argument is not 'my_print_defaults' then it would be of the format
698 # <absolute_path>/<program>
699 return $command if ($command ne 'my_print_defaults' && -f $command &&
700                     -x $command);
701
702  @paths = split(':', $ENV{'PATH'});
703  foreach $path (@paths)
704  {
705    $path .= "/$command";
706    return $path if (-f $path && -x $path);
707  }
708  return undef();
709}
710
711
712####
713#### example
714####
715
716sub example
717{
718  print <<EOF;
719# This is an example of a my.cnf file for $my_progname.
720# Usually this file is located in home dir ~/.my.cnf or /etc/my.cnf
721#
722# SOME IMPORTANT NOTES FOLLOW:
723#
724# 1.COMMON USER
725#
726#   Make sure that the MySQL user, who is stopping the mysqld services, has
727#   the same password to all MySQL servers being accessed by $my_progname.
728#   This user needs to have the 'Shutdown_priv' -privilege, but for security
729#   reasons should have no other privileges. It is advised that you create a
730#   common 'multi_admin' user for all MySQL servers being controlled by
731#   $my_progname. Here is an example how to do it:
732#
733#   GRANT SHUTDOWN ON *.* TO multi_admin\@localhost IDENTIFIED BY 'password'
734#
735#   You will need to apply the above to all MySQL servers that are being
736#   controlled by $my_progname. 'multi_admin' will shutdown the servers
737#   using 'mysqladmin' -binary, when '$my_progname stop' is being called.
738#
739# 2.PID-FILE
740#
741#   If you are using mysqld_safe to start mysqld, make sure that every
742#   MySQL server has a separate pid-file. In order to use mysqld_safe
743#   via $my_progname, you need to use two options:
744#
745#   mysqld=/path/to/mysqld_safe
746#   ledir=/path/to/mysqld-binary/
747#
748#   ledir (library executable directory), is an option that only mysqld_safe
749#   accepts, so you will get an error if you try to pass it to mysqld directly.
750#   For this reason you might want to use the above options within [mysqld#]
751#   group directly.
752#
753# 3.DATA DIRECTORY
754#
755#   It is NOT advised to run many MySQL servers within the same data directory.
756#   You can do so, but please make sure to understand and deal with the
757#   underlying caveats. In short they are:
758#   - Speed penalty
759#   - Risk of table/data corruption
760#   - Data synchronising problems between the running servers
761#   - Heavily media (disk) bound
762#   - Relies on the system (external) file locking
763#   - Is not applicable with all table types. (Such as InnoDB)
764#     Trying so will end up with undesirable results.
765#
766# 4.TCP/IP Port
767#
768#   Every server requires one and it must be unique.
769#
770# 5.[mysqld#] Groups
771#
772#   In the example below the first and the fifth mysqld group was
773#   intentionally left out. You may have 'gaps' in the config file. This
774#   gives you more flexibility.
775#
776# 6.MySQL Server User
777#
778#   You can pass the user=... option inside [mysqld#] groups. This
779#   can be very handy in some cases, but then you need to run $my_progname
780#   as UNIX root.
781#
782# 7.A Start-up Manage Script for $my_progname
783#
784#   In the recent MySQL distributions you can find a file called
785#   mysqld_multi.server.sh. It is a wrapper for $my_progname. This can
786#   be used to start and stop multiple servers during boot and shutdown.
787#
788#   You can place the file in /etc/init.d/mysqld_multi.server.sh and
789#   make the needed symbolic links to it from various run levels
790#   (as per Linux/Unix standard). You may even replace the
791#   /etc/init.d/mysql.server script with it.
792#
793#   Before using, you must create a my.cnf file either in @sysconfdir@/my.cnf
794#   or /root/.my.cnf and add the [mysqld_multi] and [mysqld#] groups.
795#
796#   The script can be found from support-files/mysqld_multi.server.sh
797#   in MySQL distribution. (Verify the script before using)
798#
799
800[mysqld_multi]
801mysqld     = @bindir@/mysqld_safe
802mysqladmin = @bindir@/mysqladmin
803user       = multi_admin
804password   = my_password
805
806[mysqld2]
807socket     = /tmp/mysql.sock2
808port       = 3307
809pid-file   = @localstatedir@2/hostname.pid2
810datadir    = @localstatedir@2
811language   = @datadir@/mysql/english
812user       = unix_user1
813
814[mysqld3]
815mysqld     = /path/to/mysqld_safe
816ledir      = /path/to/mysqld-binary/
817mysqladmin = /path/to/mysqladmin
818socket     = /tmp/mysql.sock3
819port       = 3308
820pid-file   = @localstatedir@3/hostname.pid3
821datadir    = @localstatedir@3
822language   = @datadir@/mysql/swedish
823user       = unix_user2
824
825[mysqld4]
826socket     = /tmp/mysql.sock4
827port       = 3309
828pid-file   = @localstatedir@4/hostname.pid4
829datadir    = @localstatedir@4
830language   = @datadir@/mysql/estonia
831user       = unix_user3
832 
833[mysqld6]
834socket     = /tmp/mysql.sock6
835port       = 3311
836pid-file   = @localstatedir@6/hostname.pid6
837datadir    = @localstatedir@6
838language   = @datadir@/mysql/japanese
839user       = unix_user4
840EOF
841  exit(0);
842}
843
844####
845#### usage
846####
847
848sub usage
849{
850  print <<EOF;
851$my_progname version $VER by Jani Tolonen
852
853Description:
854$my_progname can be used to start, reload, or stop any number of separate
855mysqld processes running in different TCP/IP ports and UNIX sockets.
856
857$my_progname can read group [mysqld_multi] from my.cnf file. You may
858want to put options mysqld=... and mysqladmin=... there.  Since
859version 2.10 these options can also be given under groups [mysqld#],
860which gives more control over different versions.  One can have the
861default mysqld and mysqladmin under group [mysqld_multi], but this is
862not mandatory. Please note that if mysqld or mysqladmin is missing
863from both [mysqld_multi] and [mysqld#], a group that is tried to be
864used, $my_progname will abort with an error.
865
866$my_progname will search for groups named [mysqld#] from my.cnf (or
867the given --defaults-extra-file=...), where '#' can be any positive 
868integer starting from 1. These groups should be the same as the regular
869[mysqld] group, but with those port, socket and any other options
870that are to be used with each separate mysqld process. The number
871in the group name has another function; it can be used for starting,
872reloading, stopping, or reporting any specific mysqld server.
873
874Usage: $my_progname [OPTIONS] {start|reload|stop|report} [GNR,GNR,GNR...]
875or     $my_progname [OPTIONS] {start|reload|stop|report} [GNR-GNR,GNR,GNR-GNR,...]
876
877The GNR means the group number. You can start, reload, stop or report any GNR,
878or several of them at the same time. (See --example) The GNRs list can
879be comma separated or a dash combined. The latter means that all the
880GNRs between GNR1-GNR2 will be affected. Without GNR argument all the
881groups found will either be started, reloaded, stopped, or reported. Note that
882syntax for specifying GNRs must appear without spaces.
883
884Options:
885
886These options must be given before any others:
887--no-defaults      Do not read any defaults file
888--defaults-file=...  Read only this configuration file, do not read the
889                   standard system-wide and user-specific files
890--defaults-extra-file=...  Read this configuration file in addition to the
891                   standard system-wide and user-specific files
892Using:  @{[join ' ', @defaults_options]}
893
894--example          Give an example of a config file with extra information.
895--help             Print this help and exit.
896--log=...          Log file. Full path to and the name for the log file. NOTE:
897                   If the file exists, everything will be appended.
898                   Using: $opt_log
899--mysqladmin=...   mysqladmin binary to be used for a server shutdown.
900                   Since version 2.10 this can be given within groups [mysqld#]
901                   Using: $mysqladmin
902--mysqld=...       mysqld binary to be used. Note that you can give mysqld_safe
903                   to this option also. The options are passed to mysqld. Just
904                   make sure you have mysqld in your PATH or fix mysqld_safe.
905                   Using: $mysqld
906                   Please note: Since mysqld_multi version 2.3 you can also
907                   give this option inside groups [mysqld#] in ~/.my.cnf,
908                   where '#' stands for an integer (number) of the group in
909                   question. This will be recognised as a special option and
910                   will not be passed to the mysqld. This will allow one to
911                   start different mysqld versions with mysqld_multi.
912--no-log           Print to stdout instead of the log file. By default the log
913                   file is turned on.
914--password=...     Password for mysqladmin user.
915--silent           Disable warnings.
916--tcp-ip           Connect to the MySQL server(s) via the TCP/IP port instead
917                   of the UNIX socket. This affects stopping and reporting.
918                   If a socket file is missing, the server may still be
919                   running, but can be accessed only via the TCP/IP port.
920                   By default connecting is done via the UNIX socket.
921--user=...         mysqladmin user. Using: $opt_user
922--verbose          Be more verbose.
923--version          Print the version number and exit.
924EOF
925  exit(0);
926}
927