package SI::ptable;

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

use strict;
use warnings;
use File::Find;
use File::Basename;
use IO::File;
use feature "switch";

use SI::tools;
$ENV{LC_ALL} = "C";

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

    # find the partition tables of all
    # non-removable block devices (this may include
    # LVs (used as disk itself) too)
    foreach (glob("/sys/block/*")) {
        my $name = basename($_);
        my $dev  = "/dev/$name";

        next if !-e "$_/device";
        next
          if (grep { /ATTR{removable}/ }
            `udevadm info --attribute-walk --name $name`)[0] !~ /==.0./;
        next if (stat $dev)[0] == (stat $0)[0];

        # exclude the device (stick) we're part of - this HACK is
        # only useful on KVM - the usb stick doesn't appear as a removeable
        # device
        next
          if (stat $0)[0] ~~ [
            map   { (stat)[6] }
              map { "/dev/" . basename(dirname $_) } glob("$_/*/partition")
          ];

        verbose("\n");
        verbose("device $dev\n");

        die "ERR: $dev does not exist. (should not happen): $!"
          if !-b $dev;

        # now the physical disk -- let's ask for the partition table

        my @sfdisk = `sfdisk -d /dev/$name 2>/dev/null`;

        my $of = sprintf $file, $name;
        my $oh = new IO::File ">$of" or die "Can't open >$of: $!\n";
        print $oh @sfdisk;

        $devs->{disk}{"/dev/$name"} = { pt => \@sfdisk };

        # and let's prepare the volume entries
        foreach (@sfdisk) {
            /^(\S+)\s*:.*Id=\s*([[:xdigit:]]+)/ or next;
            $devs->{volume}{$1} = {
                origin      => "ptable",
                ptable_type => $2,
            };
            push @{ $devs->{volumes} }, $1;
        }
    }

    return;
}

sub restore(\%) {
    my $devs = shift;

    foreach my $disk (keys %{$devs->{disk}}) {
	verbose("restoring partition table of $disk\n");
	die "I won't use the disk ($disk) I'm running on!" 
	    if (stat $0)[0] ~~ [ map { (stat)[6] } map { "/dev/" . basename dirname $_ } glob ("/sys/block/" . basename($disk) . "/*/partition")];

	    my $sfdisk = new IO::File "|sfdisk --force $disk >/dev/null"
		or die "Can't open |sfdisk $disk: $!\n";
	    print {$sfdisk} @{$devs->{disk}{$disk}{pt}};
	    $sfdisk->close or die $? >> 8;
	    run("partprobe $disk");
	    run("udevadm settle");
    }
}

sub mkfs(\%) {
    my $devs = shift;
    foreach my $volume ( keys %{$devs->{volume}} ) {
	my $v = $devs->{volume}{$volume};
	next if $v->{origin} ne "ptable";
	warn $volume, "\n";
	next if not defined $v->{type};
	given ($v->{type}) {
	    when(/ext\d/) {
		my $label = defined $v->{label} ? $v->{label} : "";
		my $uuid = defined $v->{uuid} ? $v->{uuid} : "";
		run("mkfs -t $v->{type} -L '$label' -U '$uuid' $volume");
	    };
	    when("swap") {
		my $label = defined $v->{label} ? $v->{label} : "";
		my $uuid = defined $v->{uuid} ? $v->{uuid} : "";
		run("mkswap -L '$label' -U '$uuid' $volume");
	    };
	};

    }

}
1;

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