#!/usr/bin/perl
#
# Copyright (c) 2006 Zmanda Inc.  All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
#
# Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
#
#

#
# The objective of this module ot to provide some common functionality 
# across ZRM.
#

package ZRM::MySQL;

use strict;
use warnings;

use File::Spec::Functions;
use Fcntl ':flock';
use File::Temp qw/ :POSIX /;
use File::Basename;

use lib "/usr/lib/mysql-zrm";
use ZRM::Common;

require Exporter;


use vars qw(@ISA @EXPORT_OK);
our @ISA = qw(Exporter);

our @EXPORT = qw( $MYSQL_BIN_PATH $MYSQL $MYSQLADMIN $MYSQLHOTCOPY $MYSQL_WINDOWS $MYSQL_NIX $binLog $datadir $slave_load_tmpdir $mysql_version $mysql_server_os $have_innodb $innodb_shared_data_on_fs $innodb_log_dir @innodb_shared_data_files $mysql_shutdown &addMySQLParams &extractValue &shutdownMySQL &isSlave &stopSlave &startSlave &getMySQLVariables &checkForWrongHostInputs &checkForRemoteHost &checkForCompressEncryptPlugin &verifyInputs &checkDirs &initMySQL $isMyDumper);

our $MYSQL_BIN_PATH;
our $MYSQL="mysql";
our $MYSQLADMIN="mysqladmin";
our $MYSQLHOTCOPY="mysqlhotcopy";
our $MYSQL_WINDOWS="Windows";
our $MYSQL_NIX="Linux/Unix";

our $binLog="OFF";
our $default_backupset="BackupSet1";
our $datadir;
our $slave_load_tmpdir;
our $mysql_version;
our $mysql_server_os = $MYSQL_NIX;
our $have_innodb = "NO";
our $innodb_shared_data_on_fs = 1;
our $innodb_log_dir;
our @innodb_shared_data_files;
our $mysql_shutdown = 0;
our $slaveStopped = 0;

my $copyPluginSpecified = 0;
our $isMyDumper=0;

$inputs{"backup-level"}="0";
$inputs{"backup-mode"}="raw";


#Adds the mysql related parameters from the command line to the mysql command
#$_[0] specifies the mysql command
sub addMySQLParams()
{
	my $comm = $_[0];
	if($inputs{"copy-plugin"} && $_[0] eq $inputs{"copy-plugin"}){
		if( $mysql_server_os eq $MYSQL_WINDOWS ){
                	$comm = "\"$comm\"";
			$comm .= " --vsscopy";
		}else{
			if($MYSQL_BIN_PATH){
				$comm .= " --mysqlhotcopy=$MYSQL_BIN_PATH";
			}else{
				$comm .= " --mysqlhotcopy";
			}
		}
	}else{
		if( $MYSQL_BIN_PATH ){
			$comm = catfile( "\"".$MYSQL_BIN_PATH."\"", $comm );
		}
	}
	if( $inputs{user} ) {
		$comm .= " --user=\"$inputs{user}\"";
	}
	if( $inputs{password} ) {
		$comm .= " --password=\"$inputs{password}\"";
	}
	if( $inputs{host} ) {
		$comm .= " --host=\"$inputs{host}\"";
	}
	if( $inputs{port} ) {
		$comm .= " --port=\"$inputs{port}\"";
	}
	if( $inputs{socket} ){
		$comm .= " --socket=\"$inputs{socket}\"";
	}
	if( $inputs{"ssl-options"} ){
		if( $_[0] ne $MYSQLHOTCOPY ) {
			if( $inputs{"copy-plugin"} &&
			    $_[0] eq $inputs{"copy-plugin"} ){
			    	if( $mysql_server_os eq $MYSQL_WINDOWS ){
					$comm .= " ".$inputs{"ssl-options"};
				}
			}else{
				$comm .= " ".$inputs{"ssl-options"};
			}
		}
	}
	return $comm;
}

#extracts required value from the output of "mysqladmin variables"
#$_[0] arg name
#$_[1] full string
sub extractValue()
{
        if( $_[1] =~ /\n\|*\s+$_[0]\s+\|([^\|]+)\|*\n/ ){
                if( $1 ne "|" ){
                        my $x = $1;
                        $x=~ s/^\s+//;
                        $x=~ s/\s+$//;
                        return $x;
                }
        }
}

#Shuts down mysql using "mysqladmin shutdown" command
sub shutdownMySQL()
{
	my $y = &addMySQLParams($MYSQLADMIN);
	my $x = " shutdown";
	if( $verbose ) {
		&printLog( "Shutting down MySQL\n" );
	}
	$x = system( "$y $x" );
	if( $x > 0 ) {
		&printAndDie( "Unable to shutdown MySQL\n" );
	}
	$mysql_shutdown = 1;
}

#Checks if the mysql server is a slave
sub isSlave()
{
        if( !$inputs{replication} || $inputs{replication} eq "0" ) {
                return 0;
        }
        my $p = &addMySQLParams($MYSQL);
        my $command = "$p -e \"show slave status\"";
        if( $verbose ) {
                &printLog( "Checking if this is a replication slave using command\n" );
                &printLog( $command."\n" );
        }
        my $r = &execCmdAndGetOutput($command);
        if( !defined $r or $r eq "" ) {
                if( $verbose ) {
                        &printLog( "This is not a replication slave or we do not have appropriate access rights. Replication data if any has not been backed up.\n" );
                        &printLog( " Ignoring the --replication option\n" );
                }
                return 0;
        }
        return 1;
}

#Stops the replication slave
sub stopSlave()
{
        my $x = &addMySQLParams($MYSQLADMIN);
        my $command = " stop-slave > ".$LOGGER;
        if( $verbose ) {
                &printLog( "Stoping slave using command\n" );
                &printLog( $x.$command."\n" );
        }
        my $y = system( $x.$command );
        if( $y > 0 ) {
                &printError( "Error stopping slave\n" );
                &printError( "Replication data will not be backed up.\n" );
                &printCommandOutputToLog( "ERROR", $MYSQLADMIN, $LOGGER );
                return 0;
        }else{
		$slaveStopped = 1;
                if( $verbose ){
                        &printCommandOutputToLog( "INFO", $MYSQLADMIN, $LOGGER );
                }
        }
        return 1;
}

#Starts the replication slave
sub startSlave()
{
	if( ! $slaveStopped ){
		return;
	}
        my $x = &addMySQLParams($MYSQLADMIN);
        my $command = " start-slave > ".$LOGGER."\n";
        if( $verbose ) {
                &printLog( "Restarting slave using command\n" );
                &printLog( $x.$command."\n" );
        }
        my $y = system( $x.$command );
        if( $y > 0 ) {
                &printWarning( "Error starting slave\n" );
                &printCommandOutputToLog( "WARNING", $MYSQLADMIN, $LOGGER );
        }else{
		$slaveStopped = 0;
                if( $verbose ){
                        &printCommandOutputToLog( "INFO", $MYSQLADMIN, $LOGGER );
                }
        }
}

#uses 'mysqladmin variables' and saves all of the relevant ones
sub getMySQLVariables()
{
	#Find the datadir & slave_load_tmpdir
	my $x = &addMySQLParams($MYSQLADMIN);
	#my $p = $x." variables"." 2> ".$LOGGER;
	my $p = $x." variables";
	if( $verbose ) {
		&printLog( "Getting mysql variables\n" );
		&printLog( $p."\n" );
	}
	my $output = &execCmdAndGetOutput( $p );
	if( !defined $output ) {
		&printAndDie( "Cannot connect to mysql server!\n" );
		return;
	}else{
		chomp( $output );
	}
	$datadir = &extractValue( "datadir", $output );
	if( ! defined $datadir || !$datadir ) {
		&printAndDie( "Could not find mysql's datadir\n" );
	}
	if( $verbose ){
		&printLog( "datadir is $datadir\n" );
	}
	if( $datadir =~ /^\w:/ ){
		$mysql_server_os = $MYSQL_WINDOWS;
		$datadir = &backSlashesToForwardSlashes( $datadir );
	}else{
		$mysql_server_os = $MYSQL_NIX;
	}
	$slave_load_tmpdir = &extractValue( "slave_load_tmpdir", $output );
	if( $mysql_server_os eq $MYSQL_WINDOWS ){
		$slave_load_tmpdir = &backSlashesToForwardSlashes( $slave_load_tmpdir );
	}

	$mysql_version = &extractValue( "version", $output );
	if( $verbose ){
		&printLog( "mysql_version is $mysql_version\n" );
	}

	$binLog = &extractValue( "log_bin", $output );
	if( $binLog && $binLog eq "OFF" ){
		&printWarning( "Binary logging is off.\n" );
	}

	$have_innodb = &extractValue( "have_innodb", $output );
	if( defined $have_innodb && $have_innodb eq "YES" ){
		my $innodb_data_home_dir = &extractValue( "innodb_data_home_dir", $output );
		if( $innodb_data_home_dir && $mysql_server_os eq $MYSQL_WINDOWS ){
			$innodb_data_home_dir = &backSlashesToForwardSlashes( $innodb_data_home_dir );
		}
		my $innodb_data_file_path = &extractValue( "innodb_data_file_path", $output );
		my @a = split( /;/, $innodb_data_file_path );
		my $fullP = "";
		foreach( @a ){
			my @b = split( /:/, $_ );
			my $c;
			my $d;
			if( $mysql_server_os eq $MYSQL_WINDOWS ){
				if( $b[1] =~ /^[^\d]/ ) {
#$b[1] =~ /^\// || $b[1] =~ /^\\/ ){
					$b[0] = $b[0].":".$b[1];
				}
				$b[0] = &backSlashesToForwardSlashes( $b[0] );
			}
			if( $innodb_data_home_dir ){
				$c = catfile( $innodb_data_home_dir, $b[0] );
				$d = catfile( $innodb_data_home_dir, $_ );
			}else{
				if( $mysql_server_os eq $MYSQL_WINDOWS ){
					if( $b[0]=~/^\w:/ ){
						$c = $b[0];
						$d = $_;
					}else{
						$c = catfile( $datadir, $b[0] );
						$d = catfile( $datadir, $_ );
					}
				}else{
					if( $b[0]=~/^\// ){
						$c = $b[0];
						$d = $_;
					}else{
						$c = catfile( $datadir, $b[0] );
						$d = catfile( $datadir, $_ );
					}
				}
			}
			$fullP .= "$d;";
			$c = &removeExtraSlashesFromPath( $c );
			push @innodb_shared_data_files, $c;
			if( $b[1]=~/raw$/ ){
				$innodb_shared_data_on_fs = 0;
			}
		}
		chop( $fullP );
		$inputs{"ihb-innodb-data"} = $fullP;
		if( $verbose ){
			&printLog( "InnoDB data file are @innodb_shared_data_files\n" );
		}
		my $innodb_log_group_home_dir = &extractValue( "innodb_log_group_home_dir", $output );
		$innodb_log_group_home_dir = &backSlashesToForwardSlashes( $innodb_log_group_home_dir );

		if( $mysql_server_os eq $MYSQL_WINDOWS ){
			if( $innodb_log_group_home_dir=~/^\w:/ ){
				$innodb_log_dir = $innodb_log_group_home_dir;
			}else{
				$innodb_log_dir = catfile( $datadir, $innodb_log_group_home_dir );
			}
		}else{
			if( $innodb_log_group_home_dir=~/^\// ){
				$innodb_log_dir = $innodb_log_group_home_dir;
			}else{
				$innodb_log_dir = catfile( $datadir, $innodb_log_group_home_dir );
			}
		}
		$innodb_log_dir = &removeExtraSlashesFromPath( $innodb_log_dir );
		$inputs{"ihb-innodb-logs"} = $innodb_log_dir;
		if( $verbose ){
			&printLog( "InnoDB log dir is $innodb_log_dir\n" );
		}
		$inputs{"ihb-datadir"} = $datadir;
		$inputs{"ihb-innodb-log-file-size"} = &extractValue( "innodb_log_file_size", $output );
		$inputs{"ihb-innodb-log-files-in-group"} = &extractValue( "innodb_log_files_in_group", $output );
	}
	if( defined $inputs{"copy-plugin"} ){
		my $name = basename( $inputs{"copy-plugin"} );
		if( $mysql_server_os eq $MYSQL_WINDOWS &&
	    	    $name ne "windows-copy.pl"){
	    	    	&printAndDie( "The copy-plugin ".$inputs{"copy-plugin"}." cannot be used since the mysql server is a windows machine. The only copy plugin supported for windows is the windows copy plugin.\n" );
		}
		if( $mysql_server_os ne $MYSQL_WINDOWS &&
	    	    $name eq "windows-copy.pl"){
	    	    	&printAndDie( "The copy-plugin ".$inputs{"copy-plugin"}." cannot be used since the mysql server is not a windows machine.\n" );
		}
		if( ! -f $inputs{"copy-plugin"} ){
			&printAndDie( "Unable to find copy plugin ".$inputs{"copy-plugin"}."\n" );
		}
	}
}

#$_[0] hostname
sub checkForWrongHostInputs()
{
	if( $_[0] eq "localhost" ){
		return;
	}
	&checkCopyPlugin();
}

sub checkCopyPlugin()
{
	if( ! defined $inputs{"copy-plugin"} ){
		$inputs{"copy-plugin"} = "/usr/share/mysql-zrm/plugins/ssh-copy.pl";
		if( $verbose ){
			&printLog( "Using ".$inputs{"copy-plugin"}." as the default plugin since copy-plugin has not been specified\n" );
		}
	}else{
		$copyPluginSpecified = 1;
		if( ! -f $inputs{"copy-plugin"} ){
			&printAndDie( "Unable to find copy plugin ". $inputs{"copy-plugin"}."\n" );
		}
	}
}

sub checkForRemoteHost()
{
	if( $inputs{"host"} ){
		&checkForWrongHostInputs( $inputs{"host"} );
	}elsif( defined $ENV{"MYSQL_HOST"} ){
		&printLog( "Environment variable MYSQL_HOST specified as $ENV{MYSQL_HOST}\n" );
		$inputs{"hosts"} = $ENV{"MYSQL_HOST"};
		&checkForWrongHostInputs( $ENV{"MYSQL_HOST"} );
	}
}

#$_[0] either "pre-backup" or "post-backup"
sub checkForPrePostPlugin()
{
        my $name = $_[0];
        my $plugin = "$name-plugin";
        if( ! defined $inputs{$plugin} ){
                return;
        }
        if( ! -f $inputs{$plugin} ){
                &printAndDie( "$plugin ".$inputs{$plugin}." not found\n" );
        }else{
        	if( ! -x $inputs{$plugin} ){
                	&printAndDie( "$plugin ".$inputs{$plugin}." not executable\n" );
        	}
	}
}


#$_[0] either "encrypt" or "compress"
sub checkForCompressEncryptPlugin()
{
	my $name = $_[0];
	if( ! defined $inputs{$name} ){
		return;
	}
	if ( $onWindows && $name eq "encrypt" ) {
		eval "use Win32";
		my @a = Win32::FsType();

		if ( ! $a[1] & hex(0x00020000) ) {
			&printLog( "No Encryption support in FS\n" );
		}
		return;
	}

	my $plugin = "$name-plugin";
        if( $inputs{$name} != 0 ){
		if( defined $inputs{$plugin} ){
		    	if( ! -f $inputs{$plugin} ){
		 		&printAndDie( "$name plugin ".$inputs{$plugin}." not found\n" );
			}
			$inputs{$name} = $inputs{$plugin};
		}else{
			$inputs{$name} = "";
		}
		if( $inputs{"backup-type"} eq "quick" ){
			&printLog( "since backup-type is quick, the $name option will be ignored\n" );
		}
	}else{
		print "DELETING\n";
		delete $inputs{$name};
	}
}

# $_[0] database name
sub buildTableList()
{
	my $command = &addMySQLParams($MYSQL);
	$command = $command." -e \"show tables\" $_[0] ";
	if( $verbose ) {
                &printLog( "Command used for getting engine type ".$command."\n" );
        }
        my $x = &execCmdAndGetOutput( $command );
        if( !defined $x ) {
                &printAndDie( "Could not find storage engine for tables in database $_[0]. Command used is ".$command."\n" );
        }
	my @out = split( "\n", $x );
	#Remove the header
        shift @out;
	chomp( @out );
	@out = &filterPattern( @out );
	my $l = @out;
	if( $l == 0 ){
		&printAndDie( "Nothing to backup after exclude pattern is applied\n" );
	}
	return join( " ", @out );
}

#Checks what databases/tables are being backed up
sub checkBackupWhat()
{
	if( defined $inputs{"exclude-pattern"} ){
		$inputs{"exclude-pattern"} = &convertGlobToPattern( $inputs{"exclude-pattern"} );
	}
	if( $inputs{"tables"} ){
		if( !($inputs{"database"}) ) {
			&printAndDie("Please specify 'database'  when using 'tables' \n" );
		}
		if( $inputs{"databases"} ){
			&printWarning("'databases' specified will be ignored since 'database' and 'tables' has been specified \n" );
		}
		if( $inputs{"all-databases"} ){
			&printWarning( "'all-databases' will be ignored since 'database' and 'tables' has been specified \n" );
		}
		my @tt = split( " ", $inputs{"tables"} );
		@tt = &filterPattern( @tt );
		my $l = @tt;
		if( $l == 0 ){
			&printAndDie( "Nothing to backup after exclude pattern is applied\n" );
		}
		$inputs{"tables"} = join( " ", @tt );
		if( $verbose ){
			&printLog( "List of tables to be backed up: ".$inputs{"table"}."\n" );
		}
	}elsif( $inputs{"database"} ){
		if( $inputs{"databases"} ){
			&printWarning( "'databases' will be ignored since 'database' has been specified\n" );
		}
		if( $inputs{"all-databases"} ){
			&printWarning( "'all-databases' will be ignored since 'database' has been specified \n" );
		}
		if( defined $inputs{"exclude-pattern"} ){
			$inputs{"tables"} = &buildTableList( $inputs{"database"} );
			if( $verbose ){
				&printLog( "List of tables to be backed up: ".$inputs{"tables"}."\n" );
			}
		}else{
			$inputs{"databases"} = $inputs{"database"};
		}
	}elsif( $inputs{"databases"} ){
		if( $inputs{"all-databases"} ){
			&printWarning( "'all-databases' will be ignored since 'databases' has been specified \n" );
		}
	}
}

sub checkForSnapshot()
{
	if( ! defined $inputs{"backup-type"} ){
		$inputs{"backup-type"} = "regular";
	}
	if( $inputs{"backup-type"} ne "regular" && $inputs{"backup-type"} ne "quick" ){
		&printAndDie( "Specified backup-type not correct. Please specify either 'regular' or 'quick'.\n" );
	}
	if( $inputs{"backup-level"} == 1 ){
		$inputs{"backup-type"} = "regular";
	}

	if( $inputs{"backup-mode"} eq "logical" ){
		$inputs{"backup-type"} = "regular";
	    	&printLog( "The quick backup-type is supported only for snapshot backups. Setting backup-type to 'regular'\n" );
	}
	if( $inputs{"backup-type"} eq "quick" ){
		if( defined $inputs{"copy-plugin"} ){
			my $name = basename( $inputs{"copy-plugin"} );
			if( $name eq "windows-copy.pl"){
				$inputs{"backup-type"} = "regular";
	    			&printLog( "The quick backup-type is not supported on windows. Setting backup-type to 'regular'\n" );
			}
		}
		$inputs{"synchronous-checksum"} = -1;
	}
	if( ! defined $inputs{"snapshot-plugin"} ){
		if( defined $inputs{"lvm-snapshot"} || $inputs{"snapshot-size"} ){
			$inputs{"snapshot-plugin"} = "/usr/share/mysql-zrm/plugins/lvm-snapshot.pl";
			if( $verbose ){
				&printLog( "Using ".$inputs{"snapshot-plugin"}." as the default plugin since snapshot-plugin has not been specified\n" );
			}
		}else{
			if( $inputs{"backup-type"} ne "regular" ){
	    			&printLog( "No snapshot-plugin specified. The quick backup-type is supported only for snapshot backups. Setting backup-type to 'regular'\n" );
				$inputs{"backup-type"} = "regular";
			}
			return;
		}
	}
	if( $inputs{"snapshot-plugin"} =~ /^\s*$/ ){
		delete $inputs{"snapshot-plugin"};
		$inputs{"backup-type"} = "regular";
		return;
	}

	if( ! -f $inputs{"snapshot-plugin"} ){
		&printAndDie( "Unable to find snapshot plugin ". $inputs{"snapshot-plugin"}."\n" );
	}
	if( defined $inputs{"lvm-snapshot"} ){
		&printWarning( "The lvm-snapshot option is deprecated. Use snapshot-size instead\n" );
		if( ! defined $inputs{"snapshot-size" } ){
			$inputs{"snapshot-size"} = $inputs{"lvm-snapshot"};
		}
	}

	if( ! defined $inputs{"snapshot-size" } ){
		$inputs{"snapshot-size" } = 10;
	}

}

# check for the logical backup
sub checkForLogicalParallelBackup()
{
    if( defined $inputs{"backup-method-name"} && $inputs{"backup-method-name"} eq "mydumper"){
        $isMyDumper = 1;
    }
    if(defined $inputs{"logical-parallel"} && $inputs{"logical-parallel"} eq "1"){
        $isMyDumper = 1;
    }
    if($isMyDumper){
        my $mydumper = "/usr/local/bin/mydumper";
        if(! -f $mydumper){
            &printAndDie("mydumper not found - $mydumper. Logical Parallel backup requires the mydumper tool\n");
        }
    }
}

sub checkForIHB()
{
	if( ! defined $inputs{"ihb-plugin"} ){
		return;
	}
	if( $inputs{"ihb-plugin"} =~ /^\s*$/ ){
		delete $inputs{"ihb-plugin"};
		return;
	}
	if( ! -f $inputs{"ihb-plugin"} ){
		&printAndDie( "Unable to find innohotbackup plugin ". $inputs{"ihb-plugin"}."\n" );
	}

}

#verifys if all of the inputs are ok.
sub verifyInputs()
{
	if( $onWindows ) {
		if( $inputs{"encrypt"} ) {
		#	&printLog( "encrypt parameter is not supported on Windows\n" );
		#	delete $inputs{"encrypt"};
		}
		$inputs{"synchronous-checksum"} = -1;
		if( !defined $inputs{"copy-plugin"} ){
			$inputs{"copy-plugin"} = catfile( $ZRM_HOME, "usr\\share\\mysql-zrm\\plugins\\windows-copy.pl" );
			if( $verbose ){
				&printLog( "Using ".$inputs{"copy-plugin"}." as the default plugin since copy-plugin has not been specified\n" );
			}
		}
	}

	if( $action ne "restore" ){
		&checkBackupWhat();
	}

	if( $inputs{"backup-level"} > 1 || $inputs{"backup-level"} < 0 ){
		&printAndDie( "Invalid backup-level specified\n" );
	}
	if( $inputs{"backup-mode"} ne "raw" &&
	    $inputs{"backup-mode"} ne "logical" ){
		&printAndDie( "invalid backup-mode specified\n" );
	}

        if( $inputs{"retention-policy"} ){
                &getRetentionTimeInSecs($inputs{"retention-policy"});
        }

        if( $inputs{"backup-name"} &&
                !&validateData( $inputs{"backup-name"} ) ){
                        &printAndDie( "backup-name not valid ".$inputs{"backup-name"}."\n" );
			delete $inputs{"backup-name"};
        }

	&checkForRemoteHost();
	&checkForSnapshot();
	&checkForIHB();

	if( $inputs{"copy-plugin"} && ! -f $inputs{"copy-plugin"} ){
		&printAndDie( "Unable to find copy plugin ". $inputs{"copy-plugin"}."\n" );
	}
	if( $inputs{"verbose"} ) {
		$verbose = 1;
	}

	# ensure mailto is not evil
	# reject mailto with the following * ( ) < > [ ] , ; : ! $ \ / "
	if ( $inputs{"mailto"} ) {
		if( $inputs{"mailto"} =~ /^([^\*\(\)<>\[\]\,\;\:\!\$\\\/\"]+)$/ ) {
			if( $verbose ){
				&printLog( "Mail address: ".$inputs{"mailto"}." is ok\n" );
			}
		} else {
			my $a = $inputs{"mailto"};
			delete $inputs{"mailto"};
			&printAndDie("Invalid data in mailto: ".$a."\n");
		}
	}
	if( !defined $inputs{"mail-policy"} ){
		$inputs{"mail-policy"} = "always";
	}
	if( $inputs{"mail-policy"} ne "always" && $inputs{"mail-policy"} ne "never" && $inputs{"mail-policy"} ne "only-on-error" ){
		&printAndDie( "mail-policy can only take values never or always or only-on-error\n" );
	}
	if( $inputs{"mail-policy"} eq "never" ){
		if( $verbose == 1 ){
			&printLog( "mail will not be sent since mail-policy is set to never\n" );
		}
		delete $inputs{"mailto"};
	}

	if( $inputs{"mysql-binpath"} ){
		if( ! -d $inputs{"mysql-binpath"} ){
			&printAndDie( "mysql-binpath not found ".$inputs{"mysql-binpath"}."\n" );
		}
		$MYSQL_BIN_PATH=$inputs{"mysql-binpath"};
		if( $onWindows ){
			$MYSQL_BIN_PATH =~ s'\\+$'';
		}
		$inputs{"mysql-binpath"} = $MYSQL_BIN_PATH;
	}
    if( $action ne "restore" ){
        &checkForLogicalParallelBackup();
    }
	if( defined $inputs{"compress-mysqldump-onthefly"} && $inputs{"compress-mysqldump-onthefly"} eq 1 ){
		if( !defined $inputs{"compress"} || $inputs{"compress"} == 0 ){
			$inputs{"compress"} = 1;
		}
	}
	&checkForCompressEncryptPlugin( "compress" );
	&checkForCompressEncryptPlugin( "encrypt" );
	if( defined $inputs{"encrypt"} ){
		if( $inputs{"encrypt"} eq "" && ! $onWindows ){
			&printAndDie( "Please specify the --encrypt-plugin\n" );
		}else{
			if( ! $inputs{"decrypt-option"} ){
				$inputs{"decrypt-option"} = "-d";
			}
		}
	}

        &checkForPrePostPlugin( "pre-backup" );
        &checkForPrePostPlugin( "post-backup" );
        &checkForPrePostPlugin( "pre-restore" );
        &checkForPrePostPlugin( "post-restore" );

	&checkDirs();

	if( $action ne "restore" and 
	    defined $inputs{"config-file-list"} and 
	    ! -e $inputs{"config-file-list"})	{
		&printError("File having list of configuration files \"$inputs{\"config-file-list\"}\" Not Found\n");
	}

	if( defined $inputs{"row-event-details"} && $inputs{"row-event-details"} ne "never" && $inputs{"row-event-details"} ne "auto" && $inputs{"row-event-details"} ne "always" ){
		&printAndDie( "row-event-details can only take the following values: auto, never or always\n" );
	}
}

#$_[0] directory to check if writable
sub checkIfWritable()
{
	if( ! -w $_[0] || ! -r $_[0] || ! -x $_[0] ){
		my $msg = "$_[0] does not have sufficient permissions.\n";
		if( defined $_[1] ){
			$msg = $_[1].$msg;
		}
                &printAndDie( $msg );
	}
}

sub checkDirs()
{
        my $checkDir = 1;
        # Check if TMPDIR is writable
        #&checkIfWritable( $TMPDIR );
        #check for root of backup dir
	my $dest = "";
        if( !$inputs{"destination"} ) {
                my $x = $VARLIB;
                $dest=catfile( $x, "mysql-zrm" );

        } else {
                if( ! -d $inputs{"destination"} ) {
                        &printAndDie( "Cannot find destination ".$inputs{"destination"}."\n" );
                        $checkDir = 0;
                }
		$dest = $inputs{"destination"};
        }

        #verify that backup-name is unique if present
        if( $checkDir == 1 ){
                my $dir=catfile($dest, $backupset );
                if( -e $dir ){
                        $dest = $dir;
                }
                if( $inputs{"backup-name"} ){
                        $dir = catfile($dir, $inputs{"backup-name"});
                        if( -e $dir ){
                                &printError( "Directory ".$dir." exists\n" );
                                &printError( "Directory with backup-name ".$inputs{"backup-name"}." already exists inside backup-set ".$backupset."\n");
                                &printAndDie( "Please provide a unique backup-name.\n" );
                        }
                }
                #verify that backup dir is writable
                &checkIfWritable( $dest, "Destination directory " );
        }

        &checkIfWritable( $backupset_dir );
        my $f = catfile( $backupset_dir, "last_backup" );
        if( -f $f ){
                if( open( TMPH, ">>$f" ) ){
                        close( TMPH );
                }else{
                        &printError( "No write permissions on $f\n" );
                }
        }
}

#Initializes all of the command line stuff, verifys them and get reads for execution
# @_ defines the command line parameters that are valid for the applications
# This is passed to GetOptions directly.
sub initMySQL()
{
	&initCommon(@_);
	&verifyInputs();
	&createConfigFile();
	&getMySQLVariables();
}

1;

__END__
