#!/usr/bin/perl
###########################################################################
## Copyright (c) 2015 SUSE LLC
## Copyright (c) 2007 Novell Inc.
###########################################################################

#
# exit codes in "smt-db":
#
# 1 : cannot disable echo mode
# 2 : Cannot read the SMT configuration file
# 3 : Invalid Database configuration. Missing value for DB/config
# 4 : Cannot connect to database (wrong mysql root password?)
# 5 : SMT database already exists
# 6 : Passwords do not match. (for smt user)
# 7 : Cannot create Database smt
#
# 20: Could not connect to the database(with smt user - wrong password?)
# 21: Database migration failed

use strict;
use warnings;
use lib ("/srv/www/perl-lib/");

use SMT;
use SMT::Utils;
use Config::IniFiles;

use Locale::gettext ();
use POSIX ();     # Needed for setlocale()
POSIX::setlocale(&POSIX::LC_MESSAGES, "");


sub help
{
    print __("\nSMT database maintenance tool\n");
    print __("Available commands:");
    print "  help :    ".__("show help\n");
    print "  migrate : ".__("initialize or upgrade database\n");
    print "  setup:    ".__("setup the database\n");
    print "  optimize: ".__("optimize the database\n");
    exit 0;
}

sub optimize
{
  my $dbh;
  if ( not $dbh=SMT::Utils::db_connect() )
  {
    print STDERR __("ERROR: Could not connect to the database.\n");
    return 20;
  }

  my @tables = ( "Catalogs",
                 "ClientSubscriptions",
                 "Clients",
                 "Filters",
                 "JobQueue",
                 "MachineData",
                 "Patchstatus",
                 "ProductCatalogs",
                 "Products",
                 "Registration",
                 "RepositoryContentData",
                 "Subscriptions",
                 "Targets"
                 );
  foreach my $table (@tables)
  {
    my $statement = sprintf("OPTIMIZE TABLE %s", $dbh->quote_identifier($table));
    #print "STATMENT: $statement\n";
    my $res = $dbh->selectall_arrayref($statement, { Slice => {}} );
    foreach my $line (@{$res})
    {
      my $status = "     ";
      $status = "ERROR" if($line->{Msg_type} eq "error");
      $status = "WARN " if($line->{Msg_type} eq "warning");
      $status = "INFO " if($line->{Msg_type} eq "info");
      print "$status Table: ".$line->{Table}.": ".$line->{Msg_text}."\n";
    }
  }
}

sub migrate
{
    `smt-schema-upgrade --yes`;
    return 0;
}

sub cpw
{
    my $opt      = shift;

    my $smtpass  = "";
    my $smtpassV = "";
    my $host     = "localhost";

    my $cfg = undef;

    eval
    {
        $cfg = SMT::Utils::getSMTConfig();
    };
    if($@ || !defined $cfg)
    {
        print STDERR sprintf(__("Cannot read the SMT configuration file: %s\n"), $@);
        return 2;
    }

    my $config = $cfg->val('DB', 'config');
    if(!defined $config || $config eq "")
    {
        print STDERR __("Invalid Database configuration. Missing value for DB/config.\n");
        return 3;
    }
    if($config =~ /host=([^;]+)/)
    {
	    $host = $1;
    }
    my $user = $cfg->val('DB', 'user');
    my $oldpw = "";
    print "Old password for $user\@$host user: ";
    if($opt ne "--yast")
    {
        system("stty -echo") == 0 or do {
                   print STDERR "Can not disable echo mode: $!\n";
                return 1;
        };
    }
    chomp($oldpw = <STDIN>);
    system("stty echo") if($opt ne "--yast");
    print "\n";

    my $dbh    = undef;
    eval {
        $dbh    = DBI->connect($config, $user, $oldpw, {RaiseError => 1, AutoCommit => 1});
    };
    if($@)
    {
            print STDERR "Cannot connect to database: $@\n";
            return 4;
    }

    print "New password for $user\@$host user: ";
    if($opt ne "--yast")
    {
        system("stty -echo") == 0 or do {
                   print STDERR "Can not disable echo mode: $!\n";
                return 1;
        };
    }
    chomp($smtpass = <STDIN>);
    system("stty echo") if($opt ne "--yast");
    print "\n";

    print "Repeat new password for $user\@$host user: ";
    if($opt ne "--yast")
    {
        system("stty -echo") == 0 or do {
                print STDERR "Can not disable echo mode: $!\n";
                return 1;
        };
    }
    chomp($smtpassV = <STDIN>);
    system("stty echo") if($opt ne "--yast");
    print "\n";

    if($smtpass ne $smtpassV)
    {
        print STDERR "Passwords do not match.\n";
        return 6;
    }

    $dbh->do("SET PASSWORD FOR '$user'\@$host=PASSWORD('$smtpass');");

    $cfg->setval('DB', 'user', $user);
    $cfg->setval('DB', 'pass', $smtpass);
    $cfg->RewriteConfig();
    my ($login,$pass,$uid,$gid) = getpwnam("wwwrun");
    chown 0, $gid, "/etc/smt.conf";

    return 0;
}

sub setup
{
    my $opt      = shift;
    my $username = "root";
    my $password = "";
    my $smtuser  = "smt";
    my $smtpass  = "";
    my $host     = "localhost";

    system("systemctl enable smt.target");
    system("systemctl enable smt-schema-upgrade.service");
    system("systemctl start mysql.service");

    print "mysql password for user $username: ";
    if($opt ne "--yast")
    {
    	system("stty -echo") == 0 or do
    	{
		   print STDERR "Can not disable echo mode: $!\n";
		   return 1;
    	};
    }
    chomp($password = <STDIN>);
    system("stty echo") if($opt ne "--yast");
    print "\n";

    my $cfg = undef;

    eval
    {
        $cfg = SMT::Utils::getSMTConfig();
    };
    if($@ || !defined $cfg)
    {
        print STDERR sprintf(__("Cannot read the SMT configuration file: %s\n"), $@);
        return 2;
    }

    my $config = $cfg->val('DB', 'config');
    if(!defined $config || $config eq "")
    {
        print STDERR __("Invalid Database configuration. Missing value for DB/config.\n");
        return 3;
    }
    $config =~ s/database=smt/database=/;
    if($config =~ /host=([^;]+)/)
    {
	$host = $1;
    }

    my $dbh    = undef;
    eval {
    	$dbh    = DBI->connect($config, $username, $password, {RaiseError => 1, AutoCommit => 1});
    };
    if($@)
    {
	    print STDERR "Cannot connect to database: $@\n";
	    return 4;
    }

    my $r = $dbh->selectcol_arrayref("show databases");
    my $found = 0;

    foreach (@{$r})
    {
        $found = 1 if($_ eq "smt");
    }

    if($found)
    {
        print STDERR "SMT database already exists.\n";
	return 5;
    }

    print "Enter a new username for the smt database: ";
    chomp($smtuser = <STDIN>);

    print "New password for user $smtuser: ";
    if($opt ne "--yast")
    {
    	system("stty -echo") == 0 or do {
		   print STDERR "Can not disable echo mode: $!\n";
	   	return 1;
    	};
    }
    chomp($smtpass = <STDIN>);
    system("stty echo") if($opt ne "--yast");
    print "\n";

    my $smtpassV = "";

    print "Repeat password for user $smtuser: ";
    if($opt ne "--yast")
    {
    	system("stty -echo") == 0 or do {
		print STDERR "Can not disable echo mode: $!\n";
	   	return 1;
    	};
    }
    chomp($smtpassV = <STDIN>);
    system("stty echo") if($opt ne "--yast");
    print "\n";

    if($smtpass ne $smtpassV)
    {
        print STDERR "Passwords do not match.\n";
	return 6;
    }

    # we use latin1, because with UTF8 we could not create indexes like we
    # want. The limitation of 767 bytes is too small to create an index
    # over the products table for name, version, release and architecture
    # if with UTF8 every character is counted as 3 bytes.
    $r = $dbh->do("create database if not exists smt character set = 'latin1'");
    if($r != 1)
    {
        print STDERR "Cannot create Database smt.\n";
	return 7;
    }

    $r = $dbh->do("grant all on smt.* to '$smtuser'\@$host identified by '$smtpass'");
    $dbh->disconnect;

    $cfg->setval('DB', 'user', $smtuser);
    $cfg->setval('DB', 'pass', $smtpass);
    $cfg->RewriteConfig();
    my ($login,$pass,$uid,$gid) = getpwnam("wwwrun");
    chown 0, $gid, "/etc/smt.conf";

    `smt-sql --select-mode-direct /usr/share/schemas/smt/mysql/latest/100-smt-tables.sql > /var/log/smt/smt-db-setup.log`;
    # reconnect to smt database
    $dbh = SMT::Utils::db_connect();
    unless ($dbh)
    {
        print STDERR "Cannot connect to database: $@\n";
        return 4;
    }
    $dbh->do("insert into migration_schema_version values ('smt', $SMT::SCHEMA_VERSION);");
    $dbh->disconnect;
    return 0;
}


if (defined $ARGV[0] )
{
  my $cmd = shift(@ARGV);
  #print "cmd: $cmd\n";
  if ( $cmd eq "help" )
  {
    help();
  }
  elsif ( $cmd eq "init" || $cmd eq "migrate" )
  {
    migrate();
  }
  elsif ( $cmd eq "optimize" )
  {
    optimize();
  }
  elsif ( $cmd eq "setup" )
  {
    my $opt = "";
    if (defined $ARGV[0] )
    {
      $opt = shift(@ARGV);
    }
    my $ret = setup($opt);
    if($ret != 0)
    {
      exit $ret;
    }
  }
  elsif ( $cmd eq "cpw" )
  {
    my $opt = "";
    if (defined $ARGV[0] )
    {
      $opt = shift(@ARGV);
    }
    my $ret = cpw($opt);
    if($ret != 0)
    {
      exit $ret;
    }
  }
}
else
{
  help();
}

exit 0;

