package PVE::LXC::Setup::CentOS;

use strict;
use warnings;

use UUID;

use PVE::Tools;
use PVE::Network;
use PVE::LXC;

use PVE::LXC::Setup::Base;

use base qw(PVE::LXC::Setup::Base);

sub new {
    my ($class, $conf, $rootdir) = @_;

    my $release = PVE::Tools::file_read_firstline("$rootdir/etc/redhat-release");
    die "unable to read version info\n" if !defined($release);

    my $version;

    if (($release =~ m/release\s+(\d+\.\d+)(\.\d+)?/) || ($release =~ m/release\s+(\d+)/)) {
	if ($1 >= 5 && $1 < 10) {
	    $version = $1;
	}
    }

    die "unsupported centos release '$release'\n" if !$version;

    my $self = { conf => $conf, rootdir => $rootdir, version => $version };

    $conf->{ostype} = "centos";

    return bless $self, $class;
}

my $tty_conf = <<__EOD__;
# tty - getty
#
# This service maintains a getty on the specified device.
#
# Do not edit this file directly. If you want to change the behaviour,
# please create a file tty.override and put your changes there.

stop on runlevel [S016]

respawn
instance \$TTY
exec /sbin/mingetty --nohangup \$TTY
usage 'tty TTY=/dev/ttyX  - where X is console id'
__EOD__
    
my $start_ttys_conf = <<__EOD__;
#
# This service starts the configured number of gettys.
#
# Do not edit this file directly. If you want to change the behaviour,
# please create a file start-ttys.override and put your changes there.

start on stopped rc RUNLEVEL=[2345]

env ACTIVE_CONSOLES=/dev/tty[1-6]
env X_TTY=/dev/tty1
task
script
        . /etc/sysconfig/init
        for tty in \$(echo \$ACTIVE_CONSOLES) ; do
                [ "\$RUNLEVEL" = "5" -a "\$tty" = "\$X_TTY" ] && continue
                initctl start tty TTY=\$tty
        done
end script
__EOD__

my $power_status_changed_conf = <<__EOD__;
#  power-status-changed - shutdown on SIGPWR
#
start on power-status-changed
    
exec /sbin/shutdown -h now "SIGPWR received"
__EOD__

sub template_fixup {
    my ($self, $conf) = @_;

    if ($self->{version} < 7) {
	# re-create emissing files for tty

	$self->ct_make_path('/etc/init');

	my $filename = "/etc/init/tty.conf";
	if ($self->ct_file_exists($filename)) {
	    my $data = $self->ct_file_get_contents($filename);
	    $data =~ s|^(exec /sbin/mingetty)(?!.*--nohangup) (.*)$|$1 --nohangup $2|gm;
	    $self->ct_file_set_contents($filename, $data);
	} else {
	    $self->ct_file_set_contents($filename, $tty_conf);
	}

	$filename = "/etc/init/start-ttys.conf";
	$self->ct_file_set_contents($filename, $start_ttys_conf)
	    if ! $self->ct_file_exists($filename);

	$filename = "/etc/init/power-status-changed.conf";
	$self->ct_file_set_contents($filename, $power_status_changed_conf)
	    if ! $self->ct_file_exists($filename);

	# do not start udevd
	$filename = "/etc/rc.d/rc.sysinit";
	my $data = $self->ct_file_get_contents($filename);
	$data =~ s!^(/sbin/start_udev.*)$!#$1!gm;
	$self->ct_file_set_contents($filename, $data);
    }

    # temporary fix for systemd-firstboot as else it prompts for this option on a unconnected tty forever,
    # making it seem like the CT hangs
    $self->ct_file_set_contents('/etc/locale.conf', "LANG=C.utf8") if !$self->ct_file_exists('/etc/locale.conf');

    # always call so root can login, if /etc/securetty doesn't exists it's a no-op
    $self->setup_securetty($conf);

    $self->remove_lxc_name_from_etc_hosts();

    $self->setup_systemd_disable_static_units();
}

sub setup_init {
    my ($self, $conf) = @_;

     # edit/etc/securetty

    $self->fixup_old_getty();

    $self->setup_container_getty_service($conf);

    # older versions might not be able to cope with our relative modern preset default
    if ($self->{version} >= 8) {
	$self->setup_systemd_preset(); # this only affects the first-boot (if no /etc/machine-id exists)
    }
}

sub set_hostname {
    my ($self, $conf) = @_;

    # Redhat wants the fqdn in /etc/sysconfig/network's HOSTNAME
    my $hostname = $conf->{hostname} || 'localhost';

    my $hostname_fn = "/etc/hostname";
    my $sysconfig_network = "/etc/sysconfig/network";

    my $oldname;
    if ($self->ct_file_exists($hostname_fn)) {
	$oldname = $self->ct_file_read_firstline($hostname_fn) || 'localhost';
    } elsif ($self->ct_file_exists($sysconfig_network)) {
	my $data = $self->ct_file_get_contents($sysconfig_network);
	if ($data =~ m/^HOSTNAME=\s*(\S+)\s*$/m) {
	    $oldname = $1;
	}
    }

    my ($ipv4, $ipv6) = PVE::LXC::get_primary_ips($conf);
    my $hostip = $ipv4 || $ipv6;

    my ($searchdomains) = $self->lookup_dns_conf($conf);

    $self->update_etc_hosts($hostip, $oldname, $hostname, $searchdomains);

    # Always write /etc/hostname, even if it does not exist yet
    $self->ct_file_set_contents($hostname_fn, "$hostname\n");

    if ($self->ct_file_exists($sysconfig_network)) {
	my $data = $self->ct_file_get_contents($sysconfig_network);
	if ($data !~ s/^HOSTNAME=\h*(\S+)\h*$/HOSTNAME=$hostname/m) {
	    $data .= "HOSTNAME=$hostname\n";
	}
	$self->ct_file_set_contents($sysconfig_network, $data);
    }
}

sub setup_network {
    my ($self, $conf) = @_;

    my ($gw, $gw6);

    $self->ct_make_path('/etc/sysconfig/network-scripts');

    my ($has_ipv4, $has_ipv6);

    foreach my $k (keys %$conf) {
	next if $k !~ m/^net(\d+)$/;
	my $d = PVE::LXC::Config->parse_lxc_network($conf->{$k});
	next if !$d->{name};
	$has_ipv4 = 1 if defined($d->{ip});
	$has_ipv6 = 1 if defined($d->{ip6});

	my $filename = "/etc/sysconfig/network-scripts/ifcfg-$d->{name}";
	my $routefile = "/etc/sysconfig/network-scripts/route-$d->{name}";
	my $route6file = "/etc/sysconfig/network-scripts/route6-$d->{name}";
	my $routes = '';
	my $routes6 = '';

	my $header = "DEVICE=$d->{name}\nONBOOT=yes\nUUID=" . UUID::uuid() ."\n";
	my $data = '';
	my $bootproto = '';

	if ($d->{ip} && $d->{ip} ne 'manual') {
	    if ($d->{ip} eq 'dhcp') {
		$bootproto = 'dhcp';
	    } else {
		$bootproto = 'none';
		my $ipinfo = PVE::LXC::parse_ipv4_cidr($d->{ip});
		$data .= "IPADDR=$ipinfo->{address}\n";
		$data .= "NETMASK=$ipinfo->{netmask}\n";
		if (defined($d->{gw})) {
		    $data .= "GATEWAY=$d->{gw}\n";
		    if (!PVE::Network::is_ip_in_cidr($d->{gw}, $d->{ip}, 4)) {
			$routes .= "$d->{gw} dev $d->{name}\n";
			$routes .= "default via $d->{gw} dev $d->{name}\n";
		    }
		}
	    }
	}

	if ($d->{ip6} && $d->{ip6} ne 'manual') {
	    $bootproto = 'none' if !$bootproto;
	    $data .= "IPV6INIT=yes\n";
	    if ($d->{ip6} eq 'auto') {
		$data .= "IPV6_AUTOCONF=yes\n";
	    } elsif ($d->{ip6} eq 'dhcp') {
		$data .= "DHCPV6C=yes\n";
	    } else {
		$data .= "IPV6ADDR=$d->{ip6}\nIPV6_AUTOCONF=no\n";
		if (defined($d->{gw6})) {
		    if (!PVE::Network::is_ip_in_cidr($d->{gw6}, $d->{ip6}, 6) &&
			!PVE::Network::is_ip_in_cidr($d->{gw6}, 'fe80::/10', 6)
		    ) {
			$routes6 .= "$d->{gw6} dev $d->{name}\n";
			$routes6 .= "default via $d->{gw6} dev $d->{name}\n";
		    } else {
			$data .= "IPV6_DEFAULTGW=$d->{gw6}\n";
		    }
		}
	    }
	}

	my ($searchdomains, $nameserver) = $self->lookup_dns_conf($conf);
	my @nameservers = PVE::Tools::split_list($nameserver);

	for my $i (0 .. $#nameservers) {
	    $data .= "DNS".($i+1)."=$nameservers[$i]\n";
	}
	$data .= "DOMAIN=".join(' ', PVE::Tools::split_list($searchdomains))."\n" if $searchdomains;

	next unless $data || $bootproto;
	$header .= "BOOTPROTO=$bootproto\n";
	$self->ct_file_set_contents($filename, $header . $data);
	$self->ct_modify_file($routefile, $routes, delete => 1, prepend => 1);
	$self->ct_modify_file($route6file, $routes6, delete => 1, prepend => 1);
    }

    my $sysconfig_network = "/etc/sysconfig/network";
    if ($self->ct_file_exists($sysconfig_network)) {
	my $data = $self->ct_file_get_contents($sysconfig_network);
	if ($has_ipv4) {
	    if ($data !~ s/(NETWORKING)=\S+/$1=yes/) {
		$data .= "NETWORKING=yes\n";
	    }
	}
	if ($has_ipv6) {
	    if ($data !~ s/(NETWORKING_IPV6)=\S+/$1=yes/) {
		$data .= "NETWORKING_IPV6=yes\n";
	    }
	}
	$self->ct_file_set_contents($sysconfig_network, $data);
    }
}

1;
