#!/usr/bin/perl
################################################################################ mysql/mariadb backup (mwx'2021)
use Getopt::Std;getopts('bza');
use DBI;
use Term::ReadKey;

$VERSION='4.0.0';

$HOST             = 'localhost';                                                                      # settings
$USER             = 'mybackup';
$PASSWD           = 'iexae3aitathoo4k';
$PATH             = '/db/backup/mysql';
$KEEPDAILYBACKUPS = 21;

$TAR              = "/bin/tar";
$RM               = "/bin/rm";
$MYSQLDUMP        = "/usr/bin/mysqldump";
$GZIP             = "/bin/gzip";


if (!$opt_a && !$opt_b && !$opt_z) {                                                                # show usage
print <<"ENDOFHELP";
mybackup, MySQL/MariaDB backup, mwx'2021, v$VERSION
usage: mybackup -a  add backup user to db (root password required)
       mybackup -b  run database backup
       mybackup -z  run database backup and compress output
ENDOFHELP
exit(0);
}

if ($opt_a) {                                                                            # add backup user to db
 	use Term::ReadPassword;
  $rootdbpw = read_password('Enter password: ');
  $dbh=DBI->connect("DBI:mysql:mysql:localhost:","root",$rootdbpw,{RaiseError=>1,PrintError=>1});

  $dbh->do("CREATE USER 'mybackup' IDENTIFIED BY '$PASSWD'");
  $dbh->do("GRANT SELECT, SHOW VIEW, LOCK TABLES, RELOAD,REPLICATION CLIENT ON *.* TO 'mybackup'");

# 
# 
# 
# CREATE USER 'mybackup' IDENTIFIED BY 'Yooch0esh9Ah';
# 
# 
# 	$sth=$dbh->prepare("SHOW COLUMNS FROM user");$sth->execute;                       # find authentication fields
# 	$HASPW=0;$HASAS=0;
# 	while ($dat = $sth->fetchrow_hashref) {
#   	$HASPW=1 if ($$dat{Field} eq 'Password');
#   	$HASAS=1 if ($$dat{Field} eq 'authentication_string');
# 	}
# 
#   $sql="INSERT INTO user SET User='$USER',Host='localhost',";
#   $sql.="Password=password('$PASSWD')," if ($HASPW); 
#   $sql.="authentication_string=password('$PASSWD')," if ($HASAS); 
#   $sql.="ssl_cipher='',x509_issuer='',x509_subject='',".
#         "Select_priv='Y',Reload_priv='Y',Lock_tables_priv='Y',Show_view_priv='Y',Process_priv='Y'";
#         
#   $dbh->do($sql);
  $dbh->do("flush privileges");
  
  if (&yesno('Write /root/.my.cnf file',1)) {
    system("rm -f /root/.my.cnf");
    open(OUT,"> /root/.my.cnf");
    print OUT "[client]\nuser=root\npassword=$rootdbpw\n[mysqldump]\nuser=mybackup\npassword=$PASSWD\n";
    close(OUT);
    system("chmod 600 /root/.my.cnf");
  }
  
  &setupcron();
  
  exit;
}

&cleanup();

@DBS=&autogetdbs();

my(@z)=localtime(time());$z[4]+=1;$z[6]+=1;$z[5]-=100;
$z=sprintf("%02d%02d%02d%02d%02d%02d",$z[3],$z[4],$z[5],$z[2],$z[1],$z[0]);


if (!-d "$PATH/$z") {                                                                          # make target dir
	mkdir("$PATH/$z",448);
}


for $db (@DBS) {                                                                               # dump databaeses
	if ($db ne 'information_schema' && $db ne 'performance_schema' && $db ne 'sys') {
		my($fdb)=$db;$fdb=~s/\s/\./g;
		if (!$IGNOREDB{$db}) {
			if ($DBPARAM{$db}) {;$db=$DBPARAM{$db};}
			&cmd("$MYSQLDUMP -h $HOST -u $USER -f -F -R --skip-extended-insert $db >$PATH/$z/$fdb.mysql");
		}
	}
}


$cmd="$MYSQLDUMP -h $HOST -u $USER -c -f -F -R --skip-extended-insert -A -v >$PATH/$z.mysql";
&cmd($cmd);


&cmd("$GZIP $PATH/$z.mysql");
chdir($PATH);
if (-d "$PATH/$z" && $opt_z) {
	&cmd("$TAR czvf $z.tar.gz $z");
	&cmd("$RM -rf $PATH/$z");
}

######################################################################################################## SUPPORT

sub cleanup() {
  use Date::Parse;

  opendir(DIR,"$PATH");
  while($file=readdir(DIR)) {
        
    if (-f "$PATH/$file" && $file=~/(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/) {
      $m=$1;
            
      $a=$3+2000;
      $time = str2time("$a/$2/$1 $4:$5:$6");
      
      my(@z)=localtime($time);$z[4]+=1;$z[5]-=100;$z[6]+=1;
      $z=sprintf("%02d\.%02d\.%02d %02d\:%02d\:%02d",$z[3],$z[4],$z[5],$z[2],$z[1],$z[0]);

      $t=(time()-$time)/86400;

      if ($m!=1 && $t>$KEEPDAILYBACKUPS) {
        &cmd("/bin/rm -f $PATH/$file") if (-f "$PATH/$file");
      }
    }
  }       
}

sub setupcron() {
  open(CRON,"crontab -l |");
  while(<CRON>) {
    chomp();
    push(@CRON,$_) if (!/\/db\/bin\/mybackup/);
  }

  push(@CRON,"0 12 * * * /db/bin/mybackup -z > /dev/null 2>&1");

  open(OUT,"> /tmp/cron.$$");
  for (@CRON) {
    print OUT "$_\n";
  }
  close(OUT);
  system("/usr/bin/crontab /tmp/cron.$$");
  system("rm -f /tmp/cron.$$");
}

sub cmd() {
  my($cmd)=@_;    
  print "$cmd\n";
  system($cmd);
}

sub autogetdbs() {
	my(@dbs);
	$dbh=DBI->connect("DBI:mysql::$HOST:",$USER,$PASSWD,{RaiseError=>1,PrintError=>1});

	$sth=$dbh->prepare("SHOW DATABASES");$sth->execute ;
	while ($dat = $sth->fetchrow_hashref) {
		push(@dbs,$$dat{Database});
	}
	return (@dbs);
}

sub yesno {
  my($prom,$def)=@_;
  my($ans);
  if ($def) {;$ans=&getkey("$prom Y/n ? ");}
  else {;$ans=&getkey("$prom y/N ? ");}
  if ($ans=~/^\s*$/) {
    if ($def) {;return(1);}
    else {;return(0);}
  }
  if ($ans=~/^\s*y\s*$/i || $ans=~/^\s*yes\s*$/i) {
    return 1;
  }
  return 0;
}

sub getkey {
  $|=1;
  print "$_[0]";
  system "stty", '-icanon', '-echo', 'eol', "\001";
  $key = getc(STDIN);$key=~s/[\r\n\t]//g;
  system "stty", 'icanon', 'echo', 'eol', "^@";
  print "$key\n";
  return $key;
}

############################################################################################################ END
