Viewing file: raid-lib.pl (20.69 KB) -rwxr-xr-x Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
# raid-lib.pl # Functions for managing RAID
BEGIN { push(@INC, ".."); }; use WebminCore; &init_config(); &foreign_require("fdisk");
open(MODE, "$module_config_directory/mode"); chop($raid_mode = <MODE>); close(MODE);
%container = ( 'raiddev', 1, 'device', 1 );
# get_raid_levels() # Returns a list of allowed RAID levels sub get_raid_levels { if ($raid_mode eq "mdadm") { return ( 0, 1, 4, 5, 6, 10 ); } else { return ( 0, 1, 4, 5 ); } }
# get_mdstat() # Read information about active RAID devices. Returns a hash indexed by # device name (like /dev/md0), with each value being an array reference # containing status level disks blocks resync disk-info sub get_mdstat { # Read the mdstat file local %mdstat; local $lastdev; open(MDSTAT, $config{'mdstat'}); while(<MDSTAT>) { if (/^(md\d+)\s*:\s+(\S+)\s+(\S+)\s+(.*)\s+(\d+)\s+blocks\s*(.*)resync=(\d+)/) { $mdstat{$lastdev = "/dev/$1"} = [ $2, $3, $4, $5, $7, $6 ]; } elsif (/^(md\d+)\s*:\s+(\S+)\s+(\S+)\s+(.*)\s+(\d+)\s+blocks\s*(.*)/) { $mdstat{$lastdev = "/dev/$1"} = [ $2, $3, $4, $5, undef, $6 ]; } elsif (/^(md\d+)\s*:\s+(\S+)\s+(\S+)\s+(.*)/) { $mdstat{$lastdev = "/dev/$1"} = [ $2, $3, $4 ]; $_ = <MDSTAT>; if (/\s+(\d+)\s+blocks\s*(.*)resync=(\d+)/) { $mdstat{$lastdev}->[3] = $1; $mdstat{$lastdev}->[4] = $3; $mdstat{$lastdev}->[5] = $2; } elsif (/\s+(\d+)\s+blocks\s*(.*)/) { $mdstat{$lastdev}->[3] = $1; $mdstat{$lastdev}->[5] = $2; } } } close(MDSTAT); return %mdstat; }
# get_raidtab() # Parse the raid config file into a list of devices sub get_raidtab { local ($raiddev, $device, %mdstat); return \@get_raidtab_cache if (scalar(@get_raidtab_cache)); %mdstat = &get_mdstat();
if ($raid_mode eq "raidtools") { # Read the raidtab file local $lnum = 0; open(RAID, $config{'raidtab'}); while(<RAID>) { s/\r|\n//g; s/#.*$//; if (/^\s*(\S+)\s+(\S+)/) { local $dir = { 'name' => lc($1), 'value' => $2, 'line' => $lnum, 'eline' => $lnum }; if ($dir->{'name'} =~ /^(raid|spare|parity|failed)-disk$/) { push(@{$device->{'members'}}, $dir); $device->{'eline'} = $lnum; $raiddev->{'eline'} = $lnum; } elsif ($dir->{'name'} eq 'raiddev') { $dir->{'index'} = scalar(@get_raidtab_cache); push(@get_raidtab_cache, $dir); } else { push(@{$raiddev->{'members'}}, $dir); $raiddev->{'eline'} = $lnum; } if ($dir->{'name'} eq 'device') { $device = $dir; } elsif ($dir->{'name'} eq 'raiddev') { $raiddev = $dir; local $m = $mdstat{$dir->{'value'}}; $dir->{'active'} = $m->[0] =~ /^active/; $dir->{'level'} = $m->[1] =~ /raid(\d+)/ ? $1 : $m->[1]; $dir->{'devices'} = [ map { /(\S+)\[\d+\](\((.)\))?/; $3 eq 'F' ? () : ("/dev/$1") } split(/\s+/, $m->[2]) ]; $dir->{'size'} = $m->[3]; $dir->{'resync'} = $m->[4]; $dir->{'errors'} = &disk_errors($m->[5]); } } $lnum++; } close(RAID); } else { # Fake up the same format from mdadm output local $m; foreach $m (sort { $a cmp $b } keys %mdstat) { local $md = { 'value' => $m, 'members' => [ ], 'index' => scalar(@get_raidtab_cache) }; local $mdstat = $mdstat{$md->{'value'}}; $md->{'active'} = $mdstat->[0] =~ /^active/; $md->{'level'} = $mdstat->[1] =~ /raid(\d+)/ ? $1 : $mdstat->[1]; $md->{'devices'} = [ map { /(\S+)\[\d+\](\((.)\))?/; $3 eq 'F' ? () : (&convert_to_hd("/dev/$1")) } split(/\s+/, $mdstat->[2]) ]; $md->{'size'} = $mdstat->[3]; $md->{'resync'} = $mdstat->[4]; $md->{'errors'} = &disk_errors($mdstat->[5]); open(MDSTAT, "mdadm --detail $m |"); while(<MDSTAT>) { if (/^\s*Raid\s+Level\s*:\s*(\S+)/) { local $lvl = $1; $lvl =~ s/^raid//; push(@{$md->{'members'}}, { 'name' => 'raid-level', 'value' => $lvl }); } elsif (/^\s*Persistence\s*:\s*(.*)/) { push(@{$md->{'members'}}, { 'name' => 'persistent-superblock', 'value' => $1 =~ /is\s+persistent/ }); } elsif (/^\s*State\s*:\s*(.*)/) { $md->{'state'} = $1; } elsif ((/^\s*Rebuild\s+Status\s*:\s*([0-9\.]+)\s*\%/) || (/^\s*Reshape\s+Status\s*:\s*(\d+)\s*\%/)) { $md->{'rebuild'} = $1; } elsif (/^\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+|\-)\s+(.*\S)\s+(\/\S+)/) { # A device line local $device = { 'name' => 'device', 'value' => $6, 'members' => [ ] }; push(@{$device->{'members'}}, { 'name' => $5 eq 'spare' ? 'spare-disk' : 'raid-disk', 'value' => $3 }); push(@{$md->{'members'}}, $device); } elsif (/^\s+(Chunk\s+Size|Rounding)\s+:\s+(\d+)/i) { push(@{$md->{'members'}}, { 'name' => 'chunk-size', 'value' => $2 }); } } close(MDSTAT); open(MDSTAT, $config{'mdstat'}); while(<MDSTAT>){ if (/^.*finish=(\S+)min/){ $md->{'remain'} = $1; } if (/^.*speed=(\S+)K/){ $md->{'speed'} = $1; } } close(MDSTAT); push(@get_raidtab_cache, $md); }
# Merge in info from mdadm.conf local $lref = &read_file_lines($config{'mdadm'}); foreach my $l (@$lref) { if ($l =~ /^ARRAY\s+(\S+)\s*(.*)/) { local $dev = $1; local %opts = map { split(/=/, $_, 2) } split(/\s+/, $2); local ($md) = grep { $_->{'value'} eq $dev } @get_raidtab_cache; if ($md) { push(@{$md->{'members'}}, { 'name' => 'spare-group', 'value' => $opts{'spare-group'} }); } } } } return \@get_raidtab_cache; }
# disk_errors(string) # Converts an mdstat errors string into an array of disk statuses sub disk_errors { if ($_[0] =~ /\[([0-9\/]+)\].*\[([A-Z_]+)\]/i) { local ($idxs, $errs) = ($1, $2); local @idxs = split(/\//, $idxs); local @errs = split(//, $errs); #if (@idxs == @errs) { # return [ map { $errs[$_-1] } @idxs ]; # } return \@errs; } return undef; }
sub lock_raid_files { &lock_file($raid_mode eq "raidtools" ? $config{'raidtab'} : $config{'mdadm'}); }
sub unlock_raid_files { &unlock_file($raid_mode eq "raidtools" ? $config{'raidtab'} : $config{'mdadm'}); }
# create_raid(&raid) # Create a new raid set in the configuration file sub create_raid { if ($raid_mode eq "raidtools") { # Add to /etc/raidtab local $lref = &read_file_lines($config{'raidtab'}); $_[0]->{'line'} = @$lref; push(@$lref, &directive_lines($_[0])); $_[0]->{'eline'} = @$lref - 1; &flush_file_lines(); } else { # Add to /etc/mdadm.conf local ($d, @devices); foreach $d (&find("device", $_[0]->{'members'})) { push(@devices, $d->{'value'}); } local $sg = &find_value("spare-group", $_[0]->{'members'}); local $lref = &read_file_lines($config{'mdadm'}); local $lvl = &find_value('raid-level', $_[0]->{'members'}); $lvl = $lvl =~ /^\d+$/ ? "raid$lvl" : $lvl; push(@$lref, "DEVICE ". join(" ", map { &device_to_volid($_) } @devices)); push(@$lref, "ARRAY $_[0]->{'value'} level=$lvl devices=". join(",", @devices). ($sg ? " spare-group=$sg" : "")); &flush_file_lines(); &update_initramfs(); } }
# delete_raid(&raid) # Delete a raid set from the config file sub delete_raid { if ($raid_mode eq "raidtools") { # Remove from /etc/raidtab local $lref = &read_file_lines($config{'raidtab'}); splice(@$lref, $_[0]->{'line'}, $_[0]->{'eline'} - $_[0]->{'line'} + 1); &flush_file_lines($config{'raidtab'}); } else { # Zero out the RAID &system_logged("mdadm --zero-superblock ". "$_[0]->{'value'} >/dev/null 2>&1");
# Zero out component superblocks my @devs = &find('device', $_[0]->{'members'}); foreach $d (@devs) { if (&find('raid-disk', $d->{'members'}) || &find('parity-disk', $d->{'members'}) || &find('spare-disk', $d->{'members'})) { &system_logged("mdadm --zero-superblock ". "$d->{'value'} >/dev/null 2>&1"); } }
# Remove from /etc/mdadm.conf local ($d, %devices); foreach $d (&find("device", $_[0]->{'members'})) { $devices{$d->{'value'}} = 1; } local $lref = &read_file_lines($config{'mdadm'}); local $i; for($i=0; $i<@$lref; $i++) { if ($lref->[$i] =~ /^ARRAY\s+(\S+)/ && $1 eq $_[0]->{'value'}) { splice(@$lref, $i--, 1); } elsif ($lref->[$i] =~ /^DEVICE\s+(.*)/) { local @olddevices = split(/\s+/, $1); local @newdevices = grep { !$devices{$_} } @olddevices; if (@newdevices) { $lref->[$i] = "DEVICE ".join(" ", @newdevices); } else { splice(@$lref, $i--, 1); } } } &flush_file_lines($config{'mdadm'}); &update_initramfs(); } }
# device_to_volid(device) # Given a device name like /dev/sda1, convert it to a volume ID if possible. # Otherwise return the device name. sub device_to_volid { local ($dev) = @_; return $dev; #return &fdisk::get_volid($dev) || $dev; }
# make_raid(&raid, force, [missing], [assume-clean]) # Call mkraid or mdadm to make a raid set for real sub make_raid { if (!-r $_[0]->{'value'} && $_[0]->{'value'} =~ /\/md(\d+)$/) { # Device file is missing - create it now &system_logged("mknod $_[0]->{'value'} b 9 $1"); } if ($raid_mode eq "raidtools") { # Call the raidtools mkraid command local $f = $_[1] ? "--really-force" : ""; local $out = &backquote_logged("mkraid $f $_[0]->{'value'} ". "2>&1 </dev/null"); return $? ? &text($out =~ /force/i ? 'eforce' : 'emkraid', "<pre>$out</pre>") : undef; } else { # Call the complete mdadm command local $lvl = &find_value("raid-level", $_[0]->{'members'}); $lvl =~ s/^raid//; local $chunk = &find_value("chunk-size", $_[0]->{'members'}); local $mode = &find_value("persistent-superblock", $_[0]->{'members'}) ? "create" : "build"; local $layout = &find_value("parity-algorithm", $_[0]->{'members'}); local ($d, @devices, @spares, @parities); foreach $d (&find("device", $_[0]->{'members'})) { if (&find("raid-disk", $d->{'members'})) { push(@devices, $d->{'value'}); } elsif (&find("spare-disk", $d->{'members'})) { push(@spares, $d->{'value'}); } elsif (&find("parity-disk", $d->{'members'})) { push(@parities, $d->{'value'}); } } local $cmd = "mdadm --$mode --level $lvl --chunk $chunk"; if ($_[2]) { push(@devices, "missing"); } $cmd .= " --layout $layout" if ($layout); $cmd .= " --raid-devices ".scalar(@devices); $cmd .= " --spare-devices ".scalar(@spares) if (@spares); $cmd .= " --force" if ($_[1]); $cmd .= " --assume-clean" if ($_[3]); $cmd .= " --run"; $cmd .= " $_[0]->{'value'}"; foreach $d (@devices, @parities, @spares) { $cmd .= " $d"; } local $out = &backquote_logged("$cmd 2>&1 </dev/null"); return $? ? &text('emdadmcreate', "<pre>$out</pre>") : undef; } }
# readwrite_raid(&raid) # Set RAID mode to read/write. sub readwrite_raid { local $cmd = "mdadm --readwrite $_[0]->{'value'}"; local $out = &backquote_logged("$cmd 2>&1 </dev/null"); return; }
# unmake_raid(&raid) # Shut down a RAID set permanently sub unmake_raid { if ($raid_mode eq "raidtools") { &deactivate_raid($_[0]) if ($_[0]->{'active'}); } else { local $out = &backquote_logged("mdadm --stop $_[0]->{'value'} 2>&1"); &error(&text('emdadmstop', "<tt>$out</tt>")) if ($?); } }
# activate_raid(&raid) # Activate a raid set, which has previously been deactivated sub activate_raid { if ($raid_mode eq "raidtools") { local $out = &backquote_logged("raidstart $_[0]->{'value'} 2>&1"); &error(&text('eraidstart', "<tt>$out</tt>")) if ($?); } }
# deactivate_raid(&raid) # Deactivate a raid set, without actually deleting it sub deactivate_raid { if ($raid_mode eq "raidtools") { # Just stop the raid set local $out = &backquote_logged("raidstop $_[0]->{'value'} 2>&1"); &error(&text('eraidstop', "<tt>$out</tt>")) if ($?); } }
# add_partition(&raid, device) # Adds a device to some RAID set, both in the config file and for real sub add_partition { if ($raid_mode eq "mdadm") { # Call mdadm command to add local $out = &backquote_logged( "mdadm --manage $_[0]->{'value'} --add $_[1] 2>&1"); &error(&text('emdadmadd', "<tt>$out</tt>")) if ($?);
# Add device to mdadm.conf local $lref = &read_file_lines($config{'mdadm'}); local ($i, $done_device); for($i=0; $i<@$lref; $i++) { if ($lref->[$i] =~ /^DEVICE\s+/ && !$done_device) { $lref->[$i] .= " $_[1]"; $done_device++; } elsif ($lref->[$i] =~ /^ARRAY\s+(\S+)/ && $1 eq $_[0]->{'value'}) { $lref->[$i] =~ s/(\s)devices=(\S+)/${1}devices=${2},$_[1]/; } } &flush_file_lines(); &update_initramfs(); } }
# grow(&raid, totaldisks) # Grows a RAID set to contain totaldisks active partitions sub grow { if ($raid_mode eq "mdadm") { # Call mdadm command to add $cmd="mdadm --grow $_[0]->{'value'} -n $_[1] 2>&1"; local $out = &backquote_logged( $cmd); &error(&text('emdadmgrow', "<tt>'$cmd' -> $out</tt>")) if ($?); } }
# convert_raid(&raid, oldcount, newcount, level) # Converts a RAID set to a defferent level RAID set sub convert_raid { if ($raid_mode eq "mdadm") { if ($_[2]) { # Call mdadm command to convert $cmd="mdadm --grow $_[0]->{'value'} --level $_[3]"; $grow_by = $_[2] - $_[1]; if ($grow_by == 1) { $raid_device_short = $_[0]->{'value'}; $raid_device_short =~ s/\/dev\///; $date = `date \+\%Y\%m\%d-\%H\%M`; chomp($date); $cmd .= " --backup-file /tmp/convert-$raid_device_short-$date"; } $cmd .= " -n $_[2] 2>&1"; local $out = &backquote_logged( $cmd); &error(&text('emdadmgrow', "<tt>'$cmd' -> $out</tt>")) if ($?); } else { $newcount = $_[1] - 1; $cmd="mdadm --grow $_[0]->{'value'} --level $_[3] -n $newcount"; $raid_device_short = $_[0]->{'value'}; $raid_device_short =~ s/\/dev\///; $date = `date \+\%Y\%m\%d-\%H\%M`; chomp($date); $cmd .= " --backup-file /tmp/convert-$raid_device_short-$date"; local $out = &backquote_logged( $cmd); &error(&text('emdadmgrow', "<tt>'$cmd' -> $out</tt>")) if ($?); } } }
# remove_partition(&raid, device) # Removes a device from some RAID set, both in the config file and for real sub remove_partition { if ($raid_mode eq "mdadm") { # Call mdadm commands to fail and remove local $out = &backquote_logged( "mdadm --manage $_[0]->{'value'} --fail $_[1] 2>&1"); &error(&text('emdadfail', "<tt>$out</tt>")) if ($?); local $out = &backquote_logged( "mdadm --manage $_[0]->{'value'} --remove $_[1] 2>&1"); &error(&text('emdadremove', "<tt>$out</tt>")) if ($?);
# Remove device from mdadm.conf local $lref = &read_file_lines($config{'mdadm'}); local ($i, $done_device); for($i=0; $i<@$lref; $i++) { if ($lref->[$i] =~ /^DEVICE\s+(.*)/) { local @olddevices = split(/\s+/, $1); local @newdevices = grep { $_ ne $_[1] } @olddevices; if (@newdevices) { $lref->[$i] = "DEVICE ".join(" ", @newdevices); } else { splice(@$lref, $i--, 1); } } elsif ($lref->[$i] =~ /^ARRAY\s+(\S+)/ && $1 eq $_[0]->{'value'}) { $lref->[$i] =~ s/((=)|,)\Q$_[1]\E/$2/; } } &flush_file_lines(); &update_initramfs(); } }
# remove_detached(&raid) # Removes detached device(s) from some RAID set sub remove_detached { if ($raid_mode eq "mdadm") { # Call mdadm commands to remove local $out = &backquote_logged( "mdadm --manage $_[0]->{'value'} --remove detached 2>&1"); &error(&text('emdadremove', "<tt>$out</tt>")) if ($?); } }
# directive_lines(&directive, indent) sub directive_lines { local @rv = ( "$_[1]$_[0]->{'name'}\t$_[0]->{'value'}" ); foreach $m (@{$_[0]->{'members'}}) { push(@rv, &directive_lines($m, $_[1]."\t")); } return @rv; }
# find(name, &array) sub find { local($c, @rv); foreach $c (@{$_[1]}) { if ($c->{'name'} eq $_[0]) { push(@rv, $c); } } return @rv ? wantarray ? @rv : $rv[0] : wantarray ? () : undef; }
# find_value(name, &array) sub find_value { local(@v); @v = &find($_[0], $_[1]); if (!@v) { return undef; } elsif (wantarray) { return map { $_->{'value'} } @v; } else { return $v[0]->{'value'}; } }
# device_status(device) # Returns an array of directory, type, mounted sub device_status { return &fdisk::device_status($_[0]); }
# find_free_partitions(&skip, showtype, showsize) # Returns a list of options, suitable for ui_select sub find_free_partitions { &foreign_require("fdisk"); &foreign_require("mount"); &foreign_require("lvm"); local %skip = map { $_, 1 } @{$_[0]}; local %used; local $c; local $conf = &get_raidtab(); foreach $c (@$conf) { foreach $d (&find_value('device', $c->{'members'})) { $used{$d}++; } } local @disks; local $d; foreach $d (&fdisk::list_disks_partitions()) { foreach $p (@{$d->{'parts'}}) { next if ($used{$p->{'device'}} || $p->{'extended'} || $skip{$p->{'device'}}); local @st = &device_status($p->{'device'}); next if (@st); $tag = $p->{'type'} ? &fdisk::tag_name($p->{'type'}) : undef; $p->{'blocks'} =~ s/\+$//; push(@disks, [ $p->{'device'}, $p->{'desc'}. ($tag && $_[1] ? " ($tag)" : ""). (!$_[2] ? "" : $d->{'cylsize'} ? " (".&nice_size($d->{'cylsize'}*($p->{'end'} - $p->{'start'} + 1)).")" : " ($p->{'blocks'} $text{'blocks'})") ]); } if (!@{$d->{'parts'}} && !$used{$d->{'device'}} && !$skip{$d->{'device'}}) { # Raw disk has no partitions - add it as an option push(@disks, [ $d->{'device'}, $d->{'desc'}. ($d->{'cylsize'} ? " (".&nice_size($d->{'cylsize'}*$d->{'cylinders'}).")" : "") ]); } } foreach $c (@$conf) { next if (!$c->{'active'} || $used{$c->{'value'}}); local @st = &device_status($c->{'value'}); next if (@st || $skip{$c->{'value'}}); push(@disks, [ $c->{'value'}, &text('create_rdev', $c->{'value'} =~ /md(\d+)$/ ? "$1" : $c->{'value'}) ]); } local $vg; foreach $vg (&lvm::list_volume_groups()) { local $lv; foreach $lv (&lvm::list_logical_volumes($vg->{'name'})) { next if ($lv->{'perm'} ne 'rw' || $used{$lv->{'device'}} || $skip->{$lv->{'device'}}); local @st = &device_status($lv->{'device'}); next if (@st); push(@disks, [ $lv->{'device'}, &text('create_lvm', $lv->{'vg'}, $lv->{'name'}) ]); } } return sort { $a->[0] cmp $b->[0] } @disks; }
# convert_to_hd(device) # Converts a device file like /dev/ide/host0/bus0/target1/lun0/part1 to # /dev/hdb1, if it doesn't actually exist. sub convert_to_hd { local ($dev) = @_; return $dev if (-r $dev); if ($dev =~ /ide\/host(\d+)\/bus(\d+)\/target(\d+)\/lun(\d+)\/part(\d+)/) { local ($host, $bus, $target, $lun, $part) = ($1, $2, $3, $4, $5); return "/dev/".&fdisk::hbt_to_device($host, $bus, $target).$part; } else { return $dev; } }
%mdadm_notification_opts = map { $_, 1 } ( 'MAILADDR', 'MAILFROM', 'PROGRAM' );
# get_mdadm_notifications() # Returns a hash from mdadm.conf notification-related settings to values sub get_mdadm_notifications { local $lref = &read_file_lines($config{'mdadm'}); local %rv; foreach my $l (@$lref) { $l =~ s/#.*$//; if ($l =~ /^(\S+)\s+(\S.*)/ && $mdadm_notification_opts{$1}) { $rv{$1} = $2; } } return \%rv; }
# save_mdadm_notifications(¬ifications) # Updates mdadm.conf with settings from the given hash. Those set to undef # are removed from the file. sub save_mdadm_notifications { local ($notif) = @_; local $lref = &read_file_lines($config{'mdadm'}); local %done; for(my $i=0; $i<@$lref; $i++) { my $l = $lref->[$i]; $l =~ s/#.*$//; local ($k, $v) = split(/\s+/, $l, 2); if (exists($notif->{$k})) { if (defined($notif->{$k})) { $lref->[$i] = "$k $notif->{$k}"; } else { splice(@$lref, $i--, 1); } $done{$k}++; } } foreach my $k (grep { !$done{$_} && defined($notif->{$_}) } keys %$notif) { push(@$lref, "$k $notif->{$k}"); } &flush_file_lines($config{'mdadm'}); }
# get_mdadm_action() # Returns the name of an init module action for mdadm monitoring, or undef if # not supported. sub get_mdadm_action { if (&foreign_installed("init")) { &foreign_require("init"); foreach my $a ("mdmonitor", "mdadm", "mdadmd") { local $st = &init::action_status($a); return $a if ($st); } } return undef; }
# get_mdadm_monitoring() # Returns 1 if mdadm monitoring is enabled, 0 if not sub get_mdadm_monitoring { local $act = &get_mdadm_action(); if ($act) { &foreign_require("init"); local $st = &init::action_status($act); return $st == 2; } return 0; }
# save_mdadm_monitoring(enabled) # Tries to enable or disable mdadm monitoring. Returns an error mesage # if something goes wrong, undef on success sub save_mdadm_monitoring { local ($enabled) = @_; local $act = &get_mdadm_action(); if ($act) { &foreign_require("init"); if ($enabled) { &init::enable_at_boot($act); &init::stop_action($act); sleep(2); local ($ok, $err) = &init::start_action($act); return $err if (!$ok); } else { &init::disable_at_boot($act); &init::stop_action($act); } } return undef; }
# update_initramfs() # If the update-initramfs command is installed, run it to update mdadm.conf # in the ramdisk sub update_initramfs { if (&has_command("update-initramfs")) { &system_logged("update-initramfs -u >/dev/null 2>&1 </dev/null"); } }
# get_mdadm_version() # Returns the mdadm version number sub get_mdadm_version { local $out = `mdadm --version 2>&1`; local $ver = $out =~ /\s+v([0-9\.]+)/ ? $1 : undef; return wantarray ? ( $ver, $out ) : $ver; }
1;
|