87 lines
3.0 KiB
Perl
Executable File
87 lines
3.0 KiB
Perl
Executable File
#!/usr/local/bin/perl
|
|
# Save the limits for a Btrfs qgroup
|
|
|
|
require './quota-lib.pl';
|
|
&ReadParse();
|
|
$dir = $in{'dir'};
|
|
|
|
# Require write access to an allowed mounted Btrfs filesystem and reject
|
|
# malformed qgroup IDs before parsing or applying limits.
|
|
$access{'ro'} && &error($text{'btrfs_eedit'});
|
|
&can_edit_btrfs_filesys($dir) || &error($text{'btrfs_eallow'});
|
|
defined(&btrfs_quota_status) && &is_btrfs_fs($dir) ||
|
|
&error($text{'btrfs_enotbtrfs'});
|
|
&valid_btrfs_qgroup_id($in{'qgroup'}) || &error($text{'btrfs_eqgroup'});
|
|
$in{'qgroup'} eq "0/5" && &error($text{'btrfs_etoplevel'});
|
|
&error_setup($text{'btrfs_esave'});
|
|
|
|
# parse_limit(name)
|
|
# Parse one optional byte limit from quota_input and validate its unit factor.
|
|
sub parse_limit
|
|
{
|
|
my ($name) = @_;
|
|
|
|
# A selected default means that this limit should be removed.
|
|
return undef if ($in{$name."_def"});
|
|
|
|
# Accept only positive decimal values and units offered by ui_bytesbox.
|
|
$in{$name} =~ /^\d+(?:\.\d+)?$/ && $in{$name} > 0 ||
|
|
&error($text{'btrfs_elimit'});
|
|
local %units = map { $_, 1 } ( 1, 1024, 1024**2, 1024**3,
|
|
1024**4, 1024**5 );
|
|
$units{$in{$name."_units"}} || &error($text{'btrfs_elimit'});
|
|
return int($in{$name} * $in{$name."_units"});
|
|
}
|
|
|
|
# Parse both limits completely before making either filesystem change.
|
|
$max_referenced = &parse_limit("max_referenced");
|
|
$max_exclusive = &parse_limit("max_exclusive");
|
|
|
|
# Apply the existing ACL ceiling, converting its KiB value to bytes.
|
|
if ($access{'maxblocks'}) {
|
|
$maxbytes = $access{'maxblocks'} * 1024;
|
|
defined($max_referenced) && $max_referenced <= $maxbytes &&
|
|
defined($max_exclusive) && $max_exclusive <= $maxbytes ||
|
|
&error(&text('btrfs_emax', &nice_size($maxbytes)));
|
|
}
|
|
|
|
# Refresh the selected qgroup so unchanged limits are not re-applied. This
|
|
# lookup only needs the stored limit values, so no filesystem sync is needed.
|
|
$qgroups = &list_btrfs_qgroups($dir, 0, \$listerr);
|
|
&error($listerr) if (!$qgroups);
|
|
($qgroup) = grep { $_->{'id'} eq $in{'qgroup'} } @$qgroups;
|
|
$qgroup || &error($text{'btrfs_eqgroup'});
|
|
|
|
# same_limit(first, second)
|
|
# Returns true when two optional byte limits are identical.
|
|
sub same_limit
|
|
{
|
|
my ($first, $second) = @_;
|
|
return !defined($first) && !defined($second) ||
|
|
defined($first) && defined($second) && $first == $second;
|
|
}
|
|
|
|
# Compare the submitted referenced and exclusive limits with their current
|
|
# values before running either Btrfs command.
|
|
$same_referenced = &same_limit(
|
|
$max_referenced, $qgroup->{'max_referenced'});
|
|
$same_exclusive = &same_limit(
|
|
$max_exclusive, $qgroup->{'max_exclusive'});
|
|
|
|
# Apply only changed limits so each independent setting is left untouched when
|
|
# the submitted value already matches it.
|
|
if (!$same_referenced) {
|
|
$err = &set_btrfs_qgroup_limit(
|
|
$dir, $in{'qgroup'}, $max_referenced, 0);
|
|
&error($err) if ($err);
|
|
}
|
|
if (!$same_exclusive) {
|
|
$err = &set_btrfs_qgroup_limit(
|
|
$dir, $in{'qgroup'}, $max_exclusive, 1);
|
|
&error($err) if ($err);
|
|
}
|
|
|
|
# Log the completed update and return to the qgroup list.
|
|
&webmin_log("save", "btrfs", $in{'qgroup'}, \%in);
|
|
&redirect("list_btrfs.cgi?dir=".&urlize($dir));
|