Files
webmin/quota/quota-lib.pl

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] = &quota_can($_, $fmap{$_->[0],$_->[1]}) } @mtab;
map { $_->[5] = &quota_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 &quota_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(&quota_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(&quota_block_size)) {
return &quota_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;