]> git.ipfire.org Git - people/stevee/ipfire-2.x.git/commitdiff
extrahd.cgi: Use new filesystem functions library
authorStefan Schantl <stefan.schantl@ipfire.org>
Wed, 1 May 2024 11:04:15 +0000 (13:04 +0200)
committerStefan Schantl <stefan.schantl@ipfire.org>
Wed, 1 May 2024 11:04:15 +0000 (13:04 +0200)
Signed-off-by: Stefan Schantl <stefan.schantl@ipfire.org>
html/cgi-bin/extrahd.cgi

index afe79479bd1ed0f0e277dabe4f7501642a746396..66d498118cdbcf23d666f9f143df71da4bd393fe 100644 (file)
@@ -27,6 +27,7 @@ use strict;
 require '/var/ipfire/general-functions.pl';
 require "${General::swroot}/lang.pl";
 require "${General::swroot}/header.pl";
+require "${General::swroot}/filesystem-functions.pl";
 
 my %extrahdsettings = ();
 my $errormessage = "";
@@ -34,9 +35,6 @@ my $errormessage = "";
 # Hash to store the configured drives.
 my %configured_drives;
 
-# SYSFS directory which contains all block device data.
-my $sysfs_block_dir = "/sys/class/block";
-
 # Array which contains the valid mount directories.
 # Only mounting to subdirectories inside them is allowed.
 my @valid_mount_dirs = (
@@ -45,26 +43,11 @@ my @valid_mount_dirs = (
        "/mnt",
 );
 
-# Grab all available block devices.
-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();
-
-# Omit the file system types of the mounted devices.
-my %filesystems = &get_mountedfs();
-
-# Gather all used swap devices.
-my @swaps = &get_swaps();
+# Gather volumes details.
+my %volumes = &Filesystem::volumes_status(
+       "devices" => "all",
+       "uuids" => "True"
+);
 
 # The config file which contains the configured devices.
 my $devicefile = "/var/ipfire/extrahd/devices";
@@ -197,8 +180,13 @@ if ($errormessage) {
 
 &Header::openbox('100%', 'center', $Lang::tr{'extrahd detected drives'});
 
-       # Re-read mountpoints.
-       %mountpoints = &get_mountpoints();
+       # Re-read mountpoints if an action has been performed.
+       if ($extrahdsettings{'ACTION'}) {
+               %volumes = &Filesystem::volumes_status(
+                       "devices" => "all",
+                       "uuids" => "True"
+               );
+       }
 
        # Read-in the device config file.
        open( FILE, "< $devicefile" ) or die "Unable to read $devicefile";
@@ -219,18 +207,24 @@ if ($errormessage) {
                <table border='0' width='600' cellspacing="0">
 END
 ;
-       foreach my $device (sort @devices) {
+       # Get all known block devices.
+       my @block_devices = &Filesystem::get_block_devices();
+
+       # Loop through the array of known block devices.
+       foreach my $block_device (@block_devices) {
+               my $device = "/dev/" . $block_device;
+
                # Grab the device details.
-               my $vendor = &get_device_vendor($device);
-               my $model = &get_device_model($device);
-               my $bsize = &get_device_size($device);
+               my $vendor = $volumes{$device}{"vendor"};
+               my $model = $volumes{$device}{"model"};
+               my $bsize = $volumes{$device}{"size"};
 
                # Convert size into human-readable format.
                my $size = &General::formatBytes($bsize);
 
                print <<END
                        <tr><td colspan="5">&nbsp;</td></tr>
-                       <tr><td align='left' colspan="2"><b>/dev/$device</b></td>
+                       <tr><td align='left' colspan="2"><b>$device</b></td>
                        <td align='center' colspan="2">$vendor $model</td>
 
                        <td align='center'>$Lang::tr{'size'} $size</td>
@@ -240,7 +234,7 @@ END
 ;
 
                # Grab the known partitions of the current block device.
-               my @partitions = &get_device_partitions($device);
+               my @partitions = @{$volumes{$device}{'partitions'}} if ($volumes{$device}{'partitions'});
 
                # Check if the block device has any partitions for display.
                if (@partitions) {
@@ -252,7 +246,7 @@ END
                }
 
                # Also print rows for devices with an UUID.
-               &print_row($device) if($uuids{$device});
+               &print_row($device) if($volumes{$device}{'uuid'});
        }
 
         print <<END
@@ -274,29 +268,27 @@ END
 #
 sub print_row ($) {
        my ($partition) = @_;
+       my $partition_string = $partition;
 
        my $disabled;
 
        # Omit the partition size.
-       my $bsize = &get_device_size($partition);
+       my $bsize = $volumes{$partition}{"size"};
 
        # Convert into human-readable format.
        my $size = &General::formatBytes($bsize);
 
        # Try to omit the used filesystem.
-       my $fs = $filesystems{$partition};
+       my $fs = $volumes{$partition}{"filesystem"};
 
        # Get the mountpoint.
-       my $mountpoint = $mountpoints{$partition};
+       my $mountpoint = $volumes{$partition}{"mpoint"};
 
-       # Generate partition string.
-       my $partition_string = "/dev/$partition";
+       # Try to omit the device mapper volume name and group.
+       my $device_mapper = $volumes{$partition}{'lvm_group'};
 
-       # 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}";
-       }
+       # Alter the partition string if the partion is managed by device mapper.
+       $partition_string = $device_mapper if ($device_mapper);
 
        # Check if the device is part of a group.
        my $grouped_device = &is_grouped_member($partition);
@@ -304,13 +296,13 @@ sub print_row ($) {
        # If no mountpoint could be determined try to grab from
        # configured drives.
        unless($mountpoint) {
-               my $uuid = $uuids{$partition};
+               my $uuid = $volumes{$partition}{"uuid"};
 
                # Build uuid string.
                $uuid = "UUID=" . $uuid;
 
-               # Try to obtain a possible moutpoint from configured drives.
-               $mountpoint = $configured_drives{$uuid} if ($configured_drives{$uuid});
+               # Try to obtain a possible moutpoint from the configured drives.
+               $mountpoint = $configured_drives{$uuid} if ($uuid);
        }
 
        # Check if the mountpoint is used as root or boot device.
@@ -318,27 +310,26 @@ sub print_row ($) {
                $disabled = "disabled";
 
        # Check if it is mounted.
-       } elsif(&is_mounted($mountpoint)) {
+       } elsif($mountpoint) {
                $disabled = "disabled";
 
        # Check if the device is used as swap.
-       } elsif (&is_swap($partition)) {
+       } elsif ($fs eq "swap") {
                $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}));
+               $mountpoint = $grouped_device if ($grouped_device);
+               $mountpoint = $device_mapper if ($device_mapper);
        }
 
        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";
+       if ($volumes{$partition}{"uuid"}) {
+               print "<tr><td align='left' colspan=5><strong>UUID=$volumes{$partition}{'uuid'}</strong></td></tr>\n";
        }
 
        print <<END
@@ -350,7 +341,7 @@ sub print_row ($) {
                <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}' />
+                       <input type='hidden' name='UUID' value='$volumes{$partition}{"uuid"}' />
 END
 ;
                # Check if the mountpoint refers to a known configured drive.
@@ -376,419 +367,22 @@ END
                }
 
        print <<END
-       </form></td></tr>
+       </td></tr></form>
 END
 ;
 }
 
-#
-## Function which return an array with all available block devices.
-#
-sub get_block_devices () {
-       my @devices;
-
-       # Open directory from kernel sysfs.
-       opendir(DEVICES, "/sys/block");
-
-       # Loop through the directory.
-       while(readdir(DEVICES)) {
-               # Skip . and ..
-               next if($_ =~ /^\.$/);
-               next if($_ =~ /^\..$/);
-
-               # Skip any loopback and ram devices.
-               next if($_ =~ "^loop");
-               next if($_ =~ "^ram");
-
-               # Add the device to the array of found devices.
-               push(@devices, $_);
-       }
-
-       # Close directory handle.
-       closedir(DEVICES);
-
-       # Return the devices array.
-       return @devices;
-}
-
-#
-## Function which return all partitions of a given block device.
-#
-sub get_device_partitions ($) {
-       my ($device) = @_;
-
-       # Array to store the known partitions for the given
-       # device.
-       my @partitions;
-
-       # Assign device directory.
-       my $device_dir = "$sysfs_block_dir/$device";
-
-       # Abort and return nothing if the device dir does not exist.
-       return unless(-d "$device_dir");
-
-       opendir(DEVICE, "$sysfs_block_dir/$device");
-       while(readdir(DEVICE)) {
-               next unless($_ =~ "^$device");
-
-               push(@partitions, $_);
-       }
-
-       closedir(DEVICE);
-
-       @partitions = sort(@partitions);
-
-       return @partitions;
-}
-
-#
-## Returns the vendor of a given block device.
-#
-sub get_device_vendor ($) {
-       my ($device) = @_;
-
-       # Assign device directory.
-       my $device_dir = "$sysfs_block_dir/$device";
-
-       # Abort and return nothing if the device dir does not exist
-       # or no vendor file exists.
-       return unless(-d "$device_dir");
-       return unless(-f "$device_dir/device/vendor");
-
-       # Open and read-in the device vendor.
-       open(VENDOR, "$device_dir/device/vendor");
-       my $vendor = <VENDOR>;
-       close(VENDOR);
-
-       # Abort and return nothing if no vendor could be read.
-       return unless($vendor);
-
-       # Remove any newlines from the vendor string.
-       chomp($vendor);
-
-       # Return the omited vendor.
-       return $vendor;
-}
-
-#
-## Returns the model name (string) of a given block device.
-#
-sub get_device_model ($) {
-       my ($device) = @_;
-
-       # Assign device directory.
-       my $device_dir = "$sysfs_block_dir/$device";
-
-       # Abort and return nothing if the device dir does not exist
-       # or no model file exists.
-       return unless(-d "$device_dir");
-       return unless(-f "$device_dir/device/model");
-
-       # Open and read-in the device model.
-       open(MODEL, "$device_dir/device/model");
-       my $model = <MODEL>;
-       close(MODEL);
-
-       # Abort and return nothing if no model could be read.
-       return unless($model);
-
-       # Remove any newlines from the model string.
-       chomp($model);
-
-       # Return the model string.
-       return $model;
-}
-
-#
-## Returns the size of a given device in bytes.
-#
-sub get_device_size ($) {
-       my ($device) = @_;
-
-       # Assign device directory.
-       my $device_dir = "$sysfs_block_dir/$device";
-
-       # Abort and return nothing if the device dir does not exist
-       # or no size file exists.
-       return unless(-d "$device_dir");
-       return unless(-f "$device_dir/size");
-
-       # Open and read-in the device size.
-       open(SIZE, "$device_dir/size");
-       my $size = <SIZE>;
-       close(SIZE);
-
-       # Abort and return nothing if the size could not be read.
-       return unless($size);
-
-       # Remove any newlines for the size string.
-       chomp($size);
-
-       # The omited size only contains the amount of blocks from the
-       # given device. To convert this into bytes we have to multiply this
-       # value with 512 bytes for each block. This is a static value used by
-       # the linux kernel.
-       $size = $size * 512;
-
-       # Return the size in bytes.
-       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"
-#
-sub get_mountpoints () {
-       my %mounts;
-
-       # Open and read-in the current mounts from the
-       # kernel file system.
-       open(MOUNT, "/proc/mounts");
-
-       # Loop through the known mounts.
-       while(<MOUNT>) {
-               # Skip mounts which does not belong to a device.
-               next unless ($_ =~ "^/dev");
-
-               # Cut the line into pieces and assign nice variables.
-               my ($dev, $mpoint, $fs, $options, $a, $b) = split(/ /, $_);
-
-               # Split the device name.
-               my @tmp = split("/", $dev);
-
-               # Assign the plain device name to a new variable.
-               # It is the last element of the array.
-               my $device = $tmp[-1];
-
-               # Add the mountpoint to the hash of mountpoints.
-               $mounts{"$device"} = $mpoint;
-       }
-
-       # Close file handle.
-       close(MOUNT);
-
-       # Return the hash of known mountpoints.
-       return %mounts;
-}
-
-sub get_swaps () {
-       my @swaps;
-
-       # Open and read the swaps file.
-       open(SWAP, "/proc/swaps");
-
-       # Loop though the file content.
-       while(<SWAP>) {
-               # Skip lines which does not belong to a device.
-               next unless ($_ =~ "^/dev");
-
-               # Split the line and assign nice variables.
-               my ($dev, $type, $size, $used, $prio) = split(/ /, $_);
-
-               # Cut the device line into pieces.
-               my @tmp = split("/", $dev);
-
-               my $device = @tmp[-1];
-
-               # Add the found swap to the array of swaps.
-               push(@swaps, $device);
-       }
-
-       # Close file handle.
-       close(SWAP);
-
-       # Sort the array.
-       @swaps = sort(@swaps);
-
-       # Return the array.
-       return @swaps;
-}
-
-#
-## Function with returns the mounted devices and the used filesystems as a hash.
-## Example: "sda1" -> "ext4"
-#
-sub get_mountedfs () {
-       my %mountedfs;
-
-       # Open and read the current mounts from the kernel
-       # file system.
-       open(MOUNT, "/proc/mounts");
-
-       # Loop through the known mounts.
-       while(<MOUNT>) {
-               # Skip mounts which does not belong to a device.
-               next unless ($_ =~ "^/dev");
-
-               # Split line and assign nice variables.
-               my ($dev, $mpoint, $fs, $options, $a, $b) = split(/ /, $_);
-
-               # Cut the device line into pieces.
-               my @tmp = split("/", $dev);
-
-               # Assign the plain device name to a variable
-               # It is the last element of the temporary array.
-               my $device = $tmp[-1];
-
-               # Convert the filesystem into lower case format.
-               $fs = lc($fs);
-
-               # Add the mounted file system.
-               $mountedfs{$device} = $fs;
-       }
-
-       # Close file handle.
-       close(MOUNT);
-
-       # Return the hash with the mounted filesystems.
-       return %mountedfs;
-}
-
-#
-## Function which returns all known UUID's as a hash.
-## Example: "sda1" -> "1234-5678-abcd"
-#
-sub get_uuids () {
-       my %uuids;
-
-       # Directory where the uuid mappings can be found.
-       my $uuid_dir = "/dev/disk/by-uuid";
-
-       # Open uuid directory and read-in the current known uuids.
-       opendir(UUIDS, "$uuid_dir");
-
-       # Loop through the uuids.
-       foreach my $uuid (readdir(UUIDS)) {
-               # Skip . and ..
-               next if($uuid eq "." or $uuid eq "..");
-
-               # Skip everything which is not a symbolic link.
-               next unless(-l "$uuid_dir/$uuid");
-
-               # Resolve the target of the symbolic link.
-               my $target = readlink("$uuid_dir/$uuid");
-
-               # Split the link target into pieces.
-               my @tmp = split("/", $target);
-
-               # Assign the last element of the array to the dev variable.
-               my $dev = "$tmp[-1]";
-
-               # Add the device and uuid to the hash of uuids.
-               $uuids{$dev} = $uuid;
-       }
-
-       # Close directory handle.
-       closedir(UUIDS);
-
-       # Return the hash of uuids.
-       return %uuids;
-}
-
-#
-## Returns the device name of a given uuid.
-#
-sub device_by_uuid ($) {
-       my ($uuid) = @_;
-
-       # Reverse the main uuids hash.
-       my %uuids = reverse %uuids;
-
-       # Lookup and return the device name.
-       return $uuids{$uuid};
-}
-
 #
 ## Returns "True" in case a given path is a known mountpoint.
 #
 sub is_mounted ($) {
        my ($mpoint) = @_;
 
-       my %mountpoints = reverse %mountpoints;
-
-       # Return "True" if the requested mountpoint is known and
-       # therefore mounted.
-       return 1 if($mountpoints{$mpoint});
+       foreach my $device (keys %volumes) {
+               # Return "True" if the requested mountpoint is known and
+               # therefore mounted.
+               return 1 if($volumes{$device}{"mpoint"} eq $mpoint);
+       }
 }
 
 #
@@ -822,7 +416,7 @@ sub is_valid_dir ($) {
 sub is_swap ($) {
        my ($device) = @_;
 
-       return 1 if(grep /$device/, @swaps);
+       return 1 if($volumes{$device}{"filesystem"} eq "swap");
 }
 
 #
@@ -844,14 +438,16 @@ sub is_grouped_member ($) {
        my ($device) = @_;
 
        # Loop through the hash of found grouped devices.
-       foreach my $grouped_device(keys %grouped_devices) {
+       foreach my $dev(keys %volumes) {
+               next unless ($volumes{$dev}{"mdraid_members"});
+
                # The found members are stored as arrays.
-               my @members = @{ $grouped_devices{$grouped_device} };
+               my @members = @{ $volumes{$dev}{"mdraid_members"} };
 
                # 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);
+                       return $dev if ($member eq $device);
                }
        }
 }