#!/usr/bin/perl -w
# vim: ts=4 sw=4 expandtab
# sds.pl :
#   Solstice Disk Suite (Solaris Volume Manager) toolbox
#       Copyright Jérôme Fenal, LogicaCMG France
#  jerome.fenal AT logicacmg.com
#  Will be available at http://jfenal.free.fr/
#
# $Header: /home/jfenal/Solaris/sds.pl,v 1.5 2004/07/26 15:55:53 jfenal Exp jfenal $
# $Log: sds.pl,v $
# Revision 1.5  2004/07/26 15:55:53  jfenal
# soft-partition may be broken into many extents. Handle that.
#
# Revision 1.4  2004/07/26 14:13:03  jfenal
# Ajout des directives et liens sur les points de montage
#
# Revision 1.3  2003/12/11 15:06:58  root
# Corrections to device sizes computations.
# Added coloured output, using Term::ANSIColor.
#
# Revision 1.2  2003/10/31 01:34:49  root
# Légères corrections sur taille de miroir, ajout des tailles, et définition concat | stripe
#
# Revision 1.1  2003/10/31 01:33:05  root
# Initial revision
#
# Revision 1.2  2003/05/07 17:56:58  root
# Ajout information de taille de partition
# Prise en compte de cette information dans l'affichage des soft partitions
#

use Getopt::Std;
use Data::Dumper;
use integer;
use strict;

my %Axis = (
    3 => [ 8, 9, 10, 11, 12, 13 ],
    4 => [ 8, 9, 10, 11, 12, 13 ]
);

my %PartType = (
    0 => "UNASSIGNED",
    1 => "BOOT",
    2 => "ROOT",
    3 => "SWAP",
    4 => "USR",
    5 => "BACKUP",
    6 => "STAND",
    7 => "VAR",
    8 => "HOME",
    9 => "ALTSCTR",
    a => "CACHE",
);

my %PartFlag = (
    '00' => 'wm',
    '01' => 'nm',
    '10' => 'wr'
);

# %Devices :     $Device{nom du device} = description texte
# %LeafPhysDev : $LeafPhysDev{nom du device} = liste des devices physiques
#                                              directement sous la structure
# %SPContains :  $SPContains{nom du device} = liste des devices sur une SP
# %SPDev :       $SPDev{nom du device} = nom du device où est taillée
#                                        la soft partition
# %SPOffset :    $SPOffset{nom du device} = offset
# %SPSize :      $SPSize{nom du device} = taille
# %DevType :     $DevType{nom du device} = type
# %Explain :     $Explain{nom du device} = description en bon anglais
# %SubElements : $SubElements{nom du device} = liste des sous-devices d*
# %SoftPartitions:

use vars qw(
  %Devices %LeafPhysDev %SPOffset %SPSize %SPDev %SPContains
  %DevType %Explain $debug %SubElements
  %DevPhysicalDevices %Partitions %VTOC
  %dev2mp %mp2dev %pdev2mp %mp2pdev
  $color
);

sub getvtoc
{
    my $dev = shift;

    #  die "Bad format for disk name" if ( $disk !~ m/c\d+t\d+d\+s\d+/ );

    my $disk = $1 if $dev =~ m!(c\d+t\d+d\d+)s\d!;
    return if defined( $VTOC{$disk} );

    foreach my $n ( 0 .. 7 ) {
        my $pn = 'slice' . $n;
        $VTOC{$disk}{$pn}{'tag'}   = 0;
        $VTOC{$disk}{$pn}{'flag'}  = '00';
        $VTOC{$disk}{$pn}{'begin'} = 0;
        $VTOC{$disk}{$pn}{'count'} = 0;
        $VTOC{$disk}{$pn}{'last'}  = 0;
        $VTOC{$disk}{$pn}{'size'}  = 0;
    }

    open VTOC, "prtvtoc /dev/rdsk/" . $disk . "s2 |";
    while (<VTOC>) {
        my ( $n, $pn, $tag, $flag, $fsec, $secount, $lsector );

        $VTOC{$disk}{'bytespersector'}  = $1 if m!^\*\s+(\d+) bytes/sector!;
        $VTOC{$disk}{'sectorspertrack'} = $1 if m!^\*\s+(\d+) sectors/track!;
        $VTOC{$disk}{'sectorspercyl'}   = $1 if m!^\*\s+(\d+) sectors/cylinder!;
        $VTOC{$disk}{'cylinders'}       = $1 if m!^\*\s+(\d+) cylinders!;
        $VTOC{$disk}{'accylinders'} = $1 if m!^\*\s+(\d+) accessible cylinders!;
        next if ( $_ =~ /^\*.*$/ );

        ( $n, $tag, $flag, $fsec, $secount, $lsector ) = split;
        $pn = 'slice' . $n;

        #    $VTOC{$disk}{$pn}{'num'}=$n;
        $VTOC{$disk}{$pn}{'tag'}   = $tag;
        $VTOC{$disk}{$pn}{'flag'}  = $flag;
        $VTOC{$disk}{$pn}{'begin'} = $fsec;
        $VTOC{$disk}{$pn}{'count'} = $secount;
        $VTOC{$disk}{$pn}{'last'}  = $lsector;
    }
    close VTOC;
    foreach my $n ( 0 .. 7 ) {
        my $pn = 'slice' . $n;
        $VTOC{$disk}{$pn}{'size'} =
          $VTOC{$disk}{$pn}{'count'} * $VTOC{$disk}{'bytespersector'};
    }
}

sub getsize
{
    my $dev  = shift;
    my $size = 0;
    my $disk;
    my $pn;

    if ( $dev =~ m!(c\d+t\d+d\d+)s(\d+)! ) {
        ( $disk, $pn ) = ( $1, 'slice' . $2 );
        $size = $VTOC{$disk}{$pn}{'count'};
    } elsif ( $dev =~ /d\d+/ ) {
        my $msize = 1 << 30;
        if ( defined( $SPSize{$dev} ) ) {
            $size = $SPSize{$dev};
        } elsif ( defined( $SubElements{$dev} ) ) {
            foreach my $se ( @{ $SubElements{$dev} } ) {
                my $s = getsize($se);
                $msize = ( $s < $msize ) ? $s : $msize;
                $size += $s;
            }
            if ( defined( $DevType{$dev} ) && $DevType{$dev} eq 'mirror' ) {
                $size = $msize;    # le minima
            }
        }
    }

    return $size;
}

sub getsdsconfig
{
    my $metastatfile = shift;
    my $dev;                       # le device courant
    my $desc;                      # la description courante en texte
    my @desc;                      # la description courante en liste
    my %desc;                      # la description courante en hash
    open MS, $metastatfile;
    while (<MS>) {
        while ( $_ =~ /.*\\\n/ ) {
            chomp;                  # vire le \n final
            chop;                   # vire le \\ final pour ligne suivante
            $_ .= readline(*MS);    # concat de la ligne suivante
        }
        ( $dev, @desc ) = split;
        $Devices{$dev} = join " ", @desc;

        #print "$dev=$Devices{$dev}\n";
    }

    # On a maintenant un hash %Devices qui contient la config brute
    while ( ( $dev, $desc ) = each %Devices ) {

        #print "$dev = $desc\n" if $debug;
        for ($desc) {
            /^\-p.*/ and do {

                #  print "$dev is a soft partition ($desc)\n";
                @desc = split /\s+/, $desc;
                my %spdesc;
                while (my $opt = shift @desc) {
                    if ($opt eq '-p') {
                        $spdesc{'slice'} = shift @desc;
                    } elsif ($opt eq '-o') {
                        my $offset = shift @desc;
                        push @{$spdesc{'offsets'}}, $offset;
                        $opt = shift @desc;
                        if ($opt eq '-b') {
                            push @{$spdesc{'sizes'}}, shift @desc;
                        } else {
                            die "Soft-partition $dev has no size at offset $offset";
                        }
                    }
                }
                push @{ $LeafPhysDev{$dev} }, $spdesc{'slice'};
                #      push @{$SubElements{$dev}}, $spdesc{'slice'};
                $SPDev{$dev} = $spdesc{'slice'};

                # SPContains est un hash de tableau de tableau
                
                $SPSize{$dev} = 0;
                foreach my $i (0 .. $#{@{$spdesc{'offsets'}}}) {
                    my $size = @{$spdesc{'sizes'}}[$i];
                    push @{ $SPContains{ $spdesc{'slice'} } },
                      [  @{$spdesc{'offsets'}}[$i],  @{$spdesc{'sizes'}}[$i], $dev ];
                    $SPSize{$dev} += @{$spdesc{'sizes'}}[$i];
                }
                $SPOffset{$dev} = $spdesc{'offsets'};
                
                $DevType{$dev}  = "softpart";
                $Explain{$dev}  =
                  "$dev is a soft partition (dev="
                  . join ( " ", @{ $LeafPhysDev{$dev} } )
                  . ", size=$SPSize{$dev}, offset=("
                  . join(', ', @{$SPOffset{$dev}})
                  . ")";
                if ( $spdesc{'slice'} =~ /c\d+t\d+d\d+s\d+/ ) {
                    $Partitions{ $spdesc{'slice'} }{'use'}++;
                }
                print "$Explain{$dev}\n" if $debug;
                last;
            };
            /^\-m.*/ and do {

                #  print "$dev is a mirror ($desc)\n";
                @desc = split " ", $desc;
                shift;    # vire le -m
                foreach (@desc) {
                    if (/d\d+/) {
                        push @{ $SubElements{$dev} }, $_;
                    }
                }
                $DevType{$dev} = 'mirror';
                $Explain{$dev} =
                  "$dev is a mirror ("
                  . join ( " ", @{ $SubElements{$dev} } ) . ")";
                print "$Explain{$dev}\n" if $debug;
                print STDERR "WARNING : $DevType{$dev} $dev has only one side\n"
                  if ( @{ $SubElements{$dev} } == 1 && $debug );
                last;
            };
            /^[0-9]+.*/ and do {

                #  print "$dev is a concat stripe ($desc)\n";
                @desc = split " ", $desc;
                my $nstripe   = shift @desc;  # nombre de colonnes du stripe
                my $cstripe   = 0;            # nombre de concat dans la colonne
                my $maxconcat = 0;            # impossible
                                              #
                foreach my $i ( 1 .. $nstripe ) {
                    $cstripe   = shift @desc;
                    $maxconcat = $cstripe
                      if ( $maxconcat < $cstripe );    # max allégé
                    foreach my $j ( 1 .. $cstripe ) {
                        my $el = shift @desc;
                        if ( $el eq '-i' ) {
                            shift @desc;
                            $el = shift @desc;
                        }
                        for ($el) {
                            /d\d+/ and do {
                                push @{ $SubElements{$dev} }, $el;
                                last;
                            };
                            /c\d+t\d+d\d+s\d+/ and do {
                                push @{ $LeafPhysDev{Dev} }, $el;
                                $Partitions{$el}{'use'}++;

                                #              push @{$SubElements{$dev}}, $el;
                                last;
                            };
                        }
                    }
                }

                if ( $nstripe == 1 && $maxconcat == 1 ) {
                    $DevType{$dev} = "device";
                }
                if ( $nstripe > 1 && $maxconcat == 1 ) {
                    $DevType{$dev} = "concat";
                }
                if ( $nstripe == 1 && $maxconcat > 1 ) {
                    $DevType{$dev} = "stripe";
                }
                if ( $nstripe > 1 && $maxconcat > 1 ) {
                    $DevType{$dev} = "concat+stripe";
                }
                $Explain{$dev} =
                  "$dev is a $DevType{$dev} ("
                  . join ( " ", @{ $SubElements{$dev} } ) . ")";
                print "$Explain{$dev}\n" if $debug;
                last;
            };
        }

    }

    close MS;

    #
    # Passe pour assigner les physical à tt le monde
    #
    foreach $dev ( keys %Devices ) {
        foreach my $sdev ( getsubdevs($dev) ) {
            if ( defined( @{ $LeafPhysDev{$sdev} } ) ) {
                push @{ $DevPhysicalDevices{$dev} }, @{ $LeafPhysDev{$sdev} };
            }
        }
    }

    #
    # Recuperation des informations des partitions
    #
    foreach $dev ( keys %Partitions ) {
        getvtoc($dev) if $dev =~ m/c\d+t\d+d\d+/;
    }
    foreach $dev ( keys %LeafPhysDev ) {
        getvtoc($dev) if $dev =~ m/c\d+t\d+d\d+/;
    }
}

sub getmtab
{
    open MTAB, "/etc/mnttab" or die "Ne peut ouvrir la table des montages";
    while (<MTAB>) {
        chomp;
        my ( $dev, $mnt, $type, $opts, $inode );
        ( $dev, $mnt, $type, $opts, $inode ) = split /\s+/;
        if ( $type eq 'ufs' && $dev =~ m!/dev/md/dsk/(d\d+)! ) {
            $dev2mp{$1} = $mnt;
            foreach my $sdev ( getsubdevs($1) ) {
                $dev2mp{$sdev} = $mnt;
            }
            foreach my $pdev ( @{ $DevPhysicalDevices{$1} } ) {
                $pdev2mp{$pdev}{$mnt}++;
            }
        }
    }
    close MTAB;
    open STAB, "swap -l|" or die "Ne peut lancer la commande swap -l";
    while (<STAB>) {
        chomp;
        my ( $dev, $devn, $slo, $sbl, $sfree) = split /\s+/;
        if ( $dev =~ m!/dev/md/dsk/(d\d+)! ) {
            $dev2mp{$1} = "swap $devn";
            foreach my $sdev ( getsubdevs($1) ) {
                $dev2mp{$sdev} = "swap $devn";
            }
            foreach my $pdev ( @{ $DevPhysicalDevices{$1} } ) {
                $pdev2mp{$pdev}{"swap $devn"}++;
            }
        }
    }
    close STAB;

    foreach my $dev ( keys %dev2mp ) {
        push @{ $mp2dev{ $dev2mp{$dev} } }, ( $dev, getsubdevs($dev) );
        push @{ $mp2pdev{ $dev2mp{$dev} } },
          ( $dev, @{ $DevPhysicalDevices{$dev} } )
          if ( defined( $DevPhysicalDevices{$dev} ) );
    }
    print Dumper \%dev2mp  if $debug;
    print Dumper \%pdev2mp if $debug;
    print Dumper \%mp2dev  if $debug;

    #  exit 1;
}

sub showaxis
{
    foreach ( keys %Axis ) {
        printf "%3d : ", $_;
        print join ( " ", @{ $Axis{$_} } ) . "\n";
    }
}

sub showconfig
{
    print "Apercu de la configuration :\n";
    my @devs = keys %Explain;

    #print "--- Devices\n";          print Dumper(\%Devices);
    #print "--- Leaf Physical Devices\n";  print Dumper(\%LeafPhysDev);
    #print "--- Physical Devices\n";    print Dumper(\%DevPhysicalDevices);
    #print "--- Device types\n";      print Dumper(\%DevType);
    #print "--- Sub elements\n";      print Dumper(\%SubElements);
    #print "--- Soft partition\n";      print Dumper(\%SPDev);
    #print "--- Dumping Partitions uses\n";    print Dumper(\%Partitions);
    #print "--- Dumping VTOC\n";      print Dumper(\%VTOC);
    #exit;

    foreach (@devs) {
        s/^d//;
    }

    foreach ( sort { $a <=> $b } @devs ) {
        my $devsize = getsize( 'd' . $_ ) >> 11;
        print "d$_ ($DevType{'d'.$_}) : $Explain{'d'.$_} ($devsize Mo)\n";
    }

    if ($debug) {
        print "--- Soft partition contains\n";
        print Dumper( \%SPContains );
    }
}

sub showsp
{
    sub sortbyoffset { $a->[0] <=> $b->[0] }

# FIXME
#print Dumper \@{$SPContains{'c3t11d0s0'}};
#exit;
    foreach my $dev ( sort @_ ) {
        my $offset       = 1;
        my $precendblock = -1;
        if ( exists( $SPContains{$dev} ) ) {
            print "\n---- Contenu de la soft partition $dev ----\n";
            print
"Partition | Device |     Offset |        End |       Size            | Mountpoint\n";
            print
"----------+--------+------------+------------+-----------------------------------\n";
            my $tsize = 0;
            foreach my $list ( sort sortbyoffset @{ $SPContains{$dev} } ) {
                my $offset   = $list->[0];
                my $size     = $list->[1];
                my $endblock = $offset + $size - 1;

                if ( ( $offset - $precendblock ) > 2 ) {
                    print color('green') if $color;
                    printf(
                        "%-9s | *FREE* | %10d | %10d | %10d (%5d Mo) | free\n",
                        $dev,
                        $precendblock + 2,
                        $offset - 2,
                        $offset - $precendblock - 3,
                        ( $offset - $precendblock - 3 ) >> 11,
                    );
                    print color('reset') if $color;
                }

                printf(
                    "%-9s |  %5s | %10d | %10d | %10d (%5d Mo) | %s\n",
                    $dev,
                    $list->[2],
                    $offset,
                    $endblock,
                    $size,
                    $size >> 11,
                    defined $dev2mp{ $list->[2] } ? $dev2mp{ $list->[2] } : ''
                );
                $tsize += $list->[1];
                $precendblock = $endblock;
            }

            if ( $dev =~ m!(c\d+t\d+d\d+)s(\d)! ) {
                my ( $disk, $pn );
                ( $disk, $pn ) = ( $1, 'slice' . $2 );
                if (
                    (
                        my $free =
                        $VTOC{$disk}{$pn}{'count'} - ( $precendblock + 2 )
                    ) > 0
                  )
                {
                    print color('green') if $color;
                    printf(
                        "%-9s | *FREE* | %10d | %10d | %10d (%5d Mo) | free\n",
                        $dev,
                        $precendblock + 2,
                        $VTOC{$disk}{$pn}{'count'},
                        $free, $free >> 11,
                    );
                    print color('reset') if $color;
                } else {
                    print color('red') if $color;
                    printf( "%-9s | No more free space...\n", $dev );
                    print color('reset') if $color;
                }
            } else {
                my $devsize = getsize($dev);
                if ( ( my $free = $devsize - $precendblock - 1 ) > 0 ) {
                    print color('green') if $color;
                    printf(
                        "%-9s | *FREE* | %10d | %10d | %10d (%5d Mo) | free\n",
                        $dev, $precendblock + 2,
                        $devsize, $free, $free >> 11,
                    );
                    print color('reset') if $color;
                }
            }
            print
"----------+--------+------------+------------+-----------------------------------\n";
            printf(
"Total space used   |            |            | %10d (%5d Mo)\n",
                $tsize, $tsize >> 11 );
        }
    }
}

#
# Print an explaination about devices asked
#
sub explaindev
{
    my $dev;
    foreach $dev (@_) {
        my $devsize = getsize($dev) >> 11;
        print "$Explain{$dev}. It is $devsize MB large\n";
    }
}

sub showpart
{
    my $dev;
    foreach $dev ( sort @_ ) {
        print "Description du disque $dev\n";
        print "$VTOC{$dev}{'bytespersector'} bytes/sector\n";
        print "$VTOC{$dev}{'sectorspertrack'} sectors/track\n";
        print "$VTOC{$dev}{'sectorspercyl'} sectors/cylinder\n";
        print "$VTOC{$dev}{'cylinders'} cylinders\n";
        print "$VTOC{$dev}{'accylinders'} accessible cylinders\n";
        print "\n";
        print "Partitions du disque $dev\n";
        print
" slice  | Usage      | Flag | Sec. Debut | Sec. Fin   | Taille (s) | Taille Mo\n";

        foreach my $slnumber ( 0 .. 7 ) {
            my $slice = $VTOC{$dev}{ 'slice' . $slnumber };

            #        tag   flag  begin   count last
            printf(
                "%7s | %10s |   %2s | %10d | %10d | %10d | %5d Mo\n",
                'slice' . $slnumber,
                $PartType{ $slice->{'tag'} },
                $PartFlag{ $slice->{'flag'} },
                $slice->{'begin'},
                $slice->{'count'},
                $slice->{'last'},
                $slice->{'count'} >> 11
            );
        }
    }
}

sub getnextdev
{
    my @devs = keys %Explain;

    foreach (@devs) {
        s/^d//;
    }

    my @sdev = sort { $a <=> $b } @devs;

    return $sdev[-1] + 1;
}

sub isdevfree
{
    my $dev = shift;

    $dev = 'd' . $dev if ( $dev =~ /\d/ );
    if ( exists $Devices{$dev} ) {
        print "Device $dev exists\n" if $debug;
        explaindev($dev);
        return 0;
    } else {
        print "Device $dev is free\n" if $debug;
        return 1;
    }
}

# $1 = dev_id
# $2 = axis
# $3 = size
# [$4] = mountpoint
# to make a mirror, we have to :
# - make a soft part
# - make concat/dev containing the soft part
# - use two of these in a mirror
# axis : 0..number of disks
# side : 0..1
# d40+5*n : mirror device
# d40+5*n + (side*2) + 1 : concat/stripe device lying on +2
# d40+5*n + (side*2) + 2 : soft partition
# make both soft parts
sub mkmirror
{
    my $dev_id     = shift;
    my $axis       = shift;
    my $size       = shift;
    my $mountpoint = shift;    # as forcement renseigne
    if ( defined($mountpoint) && $mountpoint !~ /^\/.*/ ) {
        undef $mountpoint;
    }

    foreach ( 0 .. 4 ) {
        my $testid = $dev_id + $_;
        if ( !isdevfree($testid) ) {
            print "#!! WARNING : device d$testid not free, aborting\n";
            exit 1;
        }
    }

    my @concats;
    my $i;
    foreach $i ( 0 .. 1 ) {    # pans de mirroir
        my $concat   = $dev_id + $i * 2 + 1;
        my $softpart = $dev_id + $i * 2 + 2;
        print "#### concat $i = $concat"     if $debug;
        print "#### softpart $i = $softpart" if $debug;

        # softpart
        my @Ctrls = keys %Axis;
        my @Disks = @{ $Axis{ $Ctrls[$i] } };
        print "metainit d$softpart -p c$Ctrls[$i]t$Disks[$axis]d0s0 $size\n";

        # concat on soft part
        print "metainit d$concat 1 1 d$softpart\n";
        $concats[$i] = $concat;
    }

    # mirror itself
    print "metainit d$dev_id -m d$concats[0]\n";
    print "#metattach d$dev_id  d$concats[1]\n";

    print "newfs /dev/md/dsk/d$dev_id\n";
    if ( defined($mountpoint) ) {
        print "mkdir $mountpoint\n";
        print "mount /dev/md/dsk/d$dev_id $mountpoint\n";
    }
}

sub getsubdevs
{
    my @subdevs;
    my $dev = shift;

    print "Device demandé : $dev\n" if $debug;
    if ( defined( @{ $SubElements{$dev} } ) ) {
        @subdevs = @{ $SubElements{$dev} };
        print "Sous éléments : @subdevs\n" if $debug;
        foreach my $cdev (@subdevs) {
            if ( $cdev =~ /d\d+/ ) {
                push @subdevs, getsubdevs($cdev);
            }
        }
    }
    return @subdevs;
}

sub test
{

    #print "Commande = $command\n";
    #my ($axe, $disques, $disk);
    #while (($axe, $disques) = each(%Axis)) {
    #  while ($disk = shift @disques)
    #  print "Axis $axe : $disk\n";
    #    foreach $disk (@$disques) {
    #      print $axe." ".$disk."\n" if $debug;
    #    }
    #  }
}

sub say_usage
{
    print "SDS Manager - Jerome Fenal, LogicaCMG France\n";
    print '$Revision: 1.5 $';
    print "\n\n\t$0  [-c] [-i id] command ...\n";
    print << 'EOT';
Options:
  [-f <metastat-p.txt>] :  use <metastat-p.txt> as "metastat -p" cmd output
  [-c] :      turn coloured output on
  [-h] :      show this help text
  [-i <newdevid>] :  use newdevid as new metadevice id
        instead of first avail.
Commands:
  showaxis               : show available axis
  showpart               : show partitions of all the disks involved
  getnextdev             : retrieve the next free device
  isdevfree [d]num       : is the device <dnum> free ?
  showconfig             : view all the config
  showsp [<dev|slice>+]  : view all devices on device or slices
  getphysdevs <dev>      : show physical device(s) underlying a SDS device
  getsubdevs <dev>       : show underlying device(s) for a SDS device
  explaindev <dev>       : tries to explain a SDS device in pure english

  mpondev <dev>          : mount point on <dev>
  mpondisk <disk>        : mount point on <disk> (in a form present in SDS)
  devs4mp </mountpoint>  : what are the devices underlying a mount point
  disks4mp </mountpoint> : what are the physical devices underlying a mount point

  mkmirror <axis> <size> [<mp>] : make mirror on specified axis
    axis : from $o showaxis
    size : see man metainit (section Soft Partitions)
    mp   : mount point (optional)

  <dev> has the form dnumber as in d1 or d165
  <slice> has the form cxtydzst as in c0t0d0s0

EOT
    exit 0;
}

# Main

use vars qw($opt_d $opt_i $opt_f $opt_h $opt_c $color);
my $metastatfile;

getopts('cdi:f:h');

# Sets opt_* as a side effect.

say_usage() if $opt_h;

my $NewDeviceID =
  $opt_i;    # soit le dernier non utilise', soit specifie par l'utilisateur

if ($opt_c) {
    $color = 1;
    use Term::ANSIColor;
}

$debug = 1 if ($opt_d);
if ($opt_f) {
    $metastatfile = '<' . $opt_f;
} else {
    $metastatfile = "/usr/sbin/metastat -p |";
}

my $command = shift;    # commande (showpart, etc)
print "Commmand : $command \n" if $debug;

say_usage() unless defined($command);

getsdsconfig($metastatfile);
getmtab();

for ($command) {
    /showaxis/ and do { showaxis; last; };
    /explaindev/ and do {
        my $dev = shift @ARGV;
        explaindev($dev) if defined $Devices{$dev};
        last;
    };
    /getsize/ and do {
        my $dev = shift @ARGV;
        if ( defined $Devices{$dev} ) {
            ;
            my $size = getsize($dev) if defined $Devices{$dev};
            $size >>= 11;
            print "Taille de $dev : $size Mo\n";
        }
        last;
    };
    /showconfig/ and do { showconfig(); last; };
    /getphysdevs/ and do {
        my $dev = shift @ARGV;

        if ( exists( $Devices{$dev} ) ) {
            print join ( " ", @{ $DevPhysicalDevices{$dev} } ) . "\n";
        }
        last;
    };
    /getnextdev/ and do { print getnextdev() . "\n"; last; };
    /isdevfree/ and do {
        my $dev = shift @ARGV;
        $debug = 1;
        isdevfree($dev);
        last;
    };
    /showpart/ and do {
        my @partitions = ( $#ARGV == -1 ) ? keys %VTOC : @ARGV;
        showpart @partitions;
        last;
    };
    /showsp/ and do {
        my @sps = ( $#ARGV == -1 ) ? keys %SPContains : @ARGV;
        showsp @sps;
        last;
    };
    /getsubdevs/ and do {
        my $dev  = shift @ARGV;
        my @sdev = getsubdevs($dev);
        print "Sous-éléments de $dev : @sdev\n";
        last;
    };
    /mkmirror/ and do {
        if ( $#ARGV ne 1 && $#ARGV ne 2 ) {
            print "ERROR : mkmirror must have 2 or 3 args\n";
            say_usage();
        }
        mkmirror $NewDeviceID, @ARGV;
        last;
    };
    /mpondisk/ and do {
        my $disk = shift;
        if ( defined( $pdev2mp{$disk} ) ) {
            print "$disk:" . join ( " ", keys %{ $pdev2mp{$disk} } ) . "\n";
        } else {
            print "$disk not in SDS config\n";
        }
        last;
    };
    /mpondev/ and do {
        my $dev = shift;
        if ( defined( $dev2mp{$dev} ) ) {
            print "$dev: $dev2mp{$dev}\n";
        }

        last;
    };
    /devs4mp/ and do {
        my $mp = shift;
        if ( defined( $mp2dev{$mp} ) ) {
            print "$mp: " . join ( " ", @{ $mp2dev{$mp} } ) . "\n";
        }
        last;
    };
    /disks4mp/ and do {
        my $mp = shift;
        if ( defined( $mp2pdev{$mp} ) ) {
            print "$mp:" . join ( " ", @{ $mp2pdev{$mp} } ) . "\n";
        }

        last;
    };

    /.*/ and do { say_usage(); last; };
}

