#!/usr/bin/perl

my $dasd_list;
my $dasd_count = 0;

sub max {
	if ($_[0]<$_[1]) {return $_[1]} else {return $_[0]};
}

sub get_dasd_info($)
{
	my ($busid) = @_;
	my $FD;

	open(FD, "lsdasd -a $busid|");
	my @lines=<FD>;
	foreach $line (@lines) {
		if ($line =~ /(0.0.[a-f0-9]*)\s*active\s*([a-z]*)\s*([0-9]+):([0-9]+)\s*([A-Z]*)/) {
			$dasd_list{$busid}->{'NAME'} = $2;
			$dasd_list{$busid}->{'MAJOR'} = $3;
			$dasd_list{$busid}->{'MINOR'} = $4;
			$dasd_list{$busid}->{'TYPE'} = $5;
		}
	}
	close(FD);
	open(FD, "/proc/partitions");
	my @lines=<FD>;
	foreach $line (@lines) {
		if ($line =~ /\s*(\d+)\s*(\d+)\s*(\d+)\s*([a-z]+)$/) {
			# Full dasd
			my $name = $4;
			my $size = $3;
			if ($name eq $dasd_list{$busid}->{'NAME'}) {
				$dasd_list{$busid}->{"SIZE"} = $size;
			}
		}
		if ($line =~ /\s*(\d+)\s*(\d+)\s*(\d+)\s*([a-z]+)(\d+)/) {
			my $part_name = $4;
			my $part_num = $5;
			my $size = $3;
			my $major = $1;
			my $minor = $2;
			if ($part_name eq $dasd_list{$busid}->{'NAME'}) {
				$dasd_list{$busid}->{"PART_SIZE_$part_num"} = $size;
				$dasd_list{$busid}->{"PART_MAJOR_$part_num"} = $major;
				$dasd_list{$busid}->{"PART_MINOR_$part_num"} = $minor;
				$dasd_list{$busid}->{'PART_COUNT'} = max($part_num, $dasd_list{$busid}->{'PART_COUNT'});
			}
		}
	}
	close(FD);
}

sub get_dasd_list()
{
	open(LSDASD, "lsdasd -a|");
	my @lines=<LSDASD>;
	foreach $line (@lines) {
		if ($line =~ /(0.0.[a-f0-9]*)\s*offline/) {
			$dasd_list{$1}->{'BUSID'} = $1;
			$dasd_list{$1}->{'ONLINE'} = 0;
			$dasd_list{$1}->{'TYPE'} = "unknown";
			$dasd_count += 1;
		}
		if ($line =~ /(0.0.[a-f0-9]*)\s*active/) {
			$dasd_list{$1}->{'BUSID'} = $1;
			$dasd_list{$1}->{'ONLINE'} = 1;
			$dasd_count += 1;
		}
	}
	close(LSDASD)
}

sub get_dump_dasd_info()
{
	foreach $dasd (keys %dasd_list) {
		my $busid, $online, $type;
		$busid = $dasd_list{$dasd}->{'BUSID'};
		$online = $dasd_list{$dasd}->{'ONLINE'};

		if ($online == 0) {
			system("chccwdev -e $busid > /dev/null");
		}
		get_dasd_info($busid);
		$type = $dasd_list{$dasd}->{'TYPE'};

		system("rm -f /tmp/dasd_dump_check");
		system("mknod /tmp/dasd_dump_check b $dasd_list{$dasd}->{'MAJOR'} $dasd_list{$dasd}->{'MINOR'}");
		system("zgetdump -d /tmp/dasd_dump_check 2> /dev/null");
		if ($? == 0) {
			$dasd_list{$dasd}->{'DUMPDEV'} = 1;
		} else {
			$dasd_list{$dasd}->{'DUMPDEV'} = 0;
		}
		if ($online == 0) {
			system("chccwdev -d $busid > /dev/null");
		}
	}
}

sub print_dasd_list()
{
	print "======================\n";
	print "Available DASDs:\n";
	print "======================\n";
	foreach $dasd (sort keys %dasd_list) {
		my $busid, $online, $type;
		$busid = $dasd_list{$dasd}->{'BUSID'};
		$size = $dasd_list{$dasd}->{'SIZE'};
		$online = $dasd_list{$dasd}->{'ONLINE'};
		$type = $dasd_list{$dasd}->{'TYPE'};
		print "$busid type=$type size=$size ";
		if ($dasd_list{$dasd}->{'DUMPDEV'}) {
			print "(has dump signature)";
		}
		if (($dumpconf->{'DUMP_TYPE'} eq "ccw") && ($dumpconf->{'DEVICE'} eq $dasd_list{$dasd}->{'BUSID'})) {
			print "(dump on panic configured)";
		}
		print "\n";
		for ($i = 1; $i <= $dasd_list{$dasd}->{'PART_COUNT'}; $i++) {
			$size = $dasd_list{$dasd}->{"PART_SIZE_$i"};
			print " - part $i: $size\n";
		}
	}
}

sub create_dump_partition($)
{
	my ($busid) = @_;
	my $online = $dasd_list{$busid}->{'ONLINE'};

	if ($online == 0) {
		system("chccwdev -e $busid > /dev/null");
	}
	get_dasd_info($busid);
	$major = $dasd_list{$busid}->{'MAJOR'};
	$minor = $dasd_list{$busid}->{'MINOR'};
	system("rm -f /tmp/dasd_dump_$busid");
	system("mknod /tmp/dasd_dump_$busid b $major $minor");
	system("fdasd -a -s /tmp/dasd_dump_$busid");
	system("rm -f /tmp/dasd_dump_$busid");
	if ($online == 0) {
		system("chccwdev -d $busid > /dev/null");
	}
}

sub prepare_dump_dasd($$)
{
	my ($busid, $part) = @_;
	my $online = $dasd_list{$busid}->{'ONLINE'};

	if ($online == 0) {
		system("chccwdev -e $busid > /dev/null");
	}
	get_dasd_info($busid);

	$major = $dasd_list{$busid}->{"PART_MAJOR_$part"};
	$minor = $dasd_list{$busid}->{"PART_MINOR_$part"};
	$part_size = $dasd_list{$busid}->{"PART_SIZE_$part"};

	if ($mem_size > $part_size) {
		print "WARNING: System size ($mem_size) is bigger than dump device ($part_size)\n";
	}
	system("rm -f /tmp/dasd_dump_$busid\_$part");
	system("mknod /tmp/dasd_dump_$busid\_$part b $major $minor");
	system("zipl -n -d /tmp/dasd_dump_$busid\_$part > /dev/null");
	system("rm -f /tmp/dasd_dump_$busid\_$part");
	if ($online == 0) {
		system("chccwdev -d $busid > /dev/null");
	}
}

sub prepare_dump_conf($)
{
	my ($busid) = @_;

	open(FD, ">/tmp/dumpconf");
	print FD "# Automatically created by dump_install_dasd.pl\n";
	print FD "ON_PANIC=dump\n";
	print FD "DUMP_TYPE=ccw\n";
	print FD "DEVICE=$busid\n";
	close(FD);
	system("install -b /tmp/dumpconf /etc/sysconfig/dumpconf");
	system("service dumpconf start > /dev/null");
}

sub get_mem_size()
{
	open(FD, "free -k|");
	my @lines=<FD>;
	$lines[1] =~ /Mem:\s*(\d+)/;
	$mem_size = $1;
}

sub get_dumpconf()
{
	open(FD, "/etc/sysconfig/dumpconf");

	my @lines=<FD>;
	foreach $line (@lines) {
		if ($line =~/^ON_PANIC=(.*)/) {
			$dumpconf->{'ON_PANIC'} = $1;
		}
		if ($line =~/^DUMP_TYPE=(.*)/) {
			$dumpconf->{'DUMP_TYPE'} = $1;
		}
		if ($line =~/^DEVICE=(.*)/) {
			$dumpconf->{'DEVICE'} = $1;
		}
		if ($line =~/^WWPN=(.*)/) {
			$dumpconf->{'WWPN'} = $1;
		}
		if ($line =~/^LUN=(.*)/) {
			$dumpconf->{'LUN'} = $1;
		}
		if ($line =~/^BOOTPROG=(.*)/) {
			$dumpconf->{'BOOTPROG'} = $1;
		}
		if ($line =~/^BR_LBA=(.*)/) {
			$dumpconf->{'BR_LBA'} = $1;
		}
	}
}

get_dumpconf();
get_mem_size();
get_dasd_list();
get_dump_dasd_info();
print_dasd_list();
print "SELECT DUMP DASD: ";
$dump_dasd_busid = <STDIN>;
$dump_dasd_busid =~ s/\n//g;
print "WARNING: All information on DASD will be lost. Continue (y/n)?";
$answer = <STDIN>;
$answer =~ s/\n//g;
if ($answer eq "y") {
	create_dump_partition($dump_dasd_busid);
	prepare_dump_dasd($dump_dasd_busid, 1);
	prepare_dump_conf($dump_dasd_busid);
	print "Dump Configuration complete\n";
} else {
	print "Operation canceled by user\n";
}
