File Coverage

blib/lib/MySQL/Sandbox.pm
Criterion Covered Total %
statement 44 385 11.4
branch 9 202 4.4
condition 1 66 1.5
subroutine 10 38 26.3
pod 0 28 0.0
total 64 719 8.9


line stmt bran cond sub pod time code
1             package MySQL::Sandbox;
2 24     24   116625 use strict;
  24         155  
  24         660  
3 24     24   111 use warnings;
  24         42  
  24         636  
4 24     24   153 use Carp;
  24         50  
  24         2265  
5 24     24   10118 use English qw( -no_match_vars );
  24         75813  
  24         120  
6 24     24   18479 use Socket;
  24         112256  
  24         8603  
7 24     24   172 use File::Find;
  24         42  
  24         1196  
8 24     24   12593 use Data::Dumper;
  24         141529  
  24         1590  
9              
10 24     24   164 use base qw( Exporter);
  24         44  
  24         10004  
11             our @ISA= qw(Exporter);
12             our @EXPORT_OK= qw( is_port_open
13             runs_as_root
14             mylogin_cnf_exists
15             exists_in_path
16             is_a_sandbox
17             find_safe_port_and_directory
18             first_unused_port
19             get_sandbox_params
20             is_sandbox_running
21             get_sb_info
22             get_ports
23             get_ranges
24             use_env
25             sbinstr
26             get_json_from_dirs
27             get_option_file_contents
28             validate_json_object
29             fix_server_uuid
30             greater_version
31             split_version
32             deprecation_notice
33             ) ;
34              
35             our $VERSION=q{3.2.18};
36             our $DEBUG;
37              
38             BEGIN {
39 24   50 24   294 $DEBUG = $ENV{'SBDEBUG'} || $ENV{'SBVERBOSE'} || 0;
40 24 50       90 if (! $ENV{'USER'})
41             {
42 24         88059 my $user = qx/whoami/;
43 24         575 chomp $user;
44 24         851 $ENV{'USER'} = $user;
45             }
46 24         300 for my $var (qw( HOME USER PWD ))
47             {
48 72 50       539 unless ($ENV{$var}) {
49 0         0 die "The variable \$$var is undefined - aborting\n";
50             }
51             }
52 24 50       484 if ($ENV{HOME} =~ /\s/)
53             {
54 0         0 die "# The variable \$HOME contains spaces. Please fix this problem before continuing\n(HOME='$ENV{HOME}')\n";
55             }
56 24 50       258 unless ( $ENV{SANDBOX_HOME} ) {
57 24         472 $ENV{SANDBOX_HOME} = "$ENV{HOME}/sandboxes";
58             }
59              
60 24 50       231 unless ($ENV{TMPDIR})
61             {
62 24         357 $ENV{TMPDIR} = '/tmp';
63             }
64 24 50       755 unless ( -d $ENV{TMPDIR})
65             {
66 0         0 die "could not find $ENV{TMPDIR}\n";
67             }
68              
69 24 50       424 if ( -d "$ENV{HOME}/sandboxes" ) {
70 0   0     0 $ENV{SANDBOX_HOME} = $ENV{SANDBOX_HOME} || "$ENV{HOME}/sandboxes";
71             }
72              
73 24 50       391 unless ( $ENV{SANDBOX_BINARY} ) {
74 24 50       401 if ( -d "$ENV{HOME}/opt/mysql") {
75 0         0 $ENV{SANDBOX_BINARY} = "$ENV{HOME}/opt/mysql";
76             }
77             else
78             {
79 24         116808 $ENV{SANDBOX_BINARY} = '';
80             }
81             }
82             }
83              
84             my @supported_versions = qw( 3.23 4.0 4.1 5.0 5.1 5.2 5.3 5.4
85             5.5 5.6 5.7 6.0 7.0 7.1 7.2 7.3 7.4 7.5 7.6 8.0 10.0 10.1 10.2 10.3 10.4 );
86              
87             our $sandbox_options_file = "my.sandbox.cnf";
88             # our $sandbox_current_options = "current_options.conf";
89              
90             our %default_base_port = (
91             replication => 11000,
92             circular => 14000,
93             multiple => 7000,
94             custom => 5000,
95             );
96              
97             our %default_users = (
98             db_user => 'msandbox',
99             remote_access => '127.%',
100             db_password => 'msandbox',
101             ro_user => 'msandbox_ro',
102             rw_user => 'msandbox_rw',
103             repl_user => 'rsandbox',
104             repl_password => 'rsandbox',
105             );
106              
107             our $SBINSTR_SH_TEXT =<<'SBINSTR_SH_TEXT';
108             if [ -f "$SBINSTR" ]
109             then
110             echo "[`basename $0`] - `date "+%Y-%m-%d %H:%M:%S"` - $@" >> $SBINSTR
111             fi
112             SBINSTR_SH_TEXT
113              
114              
115              
116             sub new {
117 0     0 0 0 my ($class) = @_;
118 0         0 my $self = bless {
119             parse_options => undef,
120             options => undef,
121             }, $class;
122             # my $version = get_version( $install_dir);
123             # $self->{version} = $VERSION;
124 0         0 return $self;
125             }
126              
127             sub parse_options {
128 0     0 0 0 my ($self, $opt ) = @_;
129             # print "<", ref($opt) , ">\n";
130 0 0       0 unless (ref($opt) eq 'HASH') {
131 0         0 confess "parse_options must be a hash reference\n";
132             }
133 0 0       0 if ($opt) {
134 0         0 $self->{parse_options} = $opt;
135             }
136 0         0 my %options = map { $_ , $opt->{$_}{'value'}} keys %{$opt};
  0         0  
  0         0  
137 0         0 $self->{options} = \%options;
138              
139 0         0 return $self->{options};
140             }
141              
142             sub find_safe_port_and_directory {
143 0     0 0 0 my ($wanted_port, $wanted_dir, $upper_directory) = @_;
144 0         0 my $chosen_port = $wanted_port;
145 0         0 my ($ports, undef) = get_sb_info( $ENV{SANDBOX_HOME}, undef);
146             # print Dumper($ports);
147 0   0     0 while ( is_port_open($chosen_port) or exists $ports->{$chosen_port}) {
148 0         0 $chosen_port++;
149 0         0 $chosen_port = first_unused_port($chosen_port);
150             # print "checking -> $chosen_port\n";
151             }
152 0         0 my $suffix = 'a';
153 0         0 my $chosen_dir = $wanted_dir;
154 0         0 while ( -d "$upper_directory/$chosen_dir" ) {
155             # print "checking -> $chosen_dir\n";
156 0         0 $chosen_dir = $wanted_dir . '_' . $suffix;
157 0         0 $suffix++;
158             }
159 0         0 return ($chosen_port, $chosen_dir);
160             }
161              
162             sub deprecation_notice {
163 0     0 0 0 print "#############################################################################\n";
164 0         0 print "# IMPORTANT NOTICE #\n";
165 0         0 print "# ------------------------------------------------------------------------- #\n";
166 0         0 print "# MySQL-Sandbox is NOT MAINTAINED anymore. #\n";
167 0         0 print "# It may fail on recent MySQL versions. #\n";
168 0         0 print "# You should use **dbdeployer** (https://github.com/datacharmer/dbdeployer) #\n";
169 0         0 print "#############################################################################\n";
170 0         0 print "\n";
171             }
172              
173             sub get_help {
174 0     0 0 0 my ($self, $msg) = @_;
175 0 0       0 if ($msg) {
176 0         0 warn "[***] $msg\n\n";
177             }
178              
179 0         0 my $HELP_MSG = q{};
180 0         0 for my $op (
181 0         0 sort { $self->{parse_options}->{$a}{so} <=> $self->{parse_options}->{$b}{so} }
182 0         0 grep { $self->{parse_options}->{$_}{parse}} keys %{ $self->{parse_options} } ) {
  0         0  
183 0         0 my $param = $self->{parse_options}->{$op}{parse};
184 0         0 my $param_str = q{ };
185 0         0 my ($short, $long ) = $param =~ / (?: (\w) \| )? (\S+) /x;
186 0 0       0 if ($short) {
187 0         0 $param_str .= q{-} . $short . q{ };
188             }
189 0         0 $long =~ s/ = s \@? / = name/x;
190 0         0 $long =~ s/ = i / = number/x;
191 0         0 $param_str .= q{--} . $long;
192 0         0 my $lparam = 40 - length($param_str);
193 0 0       0 if ($lparam < 0)
194             {
195 0         0 $lparam = 0;
196             }
197 0         0 $param_str .= (q{ } x $lparam );
198 0         0 my $text_items = $self->{parse_options}->{$op}{help};
199 0         0 for my $titem (@{$text_items}) {
  0         0  
200 0         0 $HELP_MSG .= $param_str . $titem . "\n";
201 0         0 $param_str = q{ } x 40;
202             }
203 0 0       0 if (@{$text_items} > 1) {
  0         0  
204 0         0 $HELP_MSG .= "\n";
205             }
206             # $HELP_MSG .= "\n";
207             }
208              
209             my $VAR_HELP =
210             "\nVARIABLES affecting this program: \n"
211             . "\t\$SBDEBUG : DEBUG LEVEL ("
212             . ($ENV{SBDEBUG} || 0) . ")\n"
213             . "\t\$SBVERBOSE : DEBUG LEVEL (same as \$SBDEBUG) ("
214             . ($ENV{SBVERBOSE} || 0) . ")\n"
215              
216             . "\t\$SANDBOX_HOME : root of all sandbox installations ("
217             . use_env($ENV{SANDBOX_HOME}) . ")\n"
218              
219             . "\t\$SANDBOX_BINARY : where to search for binaries ("
220 0   0     0 . use_env($ENV{SANDBOX_BINARY}) . ")\n"
      0        
221             ;
222              
223 0 0       0 if ( $PROGRAM_NAME =~ /replication|multiple/ ) {
224             $VAR_HELP .=
225             "\t\$NODE_OPTIONS : options to pass to all node installations ("
226 0   0     0 . ($ENV{NODE_OPTIONS} || '') . ")\n"
227             }
228              
229 0 0       0 if ( $PROGRAM_NAME =~ /replication/ ) {
230             $VAR_HELP .=
231             "\t\$MASTER_OPTIONS : options to pass to the master installation ("
232             . ($ENV{MASTER_OPTIONS} || '') . ")\n"
233              
234             . "\t\$SLAVE_OPTIONS : options to pass to all slave installations ("
235 0   0     0 . ($ENV{SLAVE_OPTIONS} || '' ) . ")\n"
      0        
236             }
237 0         0 my $target = '';
238 0 0       0 if ( grep {$PROGRAM_NAME =~ /$_/ }
  0         0  
239             qw( make_sandbox make_replication_sandbox
240             make_multiple_sandbox make_multiple_sandbox ) )
241             {
242 0         0 $target = '{tarball|dir|version}';
243 0         0 $HELP_MSG =
244             "tarball = the full path to a MySQL binary tarball\n"
245             . "dir = the path to an expanded MySQL binary tarball\n"
246             . "version = the simple version number of the expanded tarball\n"
247             . " if it is under \$SANDBOX_BINARY and renamed as the\n "
248             . " version number.\n\n"
249             . $HELP_MSG;
250             }
251 0         0 deprecation_notice();
252 0         0 print $self->credits(),
253             "syntax: $PROGRAM_NAME [options] $target \n",
254             $HELP_MSG,
255             $VAR_HELP;
256             # This example is only relevant for a single sandbox, but it is
257             # wrong for a multiple sandbox.
258             #,
259             #"\nExample:\n",
260             #" $PROGRAM_NAME --my_file=large --sandbox_directory=my_sandbox\n\n";
261              
262 0         0 deprecation_notice();
263 0         0 exit(1);
264             }
265              
266             sub credits {
267 1     1 0 2 my ($self) = @_;
268 1         3 my $CREDITS =
269             qq( The MySQL Sandbox, version $VERSION\n)
270             . qq( (C) 2006-2018 Giuseppe Maxia\n);
271 1         30 return $CREDITS;
272             }
273              
274             sub split_version
275             {
276 0     0 0   my ($v) = @_;
277             #if ($v =~ /(?\d+)\.(?\d+)\.(?\d+)/ )
278 0 0         if ($v =~ /(\d+)\.(\d+)\.(\d+)/ )
279             {
280             #return ($+{major}, $+{minor}, $+{rev})
281 0           return ($1, $2, $3)
282              
283             }
284             else
285             {
286 0           die "# Split version: could not get components from <$v>\n";
287             }
288             }
289              
290             sub greater_version
291             {
292 0     0 0   my ($v1, $v2) = @_;
293              
294 0           my ($v1_major, $v1_minor, $v1_rev) = split_version($v1);
295 0           my ($v2_major, $v2_minor, $v2_rev) = split_version($v2);
296 0 0 0       if ( $v1_major > $v2_major)
    0 0        
    0 0        
297             {
298 0           return 1;
299             }
300             elsif ( ($v1_major == $v2_major) && ($v1_minor > $v2_minor))
301             {
302 0           return 1;
303             }
304             elsif ( ($v1_major == $v2_major) && ($v1_minor == $v2_minor) && ($v1_rev > $v2_rev) )
305             {
306 0           return 1;
307             }
308 0           return 0
309             }
310              
311              
312             sub fix_server_uuid
313             {
314 0     0 0   my ($server_id, $version, $port, $sandbox_directory) = @_;
315 0 0         if ($version =~ /(\d+)\.(\d+)/)
316             {
317 0           my ($major, $minor ) = ($1, $2);
318 0 0 0       unless ( ($major == 8) or ( ($major == 5) && ($minor >=6)) )
      0        
319             {
320 0           return;
321             }
322             }
323 0           my $current_dir = $ENV{PWD};
324 0           my $increase_id = 0;
325 0           $sandbox_directory =~ s{/$}{};
326 0           my $operation_dir= "$sandbox_directory/data";
327 0 0         if ( ! -d $operation_dir)
328             {
329 0           die "<$operation_dir> not found\n";
330             }
331 0           chdir $operation_dir;
332 0 0         print "# operation_dir is $operation_dir\n" if $DEBUG;
333 0 0 0       if ( ($operation_dir =~ m{/node\d/data$}) && (-d "../../master"))
334             {
335 0           $increase_id =1;
336             }
337             # 12345678 1234 1234 1234 123456789012
338             # my $new_uuid='00000000-0000-0000-0000-000000000000';
339 0           my $group1 = sprintf('%08d', $port);
340              
341 0           my $group2= sprintf('%04d-%04d-%04d-%012d', 0,0,0,0);
342 0 0 0       if ($server_id < 10)
    0          
343             {
344 0           $group2 =~ s/\d/$server_id/g;
345             }
346             elsif (($server_id >= 100) && ($server_id < 109))
347             {
348 0           $server_id -= 100;
349 0 0         $server_id += 1 if $increase_id; # 101 => 2
350 0           $group2 =~ s/\d/$server_id/g;
351             }
352             else
353             {
354 0           my $second_id = $server_id;
355 0 0         if ($second_id > 9999)
356             {
357 0           $second_id = 9999;
358             }
359 0           $group2 = sprintf( '%04d-%04d-%04d-%012d', $second_id, $second_id, $second_id, $server_id );
360             }
361 0           my $new_uuid= "$group1-$group2";
362 0 0         open my $FH, '>', 'auto.cnf'
363             or die "Error updating 'auto.cnf' ($!)\n";
364 0           print $FH "[auto]\n";
365 0           print $FH "server-uuid=$new_uuid\n";
366 0           close $FH;
367 0           chdir $current_dir;
368 0 0         print "New UUID=$new_uuid\n" if $DEBUG;
369             }
370              
371             sub validate_json_object {
372 0     0 0   my ($json_filename, $json_text) = @_;
373              
374 0           my $JSON_module = undef;
375 0           for my $module ( 'JSON', 'JSON::PP', 'JSON::XS')
376             {
377 0           eval "use $module;";
378 0 0         if (! $@)
379             {
380 0 0         print "# Using $module\n" if $DEBUG;
381 0           $JSON_module=$module;
382 0           last;
383             }
384             }
385 0 0         unless ($JSON_module)
386             {
387 0 0         print "# JSON modules not installed - skipped evaluation\n" if $DEBUG;
388 0           return -1;
389             }
390              
391 0 0         unless ($json_text)
392             {
393 0           $json_text = slurp($json_filename);
394             }
395 0           my $json = $JSON_module->new->allow_nonref;
396              
397 0           my $perl_value;
398 0           eval {
399 0           $perl_value = $json->decode( $json_text );
400             };
401 0 0         if ($@)
402             {
403 0 0         print "error decoding json object\n" if $DEBUG;
404 0           return ;
405             }
406 0           return 1;
407             }
408              
409             sub slurp {
410 0     0 0   my ($filename, $skip_blanks, $skip_comments ) = @_;
411 0 0         open my $FH , q{<}, $filename
412             or die "file '$filename' not found\n";
413 0           my @text_array = ();
414 0           my $text='';
415 0           while (my $line = <$FH>)
416             {
417 0 0         if ($skip_blanks)
418             {
419 0 0         next if $line =~ /^\s*$/;
420             }
421 0 0         if ($skip_comments)
422             {
423 0 0         next if $line =~ /^\s*#/;
424             }
425 0 0         if (wantarray)
426             {
427 0           push @text_array, $line;
428             }
429             else
430             {
431 0           $text .= $line;
432             }
433             }
434 0           close $FH;
435 0 0         if (wantarray)
436             {
437 0           return @text_array;
438             }
439             else
440             {
441 0           return $text;
442             }
443             }
444              
445             sub get_json_from_dirs {
446 0     0 0   my ($directories, $json_file) = @_;
447 0           my $collective_json = '';
448 0           my $indent = ' ';
449 0           for my $dir (@$directories)
450             {
451 0           my $filename = "$dir/$json_file";
452 0 0         if ($collective_json)
453             {
454 0           $collective_json .= ",\n"
455             }
456             else
457             {
458 0           $collective_json = "{\n";
459             }
460 0           $collective_json .= qq("$dir": \n);
461 0 0         if ( -f $filename)
462             {
463             # get the contents
464 0           my @json_lines = slurp($filename, 'skip_blanks');
465 0           for my $jl (@json_lines)
466             {
467 0           $collective_json .= $indent . $jl;
468             }
469             }
470             else
471             {
472 0 0         if ($DEBUG)
473             {
474 0           warn "# No connection.json found in $dir\n";
475 0           my ($package, $filename, $line) = caller;
476 0           warn "# called from $package - $filename - $line \n";
477             }
478 0           $collective_json .= "{}";
479             }
480             }
481 0           $collective_json .= "}";
482 0           my $is_valid_json = validate_json_object(undef, $collective_json);
483 0 0 0       if ($is_valid_json && ($is_valid_json == -1))
    0          
484             {
485 0 0         if ($DEBUG)
486             {
487 0           warn "# Could not validate JSON object\n";
488             }
489             }
490             elsif ( ! $is_valid_json)
491             {
492 0           warn "Invalid JSON object in $ENV{PWD} from [@$directories] \n";
493 0           $collective_json = qq({ "comment": "WARNING: invalid JSON object", "original" : )
494             . $collective_json
495             . "\n}";
496             }
497 0           return $collective_json;
498             }
499              
500             #sub get_version {
501             # my ($install_dir) = @_;
502             # open my $VER , q{<}, "$install_dir/VERSION"
503             # #open my $VER , q{<}, "VERSION"
504             # or die "file 'VERSION' not found\n";
505             # my $version = <$VER>;
506             # chomp $version;
507             # close $VER;
508             # return $version;
509             #}
510              
511             sub write_to {
512 0     0 0   my ($self, $fname, $mode, $contents) = @_;
513 0 0         open my $FILE, $mode, $fname
514             or die "can't open file $fname\n";
515 0           print $FILE $contents, "\n";
516 0 0 0       if (($mode eq '>') && ( $contents =~ m/\#!\/bin\/sh/ ) ) {
517 0           print $FILE $SBINSTR_SH_TEXT;
518             }
519 0           close $FILE;
520             }
521              
522             sub supported_versions {
523 0     0 0   return \@supported_versions;
524             }
525              
526             sub is_port_open {
527 0     0 0   my ($port) = @_;
528 0 0         die "No port" unless $port;
529 0           my ($host, $iaddr, $paddr, $proto);
530              
531 0           $host = '127.0.0.1';
532 0 0         $iaddr = inet_aton($host)
533             or die "no host: $host";
534 0           $paddr = sockaddr_in($port, $iaddr);
535              
536 0           $proto = getprotobyname('tcp');
537 0 0         socket(SOCK, PF_INET, SOCK_STREAM, $proto)
538             or die "error creating test socket for port $port: $!";
539 0 0         if (connect(SOCK, $paddr)) {
540 0 0         close (SOCK)
541             or die "error closing test socket: $!";
542 0           return 1;
543             }
544 0           return 0;
545             }
546              
547             sub first_unused_port {
548 0     0 0   my ($port) = @_;
549 0           while (is_port_open($port)) {
550 0           $port++;
551 0 0         if ($port > 0xFFF0) {
552 0           die "no ports available\n";
553             }
554             }
555 0           return $port;
556             }
557              
558             ##
559             # SBtool
560             #
561             sub get_sandbox_params {
562 0     0 0   my ($dir, $skip_strict) = @_;
563 0 0         confess "directory name required\n" unless $dir;
564 0 0         confess "directory $dir doesn't exist\n" unless -d $dir;
565 0 0         unless (is_a_sandbox($dir)) {
566 0 0         confess "directory <$dir> must be a sandbox\n" unless $skip_strict;
567             }
568 0           my %params = (
569             opt => undef,
570             conf => undef
571             );
572 0 0         if ( -f "$dir/$sandbox_options_file" ) {
573 0           $params{opt} = get_option_file_contents("$dir/$sandbox_options_file");
574             }
575             else {
576             # warn "options file $dir not found\n";
577 0           return;
578             }
579             # if ( -f "$dir/$sandbox_current_options" ) {
580             # $params{conf} =
581             # get_option_file_contents("$dir/$sandbox_current_options");
582             # }
583             # else {
584             # # warn "current conf file not found\n";
585             # return;
586             # }
587 0           return \%params;
588             }
589              
590             sub get_option_file_contents {
591 0     0 0   my ($file) = @_;
592 0 0         confess "file name required\n" unless $file;
593 0 0         confess "file $file doesn't exist\n" unless -f $file;
594 0           my %options;
595 0 0         open my $RFILE, q{<}, $file
596             or confess "can't open file $file\n";
597 0           while ( my $line = <$RFILE> ) {
598 0 0         next if $line =~ /^\s*$/;
599 0 0         next if $line =~ /^\s*#/;
600 0 0         next if $line =~ /^\s*\[/;
601 0           chomp $line;
602 0           my ( $key, $val ) = split /\s*=\s*/, $line;
603 0           $key =~ s/-/_/g;
604 0           $options{$key} = $val;
605             }
606 0           close $RFILE;
607             # print Dumper(\%options) ; exit;
608 0           return \%options;
609             }
610              
611             sub get_sb_info {
612 0     0 0   my ($search_path, $options) = @_;
613 0           my %ports = ();
614 0           my %all_info = ();
615 0           my $seen_dir = '';
616              
617             find(
618             {
619             no_chdir => 1,
620             follow => 1,
621             wanted => sub {
622 0 0   0     if ( $seen_dir eq $File::Find::dir ) {
623 0           return;
624             }
625 0           my $params;
626 0 0         if ( $params = get_sandbox_params($File::Find::dir, 1) ) {
627 0           $seen_dir = $File::Find::dir;
628 0           my $port = $params->{opt}{port};
629 0 0 0       if ( -f $params->{opt}{pid_file}
630             && -e $params->{opt}{socket} )
631             {
632 0           $ports{$port} = 1;
633 0 0         $all_info{$port} = $params if $options->{all_info};
634             }
635             else {
636 0 0         unless ( $options->{only_used} ) {
637 0           $ports{$port} = 0;
638 0 0         $all_info{$port} = $params if $options->{all_info};
639             }
640             }
641             }
642             }
643             },
644             $search_path || $options->{search_path}
645 0   0       );
646 0           return ( \%ports, \%all_info );
647             }
648              
649             sub is_a_sandbox {
650 0     0 0   my ($dir) = @_;
651 0 0         unless ($dir) {
652 0           confess "directory missing\n";
653             }
654 0           $dir =~ s{/$}{};
655 0           my %sandbox_files = map {s{.*/}{}; $_, 1 } glob("$dir/*");
  0            
  0            
656 0           my @required = (qw(data start stop send_kill clear use restart),
657             # $sandbox_current_options,
658             $sandbox_options_file );
659 0           for my $req (@required) {
660 0 0         unless (exists $sandbox_files{$req}) {
661 0           return;
662             }
663             }
664 0           return 1;
665             }
666              
667             sub is_sandbox_running {
668 0     0 0   my ($sandbox) = @_;
669 0 0         unless ( -d $sandbox ) {
670 0           confess "Can't see if it's running. <$sandbox> is not a sandbox\n";
671             }
672 0           my $sboptions = get_sandbox_params($sandbox);
673 0 0 0       unless ($sboptions->{opt}
      0        
674             && $sboptions->{opt}{'pid_file'}
675             && $sboptions->{opt}{'socket'}) {
676             # print Dumper($sboptions);
677 0           confess "<$sandbox> is not a single sandbox\n";
678             }
679 0 0 0       if ( ( -f $sboptions->{opt}{'pid_file'} )
680             && ( -e $sboptions->{opt}{'socket'}) ) {
681 0           return (1, $sboptions);
682             }
683             else {
684 0           return (0, $sboptions);
685             }
686             }
687              
688             sub get_ranges {
689 0     0 0   my ($options, $silent ) = @_;
690 0           my ( $ports, $all_info ) = get_sb_info(undef, $options);
691 0           my $minimum_port = $options->{min_range};
692 0           my $maximum_port = $options->{max_range};
693 0           my $range_size = $options->{range_size};
694 0 0         if ( $minimum_port >= $maximum_port ) {
695 0           croak "minimum range must be lower than the maximum range\n";
696             }
697 0 0         if ( ( $minimum_port + $range_size ) > $maximum_port ) {
698 0           croak "range too wide for given boundaries\n";
699             }
700 0           my $range_found = 0;
701             range_search:
702 0           while ( !$range_found ) {
703 0 0         if ( $minimum_port >= $maximum_port ) {
704 0           croak "can't find a range of $range_size "
705             . "free ports between "
706             . "$options->{min_range} and $options->{max_range}\n";
707             }
708 0           for my $i ( $minimum_port .. $minimum_port + $range_size ) {
709 0 0 0       if ( exists $ports->{$i} or ( $i >= $maximum_port ) ) {
710 0           $minimum_port = $i + 1;
711 0           next range_search;
712             }
713             }
714 0           $range_found = 1;
715             }
716 0 0         unless ($silent) {
717 0           printf "%5d - %5d\n", $minimum_port , $minimum_port + $range_size;
718             }
719 0           return $minimum_port;
720             }
721              
722             sub get_ports {
723 0     0 0   my ($options) = @_;
724 0           my ( $ports, $all_info ) = get_sb_info(undef, $options);
725              
726 0 0         if ( $options->{format} eq 'perl' ) {
    0          
727 0           print Data::Dumper->Dump( [$ports], ['ports'] );
728             print Data::Dumper->Dump( [$all_info], ['all_info'] )
729 0 0         if $options->{all_info};
730             }
731             elsif ( $options->{format} eq 'text' ) {
732 0           for my $port ( sort { $a <=> $b } keys %$ports ) {
  0            
733 0           printf "%5d %2d\n", $port, $ports->{$port};
734             }
735             }
736             else {
737 0           croak "unrecognized format -> $options->{format}\n";
738             }
739 0           return ( $ports, $all_info );
740             }
741              
742             sub exists_in_path {
743 0     0 0   my ($cmd) = @_;
744 0           my @path_directories = split /:/, $ENV{PATH}; ## no critic
745 0           for my $dir (@path_directories) {
746 0 0         if ( -x "$dir/$cmd") {
747 0           return "$dir/$cmd";
748             }
749             }
750 0           return ;
751             }
752              
753             sub runs_as_root {
754 0 0 0 0 0   if ( ($REAL_USER_ID == 0) or ($EFFECTIVE_USER_ID == 0)) {
755 0 0         unless ($ENV{SANDBOX_AS_ROOT}) {
756 0           die "MySQL Sandbox should not run as root\n"
757             . "\n"
758             . "If you know what you are doing and want to\n "
759             . "run as root nonetheless, please set the environment\n"
760             . "variable 'SANDBOX_AS_ROOT' to a nonzero value\n";
761             }
762             }
763             }
764              
765             sub mylogin_cnf_exists {
766 0     0 0   my $mylogin_cnf = "$ENV{HOME}/.mylogin.cnf";
767 0 0         if ( -r $mylogin_cnf) {
768 0 0         unless ($ENV{IGNORE_MYLOGIN_CNF}) {
769 0           die "MySQL Sandbox does not work with \$HOME/.mylogin.cnf,\n"
770             . "which is a file created by mysql_config_editor.\n"
771             . "Either remove the file or make it not readable by the current user.\n"
772             . "If you know what you are doing, you can skip this check by\n"
773             . "setting the variable IGNORE_MYLOGIN_CNF to a nonzero value.\n"
774             . "Be aware that having \$HOME/.mylogin.cnf can disrupt MySQL-Sandbox.\n"
775             . "Use it at your own risk.\n"
776             }
777             }
778             }
779              
780             #
781             # Replaces a path portion with an environment variable name
782             # if a match is found
783             #
784             sub use_env{
785 0     0 0   my ($path) = @_;
786 0           my @vars = (
787             'HOME',
788             'SANDBOX_HOME',
789             );
790 0 0         return '' unless $path;
791 0           for my $var (@vars) {
792 0 0         if ($path =~ /^$ENV{$var}/) {
793 0           $path =~ s/$ENV{$var}/\$$var/;
794 0           return $path;
795             }
796             }
797 0           return $path;
798             }
799              
800             sub sbinstr {
801 0     0 0   my ($msg) = @_;
802 0 0         unless ($ENV{SBINSTR}) {
803 0           return;
804             }
805 0           my $pname = $PROGRAM_NAME;
806 0 0         unless ($DEBUG) {
807 0           $pname =~ s{.*/}{};
808             }
809             open my $FH, '>>', $ENV{SBINSTR}
810 0 0         or die "can't write to $ENV{SBINSTR} ($!)\n";
811 0           my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
812 0           $mon++;
813 0           $year +=1900;
814 0           print $FH "[$pname] - ",
815             sprintf('%4d-%02d%02d %02d:%02d:%02d',
816             $year, $mon, $mday, $hour, $min, $sec),
817             " - $msg \n";
818 0           close $FH;
819             }
820              
821             1;
822             __END__