#!/usr/bin/perl

package lxc_pve_prestart_hook;

use strict;
use warnings;

exit 0 if $ENV{LXC_NAME} && $ENV{LXC_NAME} !~ /^\d+$/;

use POSIX;
use File::Path;
use Fcntl ':mode';

use PVE::SafeSyslog;
use PVE::Tools;
use PVE::Cluster;
use PVE::INotify;
use PVE::RPCEnvironment;
use PVE::JSONSchema qw(get_standard_option);
use PVE::CLIHandler;
use PVE::Storage;
use PVE::LXC;
use PVE::LXC::Setup;
use Data::Dumper;

use base qw(PVE::CLIHandler);

__PACKAGE__->register_method ({
    name => 'lxc-pve-prestart-hook',
    path => 'lxc-pve-prestart-hook',
    method => 'GET',
    description => "Create a new container root directory.",
    parameters => {
    	additionalProperties => 0,
	properties => {
	    name => {
		description => "The container name. This hook is only active for containers using numeric IDs, where configuration is stored on /etc/pve/lxc/<name>.conf (else it is just a NOP).",
		type => 'string',
		pattern => '\S+',
		maxLength => 64,
	    },
	    path => {
		description => "The path to the container configuration directory (LXC internal argument - do not pass manually!).",
		type => 'string',
	    },
	    rootfs => {
		description => "The path to the container's rootfs (LXC internal argument - do not pass manually!)",
		type => 'string',
	    },
	},
    },
    returns => { type => 'null' },

    code => sub {
	my ($param) = @_;

	return undef if $param->{name} !~ m/^\d+$/;

	my $vmid = $param->{name};

	PVE::Cluster::check_cfs_quorum(); # only start if we have quorum

	return undef if ! -f PVE::LXC::config_file($vmid);

	my $conf = PVE::LXC::load_config($vmid);

	my $storage_cfg = PVE::Storage::config();

	my $vollist = PVE::LXC::get_vm_volumes($conf);
	my $loopdevlist = PVE::LXC::get_vm_volumes($conf, 'rootfs');

	PVE::Storage::activate_volumes($storage_cfg, $vollist);

	my $rootdir = $param->{rootfs};

	my $setup_mountpoint = sub {
	    my ($ms, $mountpoint) = @_;

	    #return if $ms eq 'rootfs';
	    PVE::LXC::mountpoint_mount($mountpoint, $rootdir, $storage_cfg);
	};

	my $setup_cgroup_device = sub {
	    my ($ms, $mountpoint) = @_;

	    my $volid = $mountpoint->{volume};
	    return if !$volid || $volid !~ m|^/dev/.+|;

	    my $path = PVE::LXC::mountpoint_mount_path($mountpoint, $storage_cfg);

	    my (undef, undef, $mode, undef, undef, undef, $rdev) = stat($path);
	    if ($mode && S_ISBLK($mode) && $rdev) {
		my $major = int($rdev / 0x100);
		my $minor = $rdev % 0x100;
		if ($major != 7) { # must not be a loop device
		    PVE::Tools::run_command(['mknod', '-m', '666', "$rootdir$path", 'b', $major, $minor]);
		    PVE::LXC::write_cgroup_value("devices", $vmid, "devices.allow", "b ${major}:${minor} rwm");
		}
	    }
	};

	PVE::LXC::foreach_mountpoint($conf, $setup_mountpoint);

	PVE::LXC::foreach_mountpoint($conf, $setup_cgroup_device);

	my $lxc_setup = PVE::LXC::Setup->new($conf, $rootdir);
	$lxc_setup->pre_start_hook();
	return undef;
    }});


push @ARGV, 'help' if !scalar(@ARGV);

my $param = {};

if ((scalar(@ARGV) == 3) && ($ARGV[1] eq 'lxc') && ($ARGV[2] eq 'pre-start')) {
    $param->{name} = $ENV{'LXC_NAME'};
    die "got wrong name" if $param->{name} ne $ARGV[0];

    $param->{path} = $ENV{'LXC_CONFIG_FILE'};
    $param->{rootfs} = $ENV{'LXC_ROOTFS_PATH'};
    @ARGV = ();
} else {
    @ARGV = ('help');
}

our $cmddef = [ __PACKAGE__, 'lxc-pve-prestart-hook', [], $param];

__PACKAGE__->run_cli_handler();
