This commit adds support for using LVM and mdadm based RAID devices
for the CGI page.
In case one or more drives/partitions are used by such a "grouped"
volume they still will displayed on the page, but can not be
configured/used. Instead the "master" volume of which the
drive/partition is part of is shown in the "mountpoint" input box.
Signed-off-by: Stefan Schantl <stefan.schantl(a)ipfire.org>
---
html/cgi-bin/extrahd.cgi | 303 +++++++++++++++++++++++++++++----------
1 file changed, 225 insertions(+), 78 deletions(-)
diff --git a/html/cgi-bin/extrahd.cgi b/html/cgi-bin/extrahd.cgi
index c3a14c9e4..afe79479b 100644
--- a/html/cgi-bin/extrahd.cgi
+++ b/html/cgi-bin/extrahd.cgi
@@ -51,6 +51,12 @@ my @devices = &get_block_devices();
# Grab all known UUID's.
my %uuids = &get_uuids();
+# Detect device mapper devices.
+my %device_mapper = &get_device_mapper();
+
+# Grab members of group devices (RAID, LVM)
+my %grouped_devices = &collect_grouped_devices();
+
# Grab all mountpoints.
my %mountpoints = &get_mountpoints();
@@ -236,102 +242,144 @@ END
# Grab the known partitions of the current block device.
my @partitions = &get_device_partitions($device);
- foreach my $partition (@partitions) {
- my $disabled;
+ # Check if the block device has any partitions for display.
+ if (@partitions) {
+ # Loop through the partitions.
+ foreach my $partition (@partitions) {
+ # Call function to display the row in the WUI.
+ &print_row($partition);
+ }
+ }
+
+ # Also print rows for devices with an UUID.
+ &print_row($device) if($uuids{$device});
+ }
- # Omit the partition size.
- my $bsize = &get_device_size($partition);
+ print <<END
+ <tr><td align="center" colspan="5"> </td></tr>
+ <tr><td align="center" colspan="5"> </td></tr>
+ <tr><td align="center" colspan="5">$Lang::tr{'extrahd install or load driver'}</td></tr>
+ </table>
+END
+;
- # Convert into human-readable format.
- my $size = &General::formatBytes($bsize);
+&Header::closebox();
- # Try to omit the used filesystem.
- my $fs = $filesystems{$partition};
+&Header::closebigbox();
+&Header::closepage();
- # Get the mountpoint.
- my $mountpoint = $mountpoints{$partition};
- # If no mountpoint could be determined try to grab from
- # configured drives.
- unless($mountpoint) {
- my $uuid = $uuids{$partition};
+#
+# Function to print a table row with device data on the WUI.
+#
+sub print_row ($) {
+ my ($partition) = @_;
- # Build uuid string.
- $uuid = "UUID=" . $uuid;
+ my $disabled;
- # Try to obtain a possible moutpoint from configured drives.
- $mountpoint = $configured_drives{$uuid} if ($configured_drives{$uuid});
- }
+ # Omit the partition size.
+ my $bsize = &get_device_size($partition);
- # Check if the mountpoint is used as root or boot device.
- if ($mountpoint eq "/" or $mountpoint =~ "^/boot") {
- $disabled = "disabled";
+ # Convert into human-readable format.
+ my $size = &General::formatBytes($bsize);
- # Check if it is mounted.
- } elsif(&is_mounted($mountpoint)) {
- $disabled = "disabled";
+ # Try to omit the used filesystem.
+ my $fs = $filesystems{$partition};
- # Check if the device is used as swap.
- } elsif (&is_swap($partition)) {
- $disabled = "disabled";
- $mountpoint = "swap";
- $fs = "swap";
- }
+ # Get the mountpoint.
+ my $mountpoint = $mountpoints{$partition};
- print <<END
-
- <form method='post' action='$ENV{'SCRIPT_NAME'}'>
- <tr><td align="left" colspan=5><strong>UUID=$uuids{$partition}</strong></td></tr>
- <tr>
- <td align="list">/dev/$partition</td>
- <td align="center">$Lang::tr{'size'} $size</td>
- <td align="center">$fs</td>
- <td align="center"><input type='text' name='PATH' value='$mountpoint' $disabled></td>
- <td align="center">
- <input type='hidden' name='DEVICE' value='/dev/$partition' />
- <input type='hidden' name='UUID' value='$uuids{$partition}' />
-END
-;
- # Check if the mountpoint refers to a known configured drive.
- if(&is_configured($mountpoint)) {
- print "<input type='hidden' name='ACTION' value='$Lang::tr{'delete'}'>\n";
- print "<input type='hidden' name='PATH' value='$mountpoint'>\n";
-
- # Check if the device is mounted properly.
- if(&is_mounted($mountpoint)) {
- print "<img src='/images/updbooster/updxl-led-green.gif' alt='$Lang::tr{'extrahd mounted'}' title='$Lang::tr{'extrahd mounted'}'> \n";
- } else {
- print "<img src='/images/updbooster/updxl-led-red.gif' alt='$Lang::tr{'extrahd not mounted'}' title='$Lang::tr{'extrahd not mounted'}'> \n";
- }
-
- print "<input type='image' alt='$Lang::tr{'delete'}' title='$Lang::tr{'delete'}' src='/images/delete.gif'>\n";
- } else {
- unless($disabled) {
- print "<input type='hidden' name='ACTION' value='$Lang::tr{'add'}'>\n";
- print "<input type='hidden' name='FS' value='auto'>\n";
- print "<img src='/images/updbooster/updxl-led-gray.gif' alt='$Lang::tr{'extrahd not configured'}' title='$Lang::tr{'extrahd not configured'}'> \n";
- print "<input type='image' alt='$Lang::tr{'add'}' title='$Lang::tr{'add'}' src='/images/add.gif'>\n";
- }
- }
-
- print <<END
- </form></td></tr>
-END
-; }
+ # Generate partition string.
+ my $partition_string = "/dev/$partition";
+ # Check if the given partition is managed by device mapper.
+ if (exists($device_mapper{$partition})) {
+ # Alter the partition string to used one by the device mapper.
+ $partition_string = "$device_mapper{$partition}";
+ }
+
+ # Check if the device is part of a group.
+ my $grouped_device = &is_grouped_member($partition);
+
+ # If no mountpoint could be determined try to grab from
+ # configured drives.
+ unless($mountpoint) {
+ my $uuid = $uuids{$partition};
+
+ # Build uuid string.
+ $uuid = "UUID=" . $uuid;
+
+ # Try to obtain a possible moutpoint from configured drives.
+ $mountpoint = $configured_drives{$uuid} if ($configured_drives{$uuid});
+ }
+
+ # Check if the mountpoint is used as root or boot device.
+ if ($mountpoint eq "/" or $mountpoint =~ "^/boot") {
+ $disabled = "disabled";
+
+ # Check if it is mounted.
+ } elsif(&is_mounted($mountpoint)) {
+ $disabled = "disabled";
+
+ # Check if the device is used as swap.
+ } elsif (&is_swap($partition)) {
+ $disabled = "disabled";
+ $mountpoint = "swap";
+ $fs = "swap";
+
+ # Check if the device is part of a group.
+ } elsif ($grouped_device) {
+ $disabled = "disabled";
+ $mountpoint = "/dev/$grouped_device";
+ $mountpoint = $device_mapper{$grouped_device} if (exists($device_mapper{$grouped_device}));
+ }
+
+ print "<form method='post' action='$ENV{'SCRIPT_NAME'}'>\n";
+
+ # Only display UUID details if an UUID could be obtained.
+ if ( $uuids{$partition} ) {
+ print "<tr><td align='left' colspan=5><strong>UUID=$uuids{$partition}</strong></td></tr>\n";
}
print <<END
- <tr><td align="center" colspan="5"> </td></tr>
- <tr><td align="center" colspan="5"> </td></tr>
- <tr><td align="center" colspan="5">$Lang::tr{'extrahd install or load driver'}</td></tr>
- </table>
+
+ <tr>
+ <td align="list">$partition_string</td>
+ <td align="center">$Lang::tr{'size'} $size</td>
+ <td align="center">$fs</td>
+ <td align="center"><input type='text' name='PATH' value='$mountpoint' $disabled></td>
+ <td align="center">
+ <input type='hidden' name='DEVICE' value='$partition_string' />
+ <input type='hidden' name='UUID' value='$uuids{$partition}' />
END
;
-&Header::closebox();
+ # Check if the mountpoint refers to a known configured drive.
+ if(&is_configured($mountpoint)) {
+ print "<input type='hidden' name='ACTION' value='$Lang::tr{'delete'}'>\n";
+ print "<input type='hidden' name='PATH' value='$mountpoint'>\n";
+
+ # Check if the device is mounted properly.
+ if(&is_mounted($mountpoint)) {
+ print "<img src='/images/updbooster/updxl-led-green.gif' alt='$Lang::tr{'extrahd mounted'}' title='$Lang::tr{'extrahd mounted'}'> \n";
+ } else {
+ print "<img src='/images/updbooster/updxl-led-red.gif' alt='$Lang::tr{'extrahd not mounted'}' title='$Lang::tr{'extrahd not mounted'}'> \n";
+ }
-&Header::closebigbox();
-&Header::closepage();
+ print "<input type='image' alt='$Lang::tr{'delete'}' title='$Lang::tr{'delete'}' src='/images/delete.gif'>\n";
+ } else {
+ unless($disabled) {
+ print "<input type='hidden' name='ACTION' value='$Lang::tr{'add'}'>\n";
+ print "<input type='hidden' name='FS' value='auto'>\n";
+ print "<img src='/images/updbooster/updxl-led-gray.gif' alt='$Lang::tr{'extrahd not configured'}' title='$Lang::tr{'extrahd not configured'}'> \n";
+ print "<input type='image' alt='$Lang::tr{'add'}' title='$Lang::tr{'add'}' src='/images/add.gif'>\n";
+ }
+ }
+
+ print <<END
+ </form></td></tr>
+END
+;
+}
#
## Function which return an array with all available block devices.
@@ -486,6 +534,86 @@ sub get_device_size ($) {
return $size;
}
+#
+## Function which tries to detect if a block device is a device mapper device and returns the alias a
+## a hash. Example: "dm-0" -> "/dev/mapper/GROUP-DEVICE"
+#
+sub get_device_mapper () {
+ my %mapper_devices = ();
+
+ # Loop through all known block devices.
+ foreach my $block_device (@devices) {
+ # Generate device directory.
+ my $device_dir = "$sysfs_block_dir/$block_device";
+
+ # Skip the device if it is not managed by device mapper
+ # In this case the "bd" is not present.
+ next unless (-e "$device_dir/dm");
+
+ # Grab the group and volume name.
+ open(NAME, "$device_dir/dm/name") if (-e "$device_dir/dm/name");
+ my $name = <NAME>;
+ close(NAME);
+
+ # Skip device if no name could be determined.
+ next unless($name);
+
+ # Remove any newlines from the name string.
+ chomp($name);
+
+ # Generate path to the dev node in devfs.
+ my $dev_path = "/dev/mapper/$name";
+
+ # Store the device and the omited mapper name in the hash.
+ $mapper_devices{$block_device} = $dev_path;
+ }
+
+ # Return the hash of omited device mapper devices.
+ return %mapper_devices;
+}
+
+#
+## Function which will collect grouped devices and their members as array in a hash and returns them.
+## For example: "sda1" -> "dm-0" in case /dev/sda1 is assigned to a device mapper group.
+#
+sub collect_grouped_devices () {
+ my %grouped_devices = ();
+
+ # Loop through the array of known block devices.
+ foreach my $device (@devices) {
+ # Generate device directory.
+ my $device_dir = "$sysfs_block_dir/$device";
+
+ # Skip device if it has no members.
+ # In this case the "slaves" directory does not exist.
+ next unless (-e "$device_dir/slaves");
+
+ # Tempoarary array to store the members of a group.
+ my @members = ();
+
+ # Grab all members.
+ opendir(MEMBERS, "$device_dir/slaves");
+ while(readdir(MEMBERS)) {
+ next if($_ eq ".");
+ next if($_ eq "..");
+
+ # Add the found member to the array of members.
+ push(@members, $_);
+ }
+
+ closedir(MEMBERS);
+
+ # Skip the device if no members could be grabbed.
+ next unless (@members);
+
+ # Add the array of found members as value to the hash of grouped devices.
+ $grouped_devices{$device} = [ @members ];
+ }
+
+ # Return the hash of found grouped devices and their members.
+ return %grouped_devices;
+}
+
#
## Function which returns all currently mounted devices as a hash.
## example: "sda1" -> "/boot"
@@ -708,3 +836,22 @@ sub is_configured ($) {
return 1 if($configured_drives{$uuid} eq "$path");
}
}
+
+#
+## Retruns the device name of the grouped device,if a given device is a group member.
+#
+sub is_grouped_member ($) {
+ my ($device) = @_;
+
+ # Loop through the hash of found grouped devices.
+ foreach my $grouped_device(keys %grouped_devices) {
+ # The found members are stored as arrays.
+ my @members = @{ $grouped_devices{$grouped_device} };
+
+ # Loop through array of members and check if the given
+ # device is part of it.
+ foreach my $member (@members) {
+ return $grouped_device if ($member eq $device);
+ }
+ }
+}
--
2.39.2