package SI::lvm;

use if $ENV{DEBUG} ~~ /lvm|all/ => qw(Smart::Comments);

use strict;
use warnings;
use IO::File;
use Cwd qw(abs_path);
use File::Basename;
use feature "switch";

use SI::tools;

my @volumegroups = ();

sub _vgs(\%) {
    return @volumegroups if @volumegroups;

    my $devs = shift;

    # find the physical volumes we've already recognised as „non-removable“
    my @known = keys %{ $devs->{volume} }, keys %{ $devs->{disk} };

    my @pvs =
      grep { $_ ~~ @known } map { s/\s*//; (split /:/)[0] } `pvdisplay -c`;
    @volumegroups = map { (split /:/)[1] } `pvdisplay -c @pvs 2>/dev/null`;
    run("vgchange -ay @volumegroups 2>&1 >/dev/null");

    # we wait for the /dev/mapper devices to appear
    run("udevadm settle");
    return @volumegroups;
}

sub volumes(\%) {
    my ($devs) = @_;

    # we can't just use `pvs', since this would return *all*
    # physical devices known to lvm, not just the non-removable

    my @vgs = _vgs(%$devs);
    my @lvs =
      map { abs_path((dirname $_) . "/" . readlink) }
      map { s/^\s*//; (split /:/)[0] }
      grep { (split /:/)[1] ~~ @vgs } `lvdisplay -c`;
    foreach (@lvs) {
        $devs->{volume}{$_} = { origin => "lvm" };
    }

    push @{ $devs->{volumes} }, @lvs;
}

sub vgcfgbackup($\%) {
    my ($file, $devs) = @_;

    # we save it vg by vg to have the restore more easy
    my @vgs = _vgs(%$devs);
    foreach (map { s/^\s*(.*)/$1/; $_ = (split /:/)[0] }
        `vgs --noheadings --separator : @vgs`)
    {
        verbose("saving vg $_\n");
        my $file = sprintf $file, $_;
        run("vgcfgbackup -f '$file' '$_' >/dev/null");
    }

    # for testing let's save it all
    verbose("saving vg *\n");
    $file = sprintf $file, "*";
    run("vgcfgbackup -f '$file' >/dev/null");
}

sub pvcreate(\%) {
    my $devs = shift;
    foreach my $volume ( keys %{$devs->{volume}} ) {
	my $v = $devs->{volume}{$volume};
	next if $v->{origin} ne "ptable"
	    or not defined $v->{type}
	    or $v->{type} !~ /^lvm/i;
	run("pvcreate -y -ff -u $v->{uuid} $volume");
    }
}

sub vgcfgrestore($\%) {
    my @cfgs = glob($_[0]);
    my $devs = shift;

    foreach (@cfgs) {
	my $vg = (split /\./, basename($_))[1];
	next if $vg eq "*";
	run("vgcfgrestore -f $_ $vg");
	run("vgchange -ay $vg");
    }
    run("udevadm settle");
}

sub mkfs(\%) {
    my $devs = shift;
    foreach my $volume ( keys %{$devs->{volume}} ) {
	my $v = $devs->{volume}{$volume};
	next if $v->{origin} ne "lvm"
	    or not defined $v->{type};
	
	my $label = defined $v->{label} ? "-L '$v->{label}'" : "";
	my $uuid = defined $v->{uuid} ? "-U '$v->{uuid}'" : "";

	given($v->{type}) {
	    when(/ext/) {
		run("mkfs -t $v->{type} $label $uuid $volume");
	    };
	    when(/swap/) {
		run("mkswap $label $uuid $volume");
	    };
	}
    }
}

1;

# vim:sts=4 sw=4 aw ai si:
