From 2c1e60fc11ce7516bea885f3be1acf0896a68a67 Mon Sep 17 00:00:00 2001 From: Stefan Schantl Date: Wed, 1 May 2024 13:04:15 +0200 Subject: [PATCH] extrahd.cgi: Use new filesystem functions library Signed-off-by: Stefan Schantl --- html/cgi-bin/extrahd.cgi | 516 +++++---------------------------------- 1 file changed, 56 insertions(+), 460 deletions(-) diff --git a/html/cgi-bin/extrahd.cgi b/html/cgi-bin/extrahd.cgi index afe79479b..66d498118 100644 --- a/html/cgi-bin/extrahd.cgi +++ b/html/cgi-bin/extrahd.cgi @@ -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) { 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 < - + @@ -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 <\n"; # Only display UUID details if an UUID could be obtained. - if ( $uuids{$partition} ) { - print "\n"; + if ($volumes{$partition}{"uuid"}) { + print "\n"; } print < + 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 = ; - 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 = ; - 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 = ; - 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 = ; - 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() { - # 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() { - # 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() { - # 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); } } } -- 2.39.5
 
/dev/$device
$device $vendor $model $Lang::tr{'size'} $size
UUID=$uuids{$partition}
UUID=$volumes{$partition}{'uuid'}
- + END ; # Check if the mountpoint refers to a known configured drive. @@ -376,419 +367,22 @@ END } print <