Permute array.pl

From Linux Raid Wiki
(Difference between revisions)
Jump to: navigation, search
(Initial raid5 permutation script)
 
m (quietened down and shows possible solutions)
 
Line 13: Line 13:
 
  return "syntax: permute_array --md <md_device> --mount <mountpoint> [--opts <mdadm options>] [--for_real] <all devices>\n";
 
  return "syntax: permute_array --md <md_device> --mount <mountpoint> [--opts <mdadm options>] [--for_real] <all devices>\n";
 
}
 
}
 +
 +
my $MD_DEVICE;
 +
my $MOUNTPOINT;
 +
my $MDADM_OPTS="";
 +
my $REAL;
  
 
################################################################
 
################################################################
Line 24: Line 29:
  
 
   # This may need a --force... <gulp>
 
   # This may need a --force... <gulp>
   my $create = "mdadm --create $MD_DEVICE --num-devices=$num_devices --level=5 $MDADM_OPTS @device_list\n";
+
   my $create = "yes | mdadm --create $MD_DEVICE --raid-devices=$num_devices --level=5 $MDADM_OPTS @device_list 2>/dev/null\n";
 
   # Don't forget to mount read-only
 
   # Don't forget to mount read-only
   my $mount =  "mount -oro $MD_DEVICE $MOUNTPOINT";
+
   my $mount =  "mount -oro $MD_DEVICE $MOUNTPOINT 2>/dev/null";
 +
  my $umount =  "umount $MOUNTPOINT 2>/dev/null";
 
   # and stop the array...
 
   # and stop the array...
   my $stop = "mdadm --stop $MD_DEVICE";
+
   my $stop = "mdadm --stop $MD_DEVICE 2>/dev/null";
  
 
   # REAL == --for_real option
 
   # REAL == --for_real option
Line 40: Line 46:
 
     system $mount;
 
     system $mount;
 
     if (!(my $err = $?>>8)) {
 
     if (!(my $err = $?>>8)) {
       die "\n\n\nSuccess. Command : $create\nworked\nArray is mounted ($mount)\n\n\n";
+
       print "Success. possible command : \n $create\n";
 +
      system $umount;
 
     }
 
     }
 
     # we expect this to succeed
 
     # we expect this to succeed
Line 58: Line 65:
 
# Execution starts here...
 
# Execution starts here...
 
#
 
#
my $MD_DEVICE;
 
my $MOUNTPOINT;
 
my $MDADM_OPTS;
 
my $REAL;
 
 
sub factorial($);
 
sub factorial($);
  

Latest revision as of 13:39, 13 July 2007

#!/usr/bin/perl -w

# If you forgot how you built an array and need to try various
# permutations then this is for you...

# based on Mark-Jason Dominus' mjd_permute: permute each word of input

use strict;
use Getopt::Long;

sub usage {
 return "syntax: permute_array --md <md_device> --mount <mountpoint> [--opts <mdadm options>] [--for_real] <all devices>\n";
}

my $MD_DEVICE;
my $MOUNTPOINT;
my $MDADM_OPTS="";
my $REAL;

################################################################
# This function is passed each permutation of component devices.
# This includes a 'missing' device.
# This is the place to hack command variations etc... 
sub try_array {
  # @_ looks like: ("/dev/sda1", "missing", "/dev/sdb1")
  my @device_list = @_;
  my $num_devices = scalar @_;

  # This may need a --force... <gulp>
  my $create = "yes | mdadm --create $MD_DEVICE --raid-devices=$num_devices --level=5 $MDADM_OPTS @device_list 2>/dev/null\n";
  # Don't forget to mount read-only
  my $mount =  "mount -oro $MD_DEVICE $MOUNTPOINT 2>/dev/null";
  my $umount =  "umount $MOUNTPOINT 2>/dev/null";
  # and stop the array...
  my $stop = "mdadm --stop $MD_DEVICE 2>/dev/null";

  # REAL == --for_real option
  if ($REAL) {
    # we expect this to succeed
    system $create;
    if (my $err = $?>>8) {
      die "command : $create\n   exited with status $err\n\n";
    }
    # we expect this to fail and are happy if it succeeds
    system $mount;
    if (!(my $err = $?>>8)) {
      print "Success. possible command : \n  $create\n";
      system $umount;
    }
    # we expect this to succeed
    system $stop;
    if (my $err = $?>>8) {
      die "command : $stop\n   exited with status $err\n\n";
    }
  } else {
    # Just show the create/mount/stop commands
    # If you want more control you could use this to write a script
    print "$create\n$mount\n$stop\n";
  }
}


################################################################
# Execution starts here...
#
sub factorial($);

GetOptions ('md=s'      => \$MD_DEVICE,
	    "mount=s"   => \$MOUNTPOINT,
	    "opts=s"    => \$MDADM_OPTS,
	    "for_real"  => \$REAL);

if (!defined($MD_DEVICE) or !defined($MOUNTPOINT)) {
  die &usage;
}

print "using device $MD_DEVICE and mounting on $MOUNTPOINT\n";

# we *always* assume a 'missing' device - not doing so will destroy
# the array...
my @devices = @ARGV;
# how many devices?
my $num_devices = scalar @devices;
if ($num_devices < 2) {
  die "$0 needs at least two component devices\n";
}
# how many base permutations...
my $num_permutations = factorial(scalar @devices);
# try all permutations, substituting 'missing' for each device in
# turn...
for (my $d=0; $d < $num_devices; $d++) {
  my $skip_device = $devices[$d];
  $devices[$d] = "missing";
  print "skipping $skip_device\n\n";
  for (my $i=0; $i < $num_permutations; $i++) {
    my @permutation = @devices[n2perm($i, $#devices)];
    try_array(@permutation);
  }
  $devices[$d] = $skip_device;
}

################################################################
# permutation code

# n2pat($N, $len) : produce the $N-th pattern of length $len
sub n2pat {
    my $i   = 1;
    my $N   = shift;
    my $len = shift;
    my @pat;
    while ($i <= $len + 1) {   # Should really be just while ($N) { ...
        push @pat, $N % $i;
        $N = int($N/$i);
        $i++;
    }
    return @pat;
}

# pat2perm(@pat) : turn pattern returned by n2pat() into
# permutation of integers.  XXX: splice is already O(N)
sub pat2perm {
    my @pat    = @_;
    my @source = (0 .. $#pat);
    my @perm;
    push @perm, splice(@source, (pop @pat), 1) while @pat;
    return @perm;
}

# n2perm($N, $len) : generate the Nth permutation of $len objects
sub n2perm {
    pat2perm(n2pat(@_));
}

# Utility function: factorial with memoizing
BEGIN {
  my @fact = (1);
  sub factorial($) {
    my $n = shift;
    return $fact[$n] if defined $fact[$n];
    $fact[$n] = $n * factorial($n - 1);
  }
}
Personal tools