Permute array.pl
From Linux Raid Wiki
Revision as of 10:24, 13 July 2007 by DavidGreaves (Talk | contribs)
#!/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"; } ################################################################ # 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 = "mdadm --create $MD_DEVICE --num-devices=$num_devices --level=5 $MDADM_OPTS @device_list\n"; # Don't forget to mount read-only my $mount = "mount -oro $MD_DEVICE $MOUNTPOINT"; # and stop the array... my $stop = "mdadm --stop $MD_DEVICE"; # 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)) { die "\n\n\nSuccess. Command : $create\nworked\nArray is mounted ($mount)\n\n\n"; } # 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... # my $MD_DEVICE; my $MOUNTPOINT; my $MDADM_OPTS; my $REAL; 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); } }