mirror of
https://github.com/webmin/webmin.git
synced 2026-03-16 07:12:07 +00:00
431 lines
10 KiB
Perl
Executable File
431 lines
10 KiB
Perl
Executable File
# quota-lib.pl
|
|
# Common functions for quota management.
|
|
|
|
do '../web-lib.pl';
|
|
&init_config();
|
|
do '../ui-lib.pl';
|
|
if ($gconfig{'os_type'} =~ /^\S+\-linux$/) {
|
|
do "linux-lib.pl";
|
|
}
|
|
else {
|
|
do "$gconfig{'os_type'}-lib.pl";
|
|
}
|
|
if ($module_info{'usermin'}) {
|
|
&switch_to_remote_user();
|
|
}
|
|
else {
|
|
%access = &get_module_acl();
|
|
&foreign_require("mount", "mount-lib.pl");
|
|
}
|
|
|
|
$email_cmd = "$module_config_directory/email.pl";
|
|
|
|
# list_filesystems()
|
|
# Returns a list of details of local filesystems on which quotas are supported
|
|
# directory device type options quotacan quotanow
|
|
sub list_filesystems
|
|
{
|
|
local $f;
|
|
local @mtab = &mount::list_mounted();
|
|
foreach $f (&mount::list_mounts()) {
|
|
$fmap{$f->[0],$f->[1]} = $f;
|
|
}
|
|
map { $_->[4] = "a_can($_, $fmap{$_->[0],$_->[1]}) } @mtab;
|
|
map { $_->[5] = "a_now($_, $fmap{$_->[0],$_->[1]}) } @mtab;
|
|
return grep { $_->[4] } @mtab;
|
|
}
|
|
|
|
# parse_options(type, options)
|
|
# Convert an options string for some filesystem into the associative
|
|
# array %options
|
|
sub parse_options
|
|
{
|
|
local($_);
|
|
undef(%options);
|
|
if ($_[0] ne "-") {
|
|
foreach (split(/,/, $_[0])) {
|
|
if (/^([^=]+)=(.*)$/) { $options{$1} = $2; }
|
|
else { $options{$_} = ""; }
|
|
}
|
|
}
|
|
}
|
|
|
|
# user_quota(user, filesystem)
|
|
# Returns an array of ublocks, sblocks, hblocks, ufiles, sfiles, hfiles
|
|
# for some user, or an empty array if no quota has been assigned
|
|
sub user_quota
|
|
{
|
|
local (%user, $n, $i);
|
|
$n = &filesystem_users($_[1]);
|
|
for($i=0; $i<$n; $i++) {
|
|
if ($user{$i,'user'} eq $_[0]) {
|
|
return ( $user{$i,'ublocks'}, $user{$i,'sblocks'},
|
|
$user{$i,'hblocks'}, $user{$i,'ufiles'},
|
|
$user{$i,'sfiles'}, $user{$i,'hfiles'} );
|
|
}
|
|
}
|
|
return ();
|
|
}
|
|
|
|
# group_quota(group, filesystem)
|
|
# Returns an array of ublocks, sblocks, hblocks, ufiles, sfiles, hfiles
|
|
# for some group, or an empty array if no quota has been assigned
|
|
sub group_quota
|
|
{
|
|
local (%group, $n, $i);
|
|
$n = &filesystem_groups($_[1]);
|
|
for($i=0; $i<$n; $i++) {
|
|
if ($group{$i,'group'} eq $_[0]) {
|
|
return ( $group{$i,'ublocks'}, $group{$i,'sblocks'},
|
|
$group{$i,'hblocks'}, $group{$i,'ufiles'},
|
|
$group{$i,'sfiles'}, $group{$i,'hfiles'} );
|
|
}
|
|
}
|
|
return ();
|
|
}
|
|
|
|
# edit_user_quota(user, filesys, sblocks, hblocks, sfiles, hfiles)
|
|
# Sets the disk quota for some user
|
|
sub edit_user_quota
|
|
{
|
|
if ($config{'user_setquota_command'} &&
|
|
&has_command((split(/\s+/, $config{'user_setquota_command'}))[0])) {
|
|
# Use quota setting command
|
|
local $user = $_[0];
|
|
if ($user =~ /^#(\d+)$/) {
|
|
# Pass numeric UID
|
|
$user = $1;
|
|
}
|
|
local $cmd = $config{'user_setquota_command'}." ".quotemeta($user)." ".
|
|
int($_[2])." ".int($_[3])." ".int($_[4])." ".int($_[5]).
|
|
" ".quotemeta($_[1]);
|
|
local $out = &backquote_logged("$cmd 2>&1 </dev/null");
|
|
&error("<tt>".&html_escape($out)."</tt>") if ($?);
|
|
}
|
|
else {
|
|
# Call the quota editor
|
|
$ENV{'EDITOR'} = $ENV{'VISUAL'} = "$module_root_directory/edquota.pl";
|
|
$ENV{'QUOTA_USER'} = $_[0];
|
|
$ENV{'QUOTA_FILESYS'} = $_[1];
|
|
$ENV{'QUOTA_SBLOCKS'} = $_[2];
|
|
$ENV{'QUOTA_HBLOCKS'} = $_[3];
|
|
$ENV{'QUOTA_SFILES'} = $_[4];
|
|
$ENV{'QUOTA_HFILES'} = $_[5];
|
|
local $user = $_[0];
|
|
if ($edquota_use_ids) {
|
|
# Use UID instead of username
|
|
if ($user =~ /^#(\d+)$/) {
|
|
$user = $1;
|
|
}
|
|
else {
|
|
local $uid = getpwnam($user);
|
|
$user = $uid if (defined($uid));
|
|
}
|
|
}
|
|
&system_logged("$config{'user_edquota_command'} ".
|
|
quotemeta($user)." >/dev/null 2>&1");
|
|
}
|
|
}
|
|
|
|
# edit_group_quota(group, filesys, sblocks, hblocks, sfiles, hfiles)
|
|
# Sets the disk quota for some group
|
|
sub edit_group_quota
|
|
{
|
|
if ($config{'group_setquota_command'} &&
|
|
&has_command((split(/\s+/, $config{'group_setquota_command'}))[0])) {
|
|
# Use quota setting command
|
|
local $group = $_[0];
|
|
if ($group =~ /^#(\d+)$/) {
|
|
# Pass numeric UID
|
|
$group = $1;
|
|
}
|
|
local $cmd =$config{'group_setquota_command'}." ".quotemeta($group)." ".
|
|
int($_[2])." ".int($_[3])." ".int($_[4])." ".int($_[5]).
|
|
" ".quotemeta($_[1]);
|
|
local $out = &backquote_logged("$cmd 2>&1 </dev/null");
|
|
&error("<tt>".&html_escape($out)."</tt>") if ($?);
|
|
}
|
|
else {
|
|
# Call the editor
|
|
$ENV{'EDITOR'} = $ENV{'VISUAL'} = "$module_root_directory/edquota.pl";
|
|
$ENV{'QUOTA_USER'} = $_[0];
|
|
$ENV{'QUOTA_FILESYS'} = $_[1];
|
|
$ENV{'QUOTA_SBLOCKS'} = $_[2];
|
|
$ENV{'QUOTA_HBLOCKS'} = $_[3];
|
|
$ENV{'QUOTA_SFILES'} = $_[4];
|
|
$ENV{'QUOTA_HFILES'} = $_[5];
|
|
local $group = $_[0];
|
|
if ($edquota_use_ids) {
|
|
# Use GID instead of group name
|
|
if ($group =~ /^#(\d+)$/) {
|
|
$group = $1;
|
|
}
|
|
else {
|
|
local $gid = getgrnam($group);
|
|
$group = $gid if (defined($gid));
|
|
}
|
|
}
|
|
&system_logged("$config{'group_edquota_command'} ".
|
|
quotemeta($group)." >/dev/null 2>&1");
|
|
}
|
|
}
|
|
|
|
# edit_user_grace(filesystem, btime, bunits, ftime, funits)
|
|
# Change the grace times for blocks and files on some filesystem
|
|
sub edit_user_grace
|
|
{
|
|
$ENV{'EDITOR'} = $ENV{'VISUAL'} = "$module_root_directory/edgrace.pl";
|
|
$ENV{'QUOTA_FILESYS'} = $_[0];
|
|
$ENV{'QUOTA_BTIME'} = $_[1];
|
|
$ENV{'QUOTA_BUNITS'} = $_[2];
|
|
$ENV{'QUOTA_FTIME'} = $_[3];
|
|
$ENV{'QUOTA_FUNITS'} = $_[4];
|
|
&system_logged($config{'user_grace_command'});
|
|
}
|
|
|
|
# edit_group_grace(filesystem, btime, bunits, ftime, funits)
|
|
# Change the grace times for blocks and files on some filesystem
|
|
sub edit_group_grace
|
|
{
|
|
$ENV{'EDITOR'} = $ENV{'VISUAL'} = "$module_root_directory/edgrace.pl";
|
|
$ENV{'QUOTA_FILESYS'} = $_[0];
|
|
$ENV{'QUOTA_BTIME'} = $_[1];
|
|
$ENV{'QUOTA_BUNITS'} = $_[2];
|
|
$ENV{'QUOTA_FTIME'} = $_[3];
|
|
$ENV{'QUOTA_FUNITS'} = $_[4];
|
|
&system_logged($config{'group_grace_command'});
|
|
}
|
|
|
|
# quota_input(name, value, [blocksize])
|
|
# Prints an input for selecting a quota or unlimited, in a table
|
|
sub quota_input
|
|
{
|
|
print "<td nowrap>",&ui_radio($_[0]."_def", $_[1] == 0 ? 1 : 0,
|
|
[ [ 1, $text{'quota_unlimited'} ], [ 0, " " ] ]);
|
|
print "a_inputbox(@_);
|
|
print "</td> </tr>\n";
|
|
}
|
|
|
|
# quota_inputbox(name, value, [blocksize])
|
|
# Returns an input for selecting a quota
|
|
sub quota_inputbox
|
|
{
|
|
if ($_[2]) {
|
|
# We know the real size, so can offer units
|
|
local $sz = $_[1]*$_[2];
|
|
local $units = 1;
|
|
if ($sz >= 10*1024*1024*1024) {
|
|
$units = 1024*1024*1024;
|
|
}
|
|
elsif ($sz >= 10*1024*1024) {
|
|
$units = 1024*1024;
|
|
}
|
|
elsif ($sz >= 10*1024) {
|
|
$units = 1024;
|
|
}
|
|
else {
|
|
$units = 1;
|
|
}
|
|
$sz = $sz == 0 ? "" : sprintf("%.2f", ($sz*1.0)/$units);
|
|
return &ui_textbox($_[0], $sz, 8).
|
|
&ui_select($_[0]."_units", $units,
|
|
[ [ 1, "bytes" ], [ 1024, "kB" ], [ 1024*1024, "MB" ],
|
|
[ 1024*1024*1024, "GB" ] ]);
|
|
}
|
|
else {
|
|
# Just show blocks
|
|
return &ui_textbox($_[0], $_[1] == 0 ? "" : $_[1], 8);
|
|
}
|
|
}
|
|
|
|
# quota_parse(name, [bsize], [nodef])
|
|
sub quota_parse
|
|
{
|
|
if ($in{$_[0]."_def"} && !$_[2]) {
|
|
return 0;
|
|
}
|
|
elsif ($_[1]) {
|
|
# Include units, and covert to blocks
|
|
return int($in{$_[0]}*$in{$_[0]."_units"}/$_[1]);
|
|
}
|
|
else {
|
|
# Just use blocks
|
|
return int($in{$_[0]});
|
|
}
|
|
}
|
|
|
|
# can_edit_filesys(filesys)
|
|
sub can_edit_filesys
|
|
{
|
|
local $fs;
|
|
foreach $fs (split(/\s+/, $access{'filesys'})) {
|
|
return 1 if ($fs eq "*" || $fs eq $_[0]);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
# can_edit_user(user)
|
|
sub can_edit_user
|
|
{
|
|
if ($access{'umode'} == 0) {
|
|
return 1;
|
|
}
|
|
elsif ($access{'umode'} == 3) {
|
|
local @u = getpwnam($_[0]);
|
|
return $access{'users'} == $u[3];
|
|
}
|
|
elsif ($access{'umode'} == 4) {
|
|
local @u = getpwnam($_[0]);
|
|
return (!$access{'umin'} || $u[2] >= $access{'umin'}) &&
|
|
(!$access{'umax'} || $u[2] <= $access{'umax'});
|
|
}
|
|
else {
|
|
local ($u, %ucan);
|
|
map { $ucan{$_}++ } split(/\s+/, $access{'users'});
|
|
return $access{'umode'} == 1 && $ucan{$_[0]} ||
|
|
$access{'umode'} == 2 && !$ucan{$_[0]};
|
|
}
|
|
}
|
|
|
|
# can_edit_group(group)
|
|
sub can_edit_group
|
|
{
|
|
return 1 if ($access{'gmode'} == 0);
|
|
return 0 if ($access{'gmode'} == 3);
|
|
local ($g, %gcan);
|
|
map { $gcan{$_}++ } split(/\s+/, $access{'groups'});
|
|
return $access{'gmode'} == 1 && $gcan{$_[0]} ||
|
|
$access{'gmode'} == 2 && !$gcan{$_[0]};
|
|
}
|
|
|
|
# filesystem_info(filesystem, &hash, count, [blocksize])
|
|
sub filesystem_info
|
|
{
|
|
local @fs = &free_space($_[0], $_[3]);
|
|
if ($_[3]) {
|
|
local $i;
|
|
foreach $i (0 .. 3) {
|
|
$fs[$i] = $i < 2 ? &nice_size($fs[$i]*$_[3])
|
|
: int($fs[$i]);
|
|
}
|
|
}
|
|
if ($_[1]) {
|
|
local $bt = 0;
|
|
local $ft = 0;
|
|
local $i;
|
|
for($i=0; $i<$_[2]; $i++) {
|
|
$bt += $_[1]->{$i,'hblocks'};
|
|
$ft += $_[1]->{$i,'hfiles'};
|
|
}
|
|
if ($_[3]) {
|
|
$bt = &nice_size($bt*$_[3]);
|
|
}
|
|
return ( "$fs[0] total / $fs[1] free / $bt granted",
|
|
"$fs[2] total / $fs[3] free / $ft granted" );
|
|
}
|
|
else {
|
|
return ( "$fs[0] total / $fs[1] free",
|
|
"$fs[2] total / $fs[3] free" );
|
|
}
|
|
}
|
|
|
|
# block_size(dir, [for-filesys])
|
|
# Returns the size (in bytes) of blocks on some filesystem
|
|
sub block_size
|
|
{
|
|
return undef if (!$config{'block_mode'});
|
|
return undef if (!defined("a_block_size) &&
|
|
!defined(&fs_block_size));
|
|
local @mounts = &mount::list_mounted();
|
|
local ($mount) = grep { $_->[0] eq $_[0] } @mounts;
|
|
if ($mount) {
|
|
if ($_[1]) {
|
|
return &fs_block_size(@$mount);
|
|
}
|
|
else {
|
|
if (defined("a_block_size)) {
|
|
return "a_block_size(@$mount);
|
|
}
|
|
else {
|
|
return &fs_block_size(@$mount);
|
|
}
|
|
}
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
# print_limit(amount, no-blocks)
|
|
sub print_limit
|
|
{
|
|
if ($_[0] == 0) { print "<td>$text{'quota_unlimited'}</td>\n"; }
|
|
elsif ($bsize && !$_[1]) { print "<td>",&nice_size($_[0]*$bsize),"</td>"; }
|
|
else { print "<td>$_[0]</td>\n"; }
|
|
}
|
|
|
|
# nice_limit(amount, bsize, no-blocks)
|
|
sub nice_limit
|
|
{
|
|
local ($amount, $bsize, $noblocks) = @_;
|
|
return $amount == 0 ? $text{'quota_unlimited'} :
|
|
$bsize && !$noblocks ? &nice_size($amount*$bsize) : $amount;
|
|
}
|
|
|
|
sub print_grace
|
|
{
|
|
print "<td>",($_[0] || "<br>"),"</td>\n";
|
|
}
|
|
|
|
sub find_email_job
|
|
{
|
|
&foreign_require("cron", "cron-lib.pl");
|
|
local @jobs = &cron::list_cron_jobs();
|
|
local ($job) = grep { $_->{'command'} eq $email_cmd } @jobs;
|
|
return $job;
|
|
}
|
|
|
|
# create_email_job()
|
|
# Creates the cron job for scheduled emailing
|
|
sub create_email_job
|
|
{
|
|
&foreign_require("cron", "cron-lib.pl");
|
|
local $job = &find_email_job();
|
|
if (!$job) {
|
|
$job = { 'user' => 'root',
|
|
'command' => $email_cmd,
|
|
'active' => 1,
|
|
'mins' => '0,10,20,30,40,50',
|
|
'hours' => '*',
|
|
'days' => '*',
|
|
'months' => '*',
|
|
'weekdays' => '*' };
|
|
&lock_file(&cron::cron_file($job));
|
|
&cron::create_cron_job($job);
|
|
&cron::create_wrapper($email_cmd, $module_name, "email.pl");
|
|
&unlock_file(&cron::cron_file($job));
|
|
}
|
|
}
|
|
|
|
# trunc_space(string)
|
|
# Removes spaces from the start and end of a string
|
|
sub trunc_space
|
|
{
|
|
local $rv = $_[0];
|
|
$rv =~ s/^\s+//;
|
|
$rv =~ s/\s+$//;
|
|
return $rv;
|
|
}
|
|
|
|
# to_percent(used, total)
|
|
sub to_percent
|
|
{
|
|
if ($_[1]) {
|
|
return $_[0]*100/$_[1];
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
1;
|
|
|