This functions are going to replace the former used scan/write to file/read from file approach by directly collecting the required informations from the kernel sysfs and devfs.
Signed-off-by: Stefan Schantl stefan.schantl@ipfire.org --- html/cgi-bin/extrahd.cgi | 360 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+)
diff --git a/html/cgi-bin/extrahd.cgi b/html/cgi-bin/extrahd.cgi index 36c0efc2e..44065a8a1 100644 --- a/html/cgi-bin/extrahd.cgi +++ b/html/cgi-bin/extrahd.cgi @@ -255,3 +255,363 @@ END
&Header::closebigbox(); &Header::closepage(); + +# +## 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 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}); +} + +# +## Returns "True" if a given mountpoint is a subdirectory of one +## of the directories specified by the valid_mount_dirs array abouve. +# +sub is_valid_dir ($) { + my ($mpoint) = @_; + + # Split the given mountpoint into pieces and store them + # in a temporay array. + my @tmp = split("/", $mpoint); + + # Exit and return nothing if the temporary array is empty. + return unless(@tmp); + + # Build the root path based on the given mount point. + my $root_path = "/" . @tmp[1]; + + # Check if the root path is valid. + return 1 if(grep /$root_path/, @valid_mount_dirs); +} + +# +# Returns "True" if a device is used as swap. +# +sub is_swap ($) { + my ($device) = @_; + + return 1 if(grep /$device/, @swaps); +}
This also gets rid of allmost all unsafe system calls.
Signed-off-by: Stefan Schantl stefan.schantl@ipfire.org --- html/cgi-bin/extrahd.cgi | 336 ++++++++++++++++++++++++--------------- 1 file changed, 208 insertions(+), 128 deletions(-)
diff --git a/html/cgi-bin/extrahd.cgi b/html/cgi-bin/extrahd.cgi index 44065a8a1..117890f08 100644 --- a/html/cgi-bin/extrahd.cgi +++ b/html/cgi-bin/extrahd.cgi @@ -29,33 +29,51 @@ require "${General::swroot}/lang.pl"; require "${General::swroot}/header.pl";
my %extrahdsettings = (); -my $message = ""; my $errormessage = ""; -my $size = ""; -my $ok = "true"; -my @tmp = (); -my @tmpline = (); -my $tmpentry = ""; -my @devices = (); -my @deviceline = (); -my $deviceentry = ""; -my @scans = (); -my @scanline = (); -my $scanentry = ""; -my @partitions = (); -my @partitionline = (); -my $partitionentry = ""; + +# 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 = ( + "/data", + "/media", + "/mnt", +); + +# Array which contains the supported file systems. +my @supported_filesystems = ( + "auto", + "ext3", + "ext4", + "xfs", + "vfat", + "ntfs-3g" +); + +# Grab all available block devices. +my @devices = &get_block_devices(); + +# Grab all known UUID's. +my %uuids = &get_uuids(); + +# 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(); + +# The config file which contains the configured devices. my $devicefile = "/var/ipfire/extrahd/devices"; -my $scanfile = "/var/ipfire/extrahd/scan"; -my $partitionsfile = "/var/ipfire/extrahd/partitions";
#workaround to suppress a warning when a variable is used only once my @dummy = ( ${Header::colourgreen}, ${Header::colourred} ); undef (@dummy);
-&General::system("/usr/local/bin/extrahdctrl", "scanhd", "ide"); -&General::system("/usr/local/bin/extrahdctrl", "scanhd", "partitions"); - &Header::showhttpheaders();
### Values that have to be initialized @@ -65,7 +83,6 @@ $extrahdsettings{'DEVICE'} = ''; $extrahdsettings{'ACTION'} = ''; $extrahdsettings{'UUID'} = '';
-&General::readhash("${General::swroot}/extrahd/settings", %extrahdsettings); &Header::getcgihash(%extrahdsettings);
&Header::openpage('ExtraHD', 1, ''); @@ -74,52 +91,88 @@ $extrahdsettings{'UUID'} = ''; ############################################################################################################################ ############################################################################################################################
-if ($extrahdsettings{'ACTION'} eq $Lang::tr{'add'}) -{ +# +## Add a new device. +# +if ($extrahdsettings{'ACTION'} eq $Lang::tr{'add'}) { + # Open device file for reading. open( FILE, "< $devicefile" ) or die "Unable to read $devicefile"; - @devices = <FILE>; + my @devices = <FILE>; close FILE; - foreach $deviceentry (sort @devices) - { - @deviceline = split( /;/, $deviceentry ); - if ( "$extrahdsettings{'PATH'}" eq "$deviceline[2]" ) { - $ok = "false"; + + # Loop through the entries line-by-line. + foreach my $entry (sort @devices) { + # Split the line into pieces and assign nice variables. + my ($uuid, $fs, $path) = split( /;/, $entry ); + + # Check if the path is allready used. + if ( "$extrahdsettings{'PATH'}" eq "$path" ) { $errormessage = "$Lang::tr{'extrahd you cant mount'} $extrahdsettings{'DEVICE'} $Lang::tr{'extrahd to'} $extrahdsettings{'PATH'}$Lang::tr{'extrahd because there is already a device mounted'}."; } - if ( "$extrahdsettings{'PATH'}" eq "/" ) { - $ok = "false"; - $errormessage = "$Lang::tr{'extrahd you cant mount'} $extrahdsettings{'DEVICE'} $Lang::tr{'extrahd to root'}."; + + # Check if the uuid is allready used. + if ("$extrahdsettings{'DEVICE'} eq $uuid") { + $errormessage = "$extrahdsettings{'DEVICE'} is allready mounted."; } }
- if ( "$ok" eq "true" ) { + # Check if a valid mount path has been choosen. + unless(&is_valid_dir("$extrahdsettings{'PATH'}")) { + $errormessage = "$Lang::tr{'extrahd you cant mount'} $extrahdsettings{'DEVICE'} $Lang::tr{'extrahd to root'}."; + } + + # Check if the given path allready is mounted somewhere. + if(&is_mounted("$extrahdsettings{'PATH'}")) { + $errormessage = "$Lang::tr{'extrahd you cant mount'} $extrahdsettings{'DEVICE'} $Lang::tr{'extrahd to'} $extrahdsettings{'PATH'}$Lang::tr{'extrahd because there is already a device mounted'}."; + } + + # Check if there was an error message. + unless($errormessage) { + # Re-open the device file for writing. open(FILE, ">> $devicefile" ) or die "Unable to write $devicefile"; - print FILE <<END -UUID=$extrahdsettings{'UUID'};$extrahdsettings{'FS'};$extrahdsettings{'PATH'}; -END -; - &General::system("/usr/local/bin/extrahdctrl", "mount", "$extrahdsettings{'PATH'}"); + + # Write the config line. + print FILE "UUID=$extrahdsettings{'UUID'};$extrahdsettings{'FS'};$extrahdsettings{'PATH'};\n"; + + # Close file handle. + close(FILE); + + # Call helper binary to mount the device. + &General::system("/usr/local/bin/extrahdctrl", "mount", "$extrahdsettings{'PATH'}"); } -} -elsif ($extrahdsettings{'ACTION'} eq $Lang::tr{'delete'}) -{ - if ( &General::system("/usr/local/bin/extrahdctrl", "umount", "$extrahdsettings{'PATH'}")) { - open( FILE, "< $devicefile" ) or die "Unable to read $devicefile"; - @tmp = <FILE>; - close FILE; - open( FILE, "> $devicefile" ) or die "Unable to write $devicefile"; - foreach $deviceentry (sort @tmp) - { - @tmpline = split( /;/, $deviceentry ); - if ( $tmpline[2] ne $extrahdsettings{'PATH'} ) - { - print FILE $deviceentry; - } + +# +# Remove an existing one. +# +} elsif ($extrahdsettings{'ACTION'} eq $Lang::tr{'delete'}) { + # Call helper binary to unmount the device. + &General::system("/usr/local/bin/extrahdctrl", "umount", "$extrahdsettings{'PATH'}"); + + # Open the device file for reading. + open(FILE, "< $devicefile" ) or die "Unable to read $devicefile"; + + # Read the file content into a temporary array. + my @tmp = <FILE>; + + # Close file handle. + close(FILE); + + # Re-open device file for writing. + open(FILE, "> $devicefile" ) or die "Unable to write $devicefile"; + + # Loop through the previous read file content. + foreach my $line (sort @tmp) { + # Split line content and assign nice variables. + my ($uuid, $fs, $path) = split( /;/, $line ); + + # Write the line in case it does not contain our element to delete. + if ($path ne $extrahdsettings{'PATH'}) { + print FILE "$line"; } - close FILE; - } else { - $errormessage = "$Lang::tr{'extrahd cant umount'} $extrahdsettings{'PATH'}$Lang::tr{'extrahd maybe the device is in use'}?"; } + + # Close file handle. + close(FILE); }
if ($errormessage) { @@ -132,34 +185,38 @@ if ($errormessage) { ############################################################################################################################ ############################################################################################################################
- open( FILE, "< $devicefile" ) or die "Unable to read $devicefile"; - @devices = <FILE>; - close FILE; print <<END <table border='0' width='600' cellspacing="0"> END ; - foreach $deviceentry (sort @devices) - { - @deviceline = split( /;/, $deviceentry ); - my $color="$Header::colourred"; + # Re-read mountpoints. + %mountpoints = &get_mountpoints();
- # Use safe system_output to get mountpoint details. - my @mountpoint = &General::system_output("/bin/mountpoint", "$deviceline[2]"); + # Read-in the device config file. + open( FILE, "< $devicefile" ) or die "Unable to read $devicefile"; + my @configfile = <FILE>; + close FILE; + + # Loop through the file content. + foreach my $entry (sort @configfile) { + my ($uuid, $fs, $path) = split( /;/, $entry ); + my $color="$Header::colourred";
- if ( ! grep(/not/, @mountpoint)) { + # Check if the device is currently mounted. + if (&is_mounted($path)) { $color=$Header::colourgreen; } + print <<END <tr><td colspan="4"> </td></tr> - <tr><td align='left'><font color=$color><b>$deviceline[0]</b></font></td> - <td align='left'>$deviceline[1]</td> - <td align='left'>$deviceline[2]</td> + <tr><td align='left'><font color=$color><b>$uuid</b></font></td> + <td align='left'>$fs</td> + <td align='left'>$path</td> <td align='center'> <form method='post' action='$ENV{'SCRIPT_NAME'}'> - <input type='hidden' name='DEVICE' value='$deviceline[0]' /> - <input type='hidden' name='FS' value='$deviceline[1]' /> - <input type='hidden' name='PATH' value='$deviceline[2]' /> + <input type='hidden' name='DEVICE' value='$uuid' /> + <input type='hidden' name='FS' value='$fs' /> + <input type='hidden' name='PATH' value='$path' /> <input type='hidden' name='ACTION' value='$Lang::tr{'delete'}' /> <input type='image' alt='$Lang::tr{'delete'}' title='$Lang::tr{'delete'}' src='/images/delete.gif' /> </form></td></tr> @@ -170,78 +227,101 @@ END </table> END ; + &Header::openbox('100%', 'center', $Lang::tr{'extrahd detected drives'}); print <<END <table border='0' width='600' cellspacing="0"> END ; - open( FILE, "< $scanfile" ) or die "Unable to read $scanfile"; - @scans = <FILE>; - close FILE; - open( FILE, "< $partitionsfile" ) or die "Unable to read $partitionsfile"; - @partitions = <FILE>; - close FILE; - foreach $scanentry (sort @scans) - { - @scanline = split( /;/, $scanentry ); - # remove wrong entries like usb controller name - if ($scanline[1] ne "\n") - { - print <<END - <tr><td colspan="5"> </td></tr> - <tr><td align='left' colspan="2"><b>/dev/$scanline[0]</b></td> - <td align='center' colspan="2">$scanline[1]</td> + foreach my $device (sort @devices) { + # Grab the device details. + my $vendor = &get_device_vendor($device); + my $model = &get_device_model($device); + my $bsize = &get_device_size($device); + + # Convert size into human-readable format. + my $size = &General::formatBytes($bsize); + + print <<END + <tr><td colspan="5"> </td></tr> + <tr><td align='left' colspan="2"><b>/dev/$device</b></td> + <td align='center' colspan="2">$vendor $model</td> + + <td align='center'>$Lang::tr{'size'} $size</td> + <td> </td></tr> + <tr><td colspan="5"> </td></tr> END ;
- } - foreach $partitionentry (sort @partitions) - { - @partitionline = split( /;/, $partitionentry ); - if ( "$partitionline[0]" eq "$scanline[0]" ) { - $size = int($partitionline[1] / 1024); - print <<END - <td align='center'>$Lang::tr{'size'} $size MB</td> - <td> </td></tr> - <tr><td colspan="5"> </td></tr> + # Grab the known partitions of the current block device. + my @partitions = &get_device_partitions($device); + + foreach my $partition (@partitions) { + my $disabled; + + # Omit the partition size. + my $bsize = &get_device_size($partition); + + # Convert into human-readable format. + my $size = &General::formatBytes($bsize); + + # Get the mountpoint. + my $mountpoint = $mountpoints{$partition}; + + if ($mountpoint eq "/" or $mountpoint =~ "^/boot") { + $disabled = "disabled"; + } elsif(&is_mounted($mountpoint)) { + $disabled = "disabled"; + } + + # Omit the used filesystem. + my $fs = $filesystems{$partition}; + + # Check if the device is used as swap. + if (&is_swap($partition)) { + $disabled = "disabled"; + $mountpoint = "swap"; + } + + 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"><select name="FS" $disabled> END ; - } - } + # Loop through the array of supported filesystems. + foreach my $filesystem (@supported_filesystems) { + my $selected;
- foreach $partitionentry (sort @partitions) - { - @partitionline = split( /;/, $partitionentry ); - if (( "$partitionline[0]" =~ /^$scanline[0]/ ) && !( "$partitionline[2]" eq "" )) { - $size = int($partitionline[1] / 1024); - print <<END - <form method='post' action='$ENV{'SCRIPT_NAME'}'> - <tr><td align="left" colspan=5><strong>UUID=$partitionline[2]</strong></td></tr> - <tr> - <td align="list">/dev/$partitionline[0]</td> - <td align="center">$Lang::tr{'size'} $size MB</td> - <td align="center"><select name="FS"> - <option value="auto">auto</option> - <option value="ext3">ext3</option> - <option value="ext4">ext4</option> - <option value="reiserfs">reiserfs</option> - <option value="vfat">fat</option> - <option value="ntfs-3g">ntfs (experimental)</option> - </select></td> - <td align="center"><input type='text' name='PATH' value=/mnt/harddisk /></td> + # Mark the used filesystem as selected. + if ($filesystem eq $fs) { + $selected = "selected"; + } + + print "<option value='$filesystem' $selected>$filesystem</option>\n"; + } + + print <<END + </select></td> + <td align="center"><input type='text' name='PATH' value=$mountpoint $disabled></td> <td align="center"> - <input type='hidden' name='DEVICE' value='$partitionline[0]' /> - <input type='hidden' name='UUID' value='$partitionline[2]' /> + <input type='hidden' name='DEVICE' value='/dev/$partition' /> + <input type='hidden' name='UUID' value='$uuids{$partition}' /> <input type='hidden' name='ACTION' value='$Lang::tr{'add'}' /> - <input type='image' alt='$Lang::tr{'add'}' title='$Lang::tr{'add'}' src='/images/add.gif' /> - </form></td></tr> END -; +; unless($disabled) { + print"<input type='image' alt='$Lang::tr{'add'}' title='$Lang::tr{'add'}' src='/images/add.gif' />\n"; + }
+ print <<END + </form></td></tr> END -; - } - } +; } + }
print <<END
Signed-off-by: Stefan Schantl stefan.schantl@ipfire.org --- html/cgi-bin/extrahd.cgi | 42 +++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 20 deletions(-)
diff --git a/html/cgi-bin/extrahd.cgi b/html/cgi-bin/extrahd.cgi index 117890f08..dde4e7356 100644 --- a/html/cgi-bin/extrahd.cgi +++ b/html/cgi-bin/extrahd.cgi @@ -146,33 +146,35 @@ if ($extrahdsettings{'ACTION'} eq $Lang::tr{'add'}) { # } elsif ($extrahdsettings{'ACTION'} eq $Lang::tr{'delete'}) { # Call helper binary to unmount the device. - &General::system("/usr/local/bin/extrahdctrl", "umount", "$extrahdsettings{'PATH'}"); + unless(&General::system("/usr/local/bin/extrahdctrl", "umount", "$extrahdsettings{'PATH'}")) { + # Open the device file for reading. + open(FILE, "< $devicefile" ) or die "Unable to read $devicefile";
- # Open the device file for reading. - open(FILE, "< $devicefile" ) or die "Unable to read $devicefile"; + # Read the file content into a temporary array. + my @tmp = <FILE>;
- # Read the file content into a temporary array. - my @tmp = <FILE>; - - # Close file handle. - close(FILE); + # Close file handle. + close(FILE);
- # Re-open device file for writing. - open(FILE, "> $devicefile" ) or die "Unable to write $devicefile"; + # Re-open device file for writing. + open(FILE, "> $devicefile" ) or die "Unable to write $devicefile";
- # Loop through the previous read file content. - foreach my $line (sort @tmp) { - # Split line content and assign nice variables. - my ($uuid, $fs, $path) = split( /;/, $line ); + # Loop through the previous read file content. + foreach my $line (sort @tmp) { + # Split line content and assign nice variables. + my ($uuid, $fs, $path) = split( /;/, $line );
- # Write the line in case it does not contain our element to delete. - if ($path ne $extrahdsettings{'PATH'}) { - print FILE "$line"; + # Write the line in case it does not contain our element to delete. + if ($path ne $extrahdsettings{'PATH'}) { + print FILE "$line"; + } } - }
- # Close file handle. - close(FILE); + # Close file handle. + close(FILE); + } else { + $errormessage = "$Lang::tr{'extrahd cant umount'} $extrahdsettings{'PATH'}$Lang::tr{'extrahd maybe the device is in use'}?"; + } }
if ($errormessage) {
Signed-off-by: Stefan Schantl stefan.schantl@ipfire.org --- html/cgi-bin/extrahd.cgi | 71 ++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 39 deletions(-)
diff --git a/html/cgi-bin/extrahd.cgi b/html/cgi-bin/extrahd.cgi index dde4e7356..fc8685830 100644 --- a/html/cgi-bin/extrahd.cgi +++ b/html/cgi-bin/extrahd.cgi @@ -31,6 +31,9 @@ require "${General::swroot}/header.pl"; my %extrahdsettings = (); 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";
@@ -187,50 +190,26 @@ if ($errormessage) { ############################################################################################################################ ############################################################################################################################
- print <<END - <table border='0' width='600' cellspacing="0"> -END -; +&Header::openbox('100%', 'center', $Lang::tr{'extrahd detected drives'}); + # Re-read mountpoints. %mountpoints = &get_mountpoints();
# Read-in the device config file. open( FILE, "< $devicefile" ) or die "Unable to read $devicefile"; - my @configfile = <FILE>; - close FILE;
# Loop through the file content. - foreach my $entry (sort @configfile) { - my ($uuid, $fs, $path) = split( /;/, $entry ); - my $color="$Header::colourred"; - - # Check if the device is currently mounted. - if (&is_mounted($path)) { - $color=$Header::colourgreen; - } + while (<FILE>) { + # Cut the line into pieces. + my ($uuid, $fs, $path) = split( /;/, $_ );
- print <<END - <tr><td colspan="4"> </td></tr> - <tr><td align='left'><font color=$color><b>$uuid</b></font></td> - <td align='left'>$fs</td> - <td align='left'>$path</td> - <td align='center'> - <form method='post' action='$ENV{'SCRIPT_NAME'}'> - <input type='hidden' name='DEVICE' value='$uuid' /> - <input type='hidden' name='FS' value='$fs' /> - <input type='hidden' name='PATH' value='$path' /> - <input type='hidden' name='ACTION' value='$Lang::tr{'delete'}' /> - <input type='image' alt='$Lang::tr{'delete'}' title='$Lang::tr{'delete'}' src='/images/delete.gif' /> - </form></td></tr> -END -; + # Add the found entry to the hash of configured drives. + $configured_drives{$uuid} = $path; } - print <<END - </table> -END -;
-&Header::openbox('100%', 'center', $Lang::tr{'extrahd detected drives'}); + # Close the file handle. + close(FILE); + print <<END <table border='0' width='600' cellspacing="0"> END @@ -270,21 +249,35 @@ END # 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}; + + # 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"; - } - - # Omit the used filesystem. - my $fs = $filesystems{$partition};
# Check if the device is used as swap. - if (&is_swap($partition)) { + } elsif (&is_swap($partition)) { $disabled = "disabled"; $mountpoint = "swap"; }
+ # Omit the used filesystem. + my $fs = $filesystems{$partition}; + print <<END
<form method='post' action='$ENV{'SCRIPT_NAME'}'>
Signed-off-by: Stefan Schantl stefan.schantl@ipfire.org --- html/cgi-bin/extrahd.cgi | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/html/cgi-bin/extrahd.cgi b/html/cgi-bin/extrahd.cgi index fc8685830..533d0cdce 100644 --- a/html/cgi-bin/extrahd.cgi +++ b/html/cgi-bin/extrahd.cgi @@ -690,3 +690,15 @@ sub is_swap ($) {
return 1 if(grep /$device/, @swaps); } + +# +## Returns "True" if a drive is a configured one. +# +sub is_configured ($) { + my ($path) = @_; + + # Loop through the hash of configured drives. + foreach my $uuid (keys %configured_drives) { + return 1 if($configured_drives{$uuid} eq "$path"); + } +}
Signed-off-by: Stefan Schantl stefan.schantl@ipfire.org --- html/cgi-bin/extrahd.cgi | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/html/cgi-bin/extrahd.cgi b/html/cgi-bin/extrahd.cgi index 533d0cdce..a4d6e2e3a 100644 --- a/html/cgi-bin/extrahd.cgi +++ b/html/cgi-bin/extrahd.cgi @@ -302,14 +302,31 @@ END
print <<END </select></td> - <td align="center"><input type='text' name='PATH' value=$mountpoint $disabled></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}' /> - <input type='hidden' name='ACTION' value='$Lang::tr{'add'}' /> END -; unless($disabled) { - print"<input type='image' alt='$Lang::tr{'add'}' title='$Lang::tr{'add'}' src='/images/add.gif' />\n"; +; + # 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='MOUNTED' title='MOUNTED'> \n"; + } else { + print "<img src='/images/updbooster/updxl-led-red.gif' alt='NOT MOUNTED' title='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 "<img src='/images/updbooster/updxl-led-gray.gif' alt='UNCONFIGURED' title='UNCONFIGURED'> \n"; + print "<input type='image' alt='$Lang::tr{'add'}' title='$Lang::tr{'add'}' src='/images/add.gif'>\n"; + } }
print <<END
Signed-off-by: Stefan Schantl stefan.schantl@ipfire.org --- html/cgi-bin/extrahd.cgi | 49 +++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 23 deletions(-)
diff --git a/html/cgi-bin/extrahd.cgi b/html/cgi-bin/extrahd.cgi index a4d6e2e3a..89ba19921 100644 --- a/html/cgi-bin/extrahd.cgi +++ b/html/cgi-bin/extrahd.cgi @@ -98,28 +98,7 @@ $extrahdsettings{'UUID'} = ''; ## Add a new device. # if ($extrahdsettings{'ACTION'} eq $Lang::tr{'add'}) { - # Open device file for reading. - open( FILE, "< $devicefile" ) or die "Unable to read $devicefile"; - my @devices = <FILE>; - close FILE; - - # Loop through the entries line-by-line. - foreach my $entry (sort @devices) { - # Split the line into pieces and assign nice variables. - my ($uuid, $fs, $path) = split( /;/, $entry ); - - # Check if the path is allready used. - if ( "$extrahdsettings{'PATH'}" eq "$path" ) { - $errormessage = "$Lang::tr{'extrahd you cant mount'} $extrahdsettings{'DEVICE'} $Lang::tr{'extrahd to'} $extrahdsettings{'PATH'}$Lang::tr{'extrahd because there is already a device mounted'}."; - } - - # Check if the uuid is allready used. - if ("$extrahdsettings{'DEVICE'} eq $uuid") { - $errormessage = "$extrahdsettings{'DEVICE'} is allready mounted."; - } - } - - # Check if a valid mount path has been choosen. + # Check if a valid mount path has been choosen. unless(&is_valid_dir("$extrahdsettings{'PATH'}")) { $errormessage = "$Lang::tr{'extrahd you cant mount'} $extrahdsettings{'DEVICE'} $Lang::tr{'extrahd to root'}."; } @@ -129,7 +108,31 @@ if ($extrahdsettings{'ACTION'} eq $Lang::tr{'add'}) { $errormessage = "$Lang::tr{'extrahd you cant mount'} $extrahdsettings{'DEVICE'} $Lang::tr{'extrahd to'} $extrahdsettings{'PATH'}$Lang::tr{'extrahd because there is already a device mounted'}."; }
- # Check if there was an error message. + # Check against may previously configured drives. + unless ($errormessage) { + # Open device file for reading. + open( FILE, "< $devicefile" ) or die "Unable to read $devicefile"; + my @devices = <FILE>; + close FILE; + + # Loop through the entries line-by-line. + foreach my $entry (sort @devices) { + # Split the line into pieces and assign nice variables. + my ($uuid, $fs, $path) = split( /;/, $entry ); + + # Check if the path is allready used. + if ( "$extrahdsettings{'PATH'}" eq "$path" ) { + $errormessage = "$Lang::tr{'extrahd you cant mount'} $extrahdsettings{'DEVICE'} $Lang::tr{'extrahd to'} $extrahdsettings{'PATH'}$Lang::tr{'extrahd because there is already a device mounted'}."; + } + + # Check if the uuid is allready used. + if ("$extrahdsettings{'DEVICE'} eq $uuid") { + $errormessage = "$extrahdsettings{'DEVICE'} is allready mounted."; + } + } + } + + # Go further if there was no error message. unless($errormessage) { # Re-open the device file for writing. open(FILE, ">> $devicefile" ) or die "Unable to write $devicefile";
Signed-off-by: Stefan Schantl stefan.schantl@ipfire.org --- html/cgi-bin/extrahd.cgi | 21 ++++++++++++--------- langs/de/cgi-bin/de.pl | 5 +++++ langs/en/cgi-bin/en.pl | 5 +++++ 3 files changed, 22 insertions(+), 9 deletions(-)
diff --git a/html/cgi-bin/extrahd.cgi b/html/cgi-bin/extrahd.cgi index 89ba19921..8f6a91a18 100644 --- a/html/cgi-bin/extrahd.cgi +++ b/html/cgi-bin/extrahd.cgi @@ -98,14 +98,17 @@ $extrahdsettings{'UUID'} = ''; ## Add a new device. # if ($extrahdsettings{'ACTION'} eq $Lang::tr{'add'}) { + # Check if a mount path has been given. + if (not $extrahdsettings{'PATH'}) { + $errormessage = "$Lang::tr{'extrahd no mount point given'}."; + # Check if a valid mount path has been choosen. - unless(&is_valid_dir("$extrahdsettings{'PATH'}")) { - $errormessage = "$Lang::tr{'extrahd you cant mount'} $extrahdsettings{'DEVICE'} $Lang::tr{'extrahd to root'}."; - } + } elsif(not &is_valid_dir("$extrahdsettings{'PATH'}")) { + $errormessage = "$Lang::tr{'extrahd you cant mount'} $extrahdsettings{'DEVICE'} $Lang::tr{'extrahd to'} $extrahdsettings{'PATH'} $Lang::tr{'extrahd because it is outside the allowed mount path'}.";
# Check if the given path allready is mounted somewhere. - if(&is_mounted("$extrahdsettings{'PATH'}")) { - $errormessage = "$Lang::tr{'extrahd you cant mount'} $extrahdsettings{'DEVICE'} $Lang::tr{'extrahd to'} $extrahdsettings{'PATH'}$Lang::tr{'extrahd because there is already a device mounted'}."; + } elsif(&is_mounted("$extrahdsettings{'PATH'}")) { + $errormessage = "$Lang::tr{'extrahd you cant mount'} $extrahdsettings{'DEVICE'} $Lang::tr{'extrahd to'} $extrahdsettings{'PATH'} $Lang::tr{'extrahd because there is already a device mounted'}."; }
# Check against may previously configured drives. @@ -122,7 +125,7 @@ if ($extrahdsettings{'ACTION'} eq $Lang::tr{'add'}) {
# Check if the path is allready used. if ( "$extrahdsettings{'PATH'}" eq "$path" ) { - $errormessage = "$Lang::tr{'extrahd you cant mount'} $extrahdsettings{'DEVICE'} $Lang::tr{'extrahd to'} $extrahdsettings{'PATH'}$Lang::tr{'extrahd because there is already a device mounted'}."; + $errormessage = "$Lang::tr{'extrahd you cant mount'} $extrahdsettings{'DEVICE'} $Lang::tr{'extrahd to'} $extrahdsettings{'PATH'} $Lang::tr{'extrahd because there is already a device mounted'}."; }
# Check if the uuid is allready used. @@ -318,16 +321,16 @@ END
# Check if the device is mounted properly. if(&is_mounted($mountpoint)) { - print "<img src='/images/updbooster/updxl-led-green.gif' alt='MOUNTED' title='MOUNTED'> \n"; + 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='NOT MOUNTED' title='NOT MOUNTED'> \n"; + 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 "<img src='/images/updbooster/updxl-led-gray.gif' alt='UNCONFIGURED' title='UNCONFIGURED'> \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"; } } diff --git a/langs/de/cgi-bin/de.pl b/langs/de/cgi-bin/de.pl index 33730f0c3..37b17b431 100644 --- a/langs/de/cgi-bin/de.pl +++ b/langs/de/cgi-bin/de.pl @@ -1025,11 +1025,16 @@ 'external access rule removed' => ' Regel für externen Zugang entfernt; starte Zugangskontroller neu', 'external aliases configuration' => 'Externe Alias-Konfiguration', 'extrahd' => 'ExtraHD', +'extrahd because it is outside the allowed mount path' => 'mounten, da sich das Ziel außerhalb der erlaubten Pfade befindet', 'extrahd because there is already a device mounted' => ' mounten, weil bereits ein Gerät gemountet ist', 'extrahd cant umount' => 'Konnte', 'extrahd detected drives' => 'Gefundene Laufwerke', 'extrahd install or load driver' => 'Wenn Ihre Festplatte nicht angezeigt wird, müssen Sie zuerst den Treiber laden oder ggf. auch nachinstallieren. Wenn diese jedoch angezeigt wird, aber keine Partitionen zu sehen sind, müssen diese erst angelegt werden.', 'extrahd maybe the device is in use' => 'nicht mounten. Vielleicht wird das Gerät bereits verwendet', +'extrahd no mount point given' => 'Kein Pfad zum mounten angegeben', +'extrahd mounted' => 'Gemounted', +'extrahd not mounted' => 'Nicht gemounted', +'extrahd not configured' => 'Nicht konfiguriert', 'extrahd to' => 'nicht nach', 'extrahd to root' => 'nicht nach root mounten', 'extrahd unable to read' => 'Lesefehler von', diff --git a/langs/en/cgi-bin/en.pl b/langs/en/cgi-bin/en.pl index 729516538..b00ecc5eb 100644 --- a/langs/en/cgi-bin/en.pl +++ b/langs/en/cgi-bin/en.pl @@ -1072,11 +1072,16 @@ 'external access rule removed' => ' External access rule removed; restarting access controller', 'external aliases configuration' => 'External aliases configuration', 'extrahd' => 'ExtraHD', +'extrahd because it it outside the allowed mount path' => ', because it is outside the allowed mount path', 'extrahd because there is already a device mounted' => ', because there is already a device mounted', 'extrahd cant umount' => 'Can't umount', 'extrahd detected drives' => 'detected drives', 'extrahd install or load driver' => 'If your device isn't listed here, you need to install or load the driver.<br />If you can see your device but no partitions you have to create them first.', +'extrahd no mount point given', => 'No mount point given', 'extrahd maybe the device is in use' => '. Maybe the device is in use', +'extrahd mounted' => 'Mounted', +'extrahd not mounted' => 'Not mounted', +'extrahd not configured' => 'Not configured', 'extrahd to' => 'to', 'extrahd to root' => 'to root', 'extrahd unable to read' => 'Unable to read',
Stefan,
I tried to apply this patch but it doesn’t seem to work.
I notice there are no lines that begin with `-`.
Does this patch start from a blank `extrahd.cgi` file?
Jon
On Jun 22, 2023, at 11:01 PM, Stefan Schantl stefan.schantl@ipfire.org wrote:
This functions are going to replace the former used scan/write to file/read from file approach by directly collecting the required informations from the kernel sysfs and devfs.
Signed-off-by: Stefan Schantl stefan.schantl@ipfire.org
html/cgi-bin/extrahd.cgi | 360 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+)
diff --git a/html/cgi-bin/extrahd.cgi b/html/cgi-bin/extrahd.cgi index 36c0efc2e..44065a8a1 100644 --- a/html/cgi-bin/extrahd.cgi +++ b/html/cgi-bin/extrahd.cgi @@ -255,3 +255,363 @@ END
&Header::closebigbox(); &Header::closepage();
+# +## 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 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});
+}
+# +## Returns "True" if a given mountpoint is a subdirectory of one +## of the directories specified by the valid_mount_dirs array abouve. +# +sub is_valid_dir ($) {
- my ($mpoint) = @_;
- # Split the given mountpoint into pieces and store them
- # in a temporay array.
- my @tmp = split("/", $mpoint);
- # Exit and return nothing if the temporary array is empty.
- return unless(@tmp);
- # Build the root path based on the given mount point.
- my $root_path = "/" . @tmp[1];
- # Check if the root path is valid.
- return 1 if(grep /$root_path/, @valid_mount_dirs);
+}
+# +# Returns "True" if a device is used as swap. +# +sub is_swap ($) {
- my ($device) = @_;
- return 1 if(grep /$device/, @swaps);
+}
2.39.2
Stefan, could you please send a link to the CGI file so it can be downloaded easily without putting all these patches together?
On 25 Jun 2023, at 04:43, jon jon.murphy@ipfire.org wrote:
Stefan,
I tried to apply this patch but it doesn’t seem to work.
I notice there are no lines that begin with `-`.
Does this patch start from a blank `extrahd.cgi` file?
Jon
On Jun 22, 2023, at 11:01 PM, Stefan Schantl stefan.schantl@ipfire.org wrote:
This functions are going to replace the former used scan/write to file/read from file approach by directly collecting the required informations from the kernel sysfs and devfs.
Signed-off-by: Stefan Schantl stefan.schantl@ipfire.org
html/cgi-bin/extrahd.cgi | 360 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+)
diff --git a/html/cgi-bin/extrahd.cgi b/html/cgi-bin/extrahd.cgi index 36c0efc2e..44065a8a1 100644 --- a/html/cgi-bin/extrahd.cgi +++ b/html/cgi-bin/extrahd.cgi @@ -255,3 +255,363 @@ END
&Header::closebigbox(); &Header::closepage();
+# +## 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 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});
+}
+# +## Returns "True" if a given mountpoint is a subdirectory of one +## of the directories specified by the valid_mount_dirs array abouve. +# +sub is_valid_dir ($) {
- my ($mpoint) = @_;
- # Split the given mountpoint into pieces and store them
- # in a temporay array.
- my @tmp = split("/", $mpoint);
- # Exit and return nothing if the temporary array is empty.
- return unless(@tmp);
- # Build the root path based on the given mount point.
- my $root_path = "/" . @tmp[1];
- # Check if the root path is valid.
- return 1 if(grep /$root_path/, @valid_mount_dirs);
+}
+# +# Returns "True" if a device is used as swap. +# +sub is_swap ($) {
- my ($device) = @_;
- return 1 if(grep /$device/, @swaps);
+}
2.39.2
Hello Michael,
I'm quite a bit bussy at the moment so thanks for your reminder.
I've attached the CGI file and required language file on our bugtracker :
https://bugzilla.ipfire.org/show_bug.cgi?id=12863
-Stefan
Stefan, could you please send a link to the CGI file so it can be downloaded easily without putting all these patches together?
On 25 Jun 2023, at 04:43, jon jon.murphy@ipfire.org wrote:
Stefan,
I tried to apply this patch but it doesn’t seem to work.
I notice there are no lines that begin with `-`.
Does this patch start from a blank `extrahd.cgi` file?
Jon
On Jun 22, 2023, at 11:01 PM, Stefan Schantl stefan.schantl@ipfire.org wrote:
This functions are going to replace the former used scan/write to file/read from file approach by directly collecting the required informations from the kernel sysfs and devfs.
Signed-off-by: Stefan Schantl stefan.schantl@ipfire.org
html/cgi-bin/extrahd.cgi | 360 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+)
diff --git a/html/cgi-bin/extrahd.cgi b/html/cgi-bin/extrahd.cgi index 36c0efc2e..44065a8a1 100644 --- a/html/cgi-bin/extrahd.cgi +++ b/html/cgi-bin/extrahd.cgi @@ -255,3 +255,363 @@ END
&Header::closebigbox(); &Header::closepage();
+# +## 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 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});
+}
+# +## Returns "True" if a given mountpoint is a subdirectory of one +## of the directories specified by the valid_mount_dirs array abouve. +# +sub is_valid_dir ($) {
- my ($mpoint) = @_;
- # Split the given mountpoint into pieces and store them
- # in a temporay array.
- my @tmp = split("/", $mpoint);
- # Exit and return nothing if the temporary array is empty.
- return unless(@tmp);
- # Build the root path based on the given mount point.
- my $root_path = "/" . @tmp[1];
- # Check if the root path is valid.
- return 1 if(grep /$root_path/, @valid_mount_dirs);
+}
+# +# Returns "True" if a device is used as swap. +# +sub is_swap ($) {
- my ($device) = @_;
- return 1 if(grep /$device/, @swaps);
+}
2.39.2