#!/usr/bin/perl

use lib qw(/usr/lib/libDrakX);

# i18n: IMPORTANT: to get correct namespace (draklive-resize instead of libDrakX)
BEGIN { unshift @::textdomains, 'draklive-resize' }

use standalone;
use common;
use interactive;
use run_program;
use fs;
use fs::format;
use fs::mount;
use IPC::Open3;
use any;

my $conf_file = '/etc/sysconfig/draklive-resize';
my %conf = getVarsFromSh($conf_file);

my $is_unionfs1 = run_program::get_stdout("/sbin/modinfo", "-F", "description", "unionfs") =~ /\b1\.4\b/;

my $do_not_modify_union = 0;
my $may_miss_written_files = !$is_unionfs1;
my $use_unionctl = $is_unionfs1;

my $part = {
	    real_device => $conf{LOOPBACK},
	    fs_type => $conf{TYPE},
	    mntpoint => $conf{MOUNT},
	    options => "loop",
};

sub disable_draklive_resize {
    my ($o_prefix) = @_;
    addVarsInSh($o_prefix . $conf_file, { DRAKLIVE_RESIZE => 'no' });
}

sub safe_resize {
    my ($in, $initial_size, $new_size) = @_;
    eval { resize($in, $initial_size, $new_size) };
    my $error = $@;
    if ($error) {
        $in->ask_warn(N("Error"), N("Unable to resize system space: %s", formatError($error)));
        exec("/sbin/reboot");
    }
}

sub resize {
    my ($in, $initial_size, $new_size) = @_;

    if (defined $new_size) {
	my ($_wait, $progress) = $in->wait_message_with_progress_bar(N("Please wait"));
	$progress->(N("Resizing live system"));
	my $count = $new_size - $initial_size;
	#- use dd instead of truncate() (not to trigger OOM when truncating big files on vfat partitions)
	#- IPC::Open3 allows to catch both stderr and stdout
        my $pid = open3(my $dd_stdin, my $dd_stdout, undef, 'dd', 'if=/dev/zero', 'of=' . $conf{LOOPBACK}, 'bs=1M', ($count > 0 ? ('seek=' . $initial_size, 'count=' . $count) : ('seek=' . $new_size, 'count=0')))
	    or die "dd failed";
	sleep 2; #- do not send initial USR1 signal too early, or dd may die prematurely
	kill 'USR1', $pid;
	my $total_mb = int(($count > 0 ? $count : $new_size) * 1024 * 1024 / 1000 / 1000);
	local $_;
	while (<$dd_stdout>) {
            if (/^(\d+) bytes \((\d+) MB\) copied/) {
                $progress->(undef, $2, $total_mb);
                sleep 1;
                kill 'USR1', $pid;
            }
	}
	close $dd_stdout;
	close $dd_stdin;
    }

    my $_wait = $in->wait_message(N("Please wait"), N("Preparing live system..."));
    {
      local $part->{mntpoint} = "/home";
      fs::format::part_raw($part, undef);
    }
    fs::mount::part($part);

    if (!$do_not_modify_union && !$may_miss_written_files) {
        my @cmd = $use_unionctl ?
          ("unionctl", $conf{UNION}, "--mode", "ro", $conf{OLD_MOUNT}) :
          ("mount", "-n", "none", $conf{UNION}, "-o", "remount,mode=$conf{OLD_MOUNT}=ro");
        run_program::run(@cmd)
            or die "unionctl ro failed";
    }

    if (my @old_files = glob_($conf{OLD_MOUNT} . "/*")) {
	run_program::run("cp", "-a", @old_files, $conf{MOUNT})
	    or die "cp failed";
    }

    disable_draklive_resize($conf{MOUNT});

    if (!$do_not_modify_union) {
        my @cmd = $use_unionctl ?
          ("unionctl", $conf{UNION}, "--add", "--mode", "rw", $conf{MOUNT}) :
          ("mount", "none", $conf{UNION}, "-o", "remount,add=$conf{MOUNT}=rw");
        run_program::run(@cmd)
            or die "unionctl rw failed";
    }

    run_program::run("sync");

    if ($do_not_modify_union) {
        fs::mount::umount_part($part);
        die N("You have to reboot.");
    }
}

if (any { $_->{mntpoint} eq $conf{OLD_MOUNT} && $_->{fs_type} eq $conf{TYPE} } fs::read_fstab('', '/proc/mounts')) {
    print STDERR "live system writable partition is already mounted, exiting\n";
    disable_draklive_resize();
    exit 0;
}

my $resize = 0;
my $loopback_size = int((stat($conf{LOOPBACK}))[7] / 1024 / 1024);
my $new_size = $loopback_size;
my ($loopback_du) = split(' ', run_program::get_stdout("du", "-k", $conf{LOOPBACK}));
my (undef, $available_size) = MDK::Common::System::df(dirname($conf{LOOPBACK}));
$available_size = int(($available_size + $loopback_du) / 1024);

my $min_size = removeXiBSuffix($conf{MIN_SIZE}) / 1024 / 1024;

my $force_resize;
if ($loopback_size < $min_size) {
    $force_resize = 1;
    $resize = 1;
}

my $icon = 'MandrivaOne-resize-icon.png';
$ugtk2::wm_icon = $icon;

my $in = 'interactive'->vnew('su');
any::set_wm_hints_if_needed($in);

$in->ask_from_({
    cancel => '',
    title => N("Live system resizing wizard"),
    messages => [ N("This live media uses %s MB to save system modifications and home directories.", $loopback_size) . N("You can resize this system space."), "", N("The remaining space will be used to share documents with other operating systems."), "" ],
    banner_title => N("Live system resizing wizard"),

    icon => $icon,
    	       },
	       [
		{
		    text => N("Resize live system (it will take some minutes)"),
		    type => "bool", val => \$resize,
		    disabled => sub { $force_resize },
		},
		{
		    label => N("System and home space (in MB)"),
		    type => "range",
		    val => \$new_size,
		    min => $min_size,
		    max => $available_size,
		    disabled => sub { !$resize },
		},
	       ]);

safe_resize($in, $loopback_size, $resize ? $new_size : undef);

$in->exit;
