#!/usr/local/bin/perl
#get-dev-info.pl
# get information on installed drives and how they are used by disksuite


if (! defined($ENV{SUDO_USER}))
{
    print "USAGE: sudo $0\n";
    exit(1);
}

my (%cf,%data,@devices,%used);

if ($#ARGV == -1)
{
    $debug = 0;
}
else
{
    $debug = 1;
}

read_vfstab();
run_format();
run_metadb();
run_metastat();
run_prtvtoc();

foreach $dev (sort keys %data)
{
    $tmp = $dev;
    $tmp =~ s#(\d+)$#2#;
    if ($i != 2)
    {
        delete($data{$tmp});
    }
}
foreach $dev (sort keys %data)
{
    print "$dev\t$data{$dev}\n";
}


################################################################################
sub run_format
################################################################################
{
#
## get disk information from format
#
    if ($debug)
    {
        print "data from format\n";
    }
    $input = "/tmp/format.input";
    open(OUT,">$input");
    print OUT "0\nq\n";
    close(OUT);
    $format = "/tmp/format.output";
    @res = `/usr/sbin/format < $input > $format`;
    
    open(IN,"$format");
    while ($line = <IN>)
    {
        chomp($line);
        if ($line =~ m#^\s+(\d+)\.\s+(.*?)\s+<(.*?)>#)
        {
            if ($debug)
            {
                print "$1 - $2\n";
            }
            push(@devices,$2);
        }
    }
    close(IN);
    if ($debug)
    {
        print "\n";
    }
}


################################################################################
sub run_metadb
################################################################################
{
#
## get meta-device information from metadb
#
    if (-f "/usr/opt/SUNWmd/sbin/metadb")
    {
        $execdir = "/usr/opt/SUNWmd/sbin";
    }
    elsif (-f "/usr/sbin/metadb")
    {
        $execdir = "/usr/sbin";
    }
    if ($debug)
    {
        print "data from metadb\n";
    }

    $cmd = $execdir."/metadb";
    open(METADB,"$cmd |");
    while ($line = <METADB>)
    {
        chomp($line);
        ($flags,$first,$count,$unk,$unk2,$file) = split(m#\t#,$line);
        if ($file =~ m#/#)
        {
             @parts = split(m#/#,$file);
             $devname = pop(@parts);
             $used{$devname} = "metadb";
        }
    }
    close(METADB);
}


################################################################################
sub run_metastat
################################################################################
{
#
## get meta-device information from metastat
#
    if (-f "/usr/opt/SUNWmd/sbin/metastat")
    {
        $execdir = "/usr/opt/SUNWmd/sbin";
    }
    if (-f "/usr/sbin/metastat")
    {
        $execdir = "/usr/sbin";
    }
#    /usr/opt/SUNWmd/sbin/metastat
#    /usr/sbin/metastat
    if ($debug)
    {
        print "data from metastat\n";
    }
    
    $metafile = "/tmp/metastat.output";
    @res = system($execdir."/metastat > $metafile");
    
#    ### TESTING ################################
#    $metafile = "/tmp/metastat.output.website1";
    
    
    $size = (-s $metafile);
    open(IN,"$metafile");
    read(IN,$buf,$size);
    close(IN);
    
    # join the multi-line outup for each meta device
    $buf =~ s#\s+Invoke:#\tInvoke:#g;
    $buf =~ s#\s+State:#\tState:#g;
    $buf =~ s#\s+Size:#\tSize:#g;
    $buf =~ s#\s+Submirror#\tSubmirror#g;
    $buf =~ s#\s+Stripe#\tStripe#g;
    $buf =~ s#\s+Device\s+Start\s+Block\s+Dbase\s+State\s+Hot\s+Spare\s+# #g;
    while ($buf =~ m#\n\t(c\d+t\d+d\d+s\d)#)
    {
        $buf =~ s#\n\t(c\d+t\d+d\d+s\d)# $1#;
    }
    
    @data = split(m#[\n\r]+#,$buf);
    
#    @devs = grep(m#c\d+t\d+d\d+s\d#,$buf);
    
    foreach $line (@data)
    {
        chomp($line);
#                print "$line\n";
    
        $line =~ s#^\s+##;
        @words = split(m#\s+#,$line);
#    print "$#words\t$line\n";
        if (($line =~ m#^d#) && ($words[1] =~ m#Mirror#))
        {
#            print "mirror - $line\n";
            $volume =  $words[0];
            $voltype = $words[1];
            @parts = split(m#\t#,$line);
            foreach $pair (@parts)
            {
                ($name,$val) = split(m#:#,$pair,2);
                if ($name =~ m#Submirror#)
                {
#                    print " Submirror: $val\n"; 
                }
                elsif ($name =~ m#State#)
                {
#                    print " State: $val\n"; 
                }
                elsif ($name =~ m#Size#)
                {
#                    print " Size: $val\n"; 
                }
                elsif ($name =~ m#Stripe#)
                {
#                    print " $name: $val\n"; 
                }
            }
        }
        if (($line =~ m#^d#) && ($words[1] =~ m#Submirror#))
        {
#            print "submirror - $line\n";
            $volume =  $words[0];
            $volume =~ s#:$##;
            $voltype = $words[1];
            $parent =  $words[3];
            @parts = split(m#\t#,$line);
            foreach $pair (@parts)
            {
                if ($pair =~ m#(.*?):(.*?)$#)
                {
                    $name = $1;
                    $val  = $2;
#                    ($name,$val) = split(m#:#,$pair,2);
                    if ($name =~ m#Submirror#)
                    {
#                        print " Submirror: $val\n";
                    }
                    elsif ($name =~ m#State#)
                    {
#                        print " State: $val\n";
                    }
                    elsif ($name =~ m#Size#)
                    {
#                        print " Size: $val\n";
                    }
                    elsif ($name =~ m#Stripe#)
                    {
#                        print " $pair] [$name:] [$val\n"; 
                        if ($val =~ m#\)#)
                        {
                            ($front,$back) = split(m#\)#,$val);
#                            print "[$front] [$back]\n";
                            $val = $back;
                        }
                        $val =~ s#\s+c#XYzzYc#g;
                        @slices = split(m#XYzzY#,$val);
                        foreach $slice (@slices)
                        {
                            ($dev,$start,$dbase,$state,$spare) = split(m#\s+#,$slice);
                            if ($dev ne "")
                            {
                                if (($debug) or ($state =~ m#Maintenance#))
                                {
                                    print " Dev: $dev\t$state\t$spare\tsubmirror $volume of $parent\n";
                                }
                                $string = "submirror $volume of $parent ($used{$parent})\t$state\t$spare";
                                $used{$dev} = $string;
                            }
                        }
    
                    }
                }
                if ($pair =~ m#^c#)
                {
                    ($dev,$start,$dbase,$state,$spare) = split(m#\s+#,$pair);
                    print " dev: $dev] [$start][$dbase]\n";
                }
            }
        }
    }
    if ($debug)
    {
        print "\n";
    }
}

#exit();


################################################################################
sub read_vfstab
################################################################################
{
#
## get mount point info from vfstab
#
    if ($debug)
    {
        print "data from vfstab\n";
    }
    $vfstab = "/etc/vfstab";
    open(IN,"$vfstab");
    read(IN,$buf,$size);
    
    while ($line = <IN>)
    {
        chomp($line);
        if ($line =~ m/^#/)
        {
            #ignore comments
        }
        else
        {
#            if ($line =~ m#/dev/dsk#)
            {
                ($vdevice,$vrawdevice,$vmountpoint,$vfsck,$vpass,$vboot,$vopt) = split(m#\s+#,$line);
                @dparts = split(m#/#,$vdevice);
                $dev = pop(@dparts);
                if ($vfsck =~ m#swap#)
                {
                    $vmountpoint = $vfsck;
                }
                if (($vfsck ne "proc") && ($vfsck ne "nfs"))
                {
                    $used{$dev} = $vmountpoint;
                    if ($debug)
                    {
                        print "$dev -> $vmountpoint\n";
                    }
                }
            }
#            elsif ($line =~ m#/dev/md#)
#            {
#                ($vdevice,$vrawdevice,$vmountpoint,$vfsck,$vpass,$vboot,$vopt) = split(m#\s+#,$line);
#                @dparts = split(m#/#,$vdevice);
#                $dev = pop(@dparts);
#                $used{$dev} = $vmountpoint;
#            }
        }
    }
    close(IN);
    if ($debug)
    {
        print "\n";
    }
}


#
## put it all together
#


################################################################################
sub run_prtvtoc
################################################################################
{
    if ($debug)
    {
        print "data from prtvtoc\n";
    }
    foreach $dev (@devices)
    {
        $file = "/dev/rdsk/".$dev."s2";
        if (-e $file)
        {
            $lc = 0;
            open(IN,"/usr/sbin/prtvtoc $file |");
            @data = <IN>;
            close(IN);

#            while ($line = <IN>)
            foreach $line (@data)
            {
                $lc++;
                chomp($line);
#                print "$line\n";
                if ($line =~ m#^\*#)
                {
                    if ($line =~ m#bytes/sector#)
                    {
                        ($j,$bytes_per_sector,$j) = split(m#\s+#,$line);
                    }
                }
                else
                {
                    ($j,$partition,$tag,$flags,$first,$count,$last,$dir) = split(m#\s+#,$line);
                    $devname = $dev."s".$partition;
                    $size    = $bytes_per_sector * $count;
                    $ksize = $size / 1024;
                    $size = add_commas($size);
                    $ksize = add_commas($ksize);
                    if (($dir eq "") && (defined($used{$devname})))
                    {
                        $dir = $used{$devname};
                    }
#                    print "$devname\t$size\tbytes\t$ksize\tKB\tmounted as\t$dir\n";
#                    print "$devname\t$ksize\tKB\tmounted as\t$dir\n";
                    if ($dir eq "")
                    {
                        $string = sprintf "%12s\tKB",$ksize;
                    }
                    else
                    {
                        $string = sprintf "%12s\tKB\tmounted as\t$dir",$ksize;
                    }
                    $data{$devname} = $string;
#                    if ($ksize < 15000)
#                    {
#                        delete($data{$devname});
#                    }
                }
            }
            close(IN);

#
## if the drive has failed, prtvtoc fails
## build info from the .cf file
#
            if ($lc == 0)
            {
                parse_cf();
                
                @parts = split(m#/#,$file);
                $device = pop(@parts);
                $device =~ s#s2#s#;
                foreach $devname (keys %cf)
                {
                    if ($devname =~ m#$device#)
                    {
                        $data{$devname} = $cf{$devname};
                    }
                }
                print "disk Error: $file\n";
            }
        }
    }
}


################################################################################
sub parse_cf
################################################################################
{
    my ($devname);
    open(CF,"/etc/lvm/md.cf");
    while ($line = <CF>)
    {
        if ($line =~ m#\s+-m\s+#)
        {
            chomp($line);
            ($mir,$j,$rest) = split(m#\s+#,$line,3);
#            print "[$mir][$j][$rest]\n";

        }
        elsif ($line =~ m#(.*?)\s+\d+\s+\d+\s+(.*?)$#)
        {
            $submir = $1;
            $devname = $2;
#            print "[$submir] [$devname]\n";
            if (($dir eq "") && (defined($used{$devname})))
            {
                $dir = $used{$devname};
            }

            $string = sprintf "%12s\t\tmounted as\tsubmirror $submir of $mir ($used{$mir})\t[Maintenance?]",$foo;
            $cf{$devname} = $string;
#            print "$devname => $string\n";
        }
    }
    close(CF);
}


################################################################################
sub add_commas
################################################################################
{
    local($num) = @_;
    $wholenumber = (split(m#\.#,$num))[0];

    while ($wholenumber =~ s#(.*\d)(\d\d\d)#$1,$2#)
    {
#        print "$wholenumber\n";
    }
    return($wholenumber);
}


