Viewing file: quota-lib.pl (13.96 KB) -rwxr-xr-x Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
=head1 quota-lib.pl
Functions for Unix user and group quota management. Some of the functionality is implemented in OS-specific library files which get automatically included into this one, like linux-lib.pl. Check the documentation on that file for more functions.
Example code:
foreign_require('quota', 'quota-lib.pl'); quota::edit_user_quota('joe', '/home', 1000000, 1200000, 1000, 1200); $n = quota::user_filesystems('joe'); for($i=0; $i<$n; $i++) { print "filesystem=",$filesys{$i,'filesys'}," ", "block quota=",$filesys{$i,'hblocks'}," ", "blocks used=",$filesys{$i,'ublocks'},"\n"; }
=cut
BEGIN { push(@INC, ".."); }; use WebminCore; &init_config(); 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";
=head2 list_filesystems
Returns a list of details of local filesystems on which quotas are supported. Each is an array ref whose values are :
=item directory - Mount point, like /home
=item device - Source device, like /dev/hda1
=item type - Filesystem type, like ext3
=item options - Mount options, like rw,usrquota,grpquota
=item quotacan - Can this filesystem type support quotas?
=item quotanow - Are quotas enabled right now?
The values of quotacan and quotanow are :
=item 0 - No quotas
=item 1 - User quotas only
=item 2 - Group quotas only
=item 3 - User and group quotas
=cut 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; }
=head2 parse_options(type, options)
Convert an options string for some filesystem into the global hash %options.
=cut sub parse_options { local($_); undef(%options); if ($_[0] ne "-") { foreach (split(/,/, $_[0])) { if (/^([^=]+)=(.*)$/) { $options{$1} = $2; } else { $options{$_} = ""; } } } }
=head2 user_quota(user, filesystem)
Returns an array of quotas and usage information for some user on some filesystem, or an empty array if no quota has been assigned. The array elements are :
=item Number of blocks used.
=item Soft block quota.
=item Hard block quota.
=item Number of files used.
=item Soft file quota.
=item Hard file quota.
=cut 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 (); }
=head2 group_quota(group, filesystem)
Returns an array of ublocks, sblocks, hblocks, ufiles, sfiles, hfiles for some group on some filesystem, or an empty array if no quota has been assigned.
=cut 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 (); }
=head2 edit_user_quota(user, filesys, sblocks, hblocks, sfiles, hfiles)
Sets the disk quota for some user. The parameters are :
=item user - Unix username.
=item filesys - Filesystem on which to change quotas.
=item sblocks - Soft block limit.
=item hblocks - Hard block limit.
=item sfiles - Sort files limit.
=item hfiles - Hard files limit.
=cut 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; } elsif ($user =~ /^\d+$/) { # Username is numeric .. convert to UID local $uid = getpwnam($user); $user = $uid if (defined($uid)); } 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"); } }
=head2 edit_group_quota(group, filesys, sblocks, hblocks, sfiles, hfiles)
Sets the disk quota for some group The parameters are :
=item user - Unix group name.
=item filesys - Filesystem on which to change quotas.
=item sblocks - Soft block limit.
=item hblocks - Hard block limit.
=item sfiles - Sort files limit.
=item hfiles - Hard files limit.
=cut 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; } elsif ($group =~ /^\d+$/) { # Group name is numeric .. convert to GID local $gid = getgrnam($group); $group = $gid if (defined($gid)); } 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"); } }
=head2 edit_user_grace(filesystem, btime, bunits, ftime, funits)
Change the grace times for blocks and files on some filesystem. Parameters are:
=item filesystem - Filesystem to change the grace time on.
=item btime - Number of units after which a user over his soft block limit is turned into a hard limit.
=item bunits - Units for the block grace time, such as 'seconds', 'minutes', 'hours' or 'days'.
=item ftime - Number of units after which a user over his soft file limit is turned into a hard limit.
=item funits - Units for the file grace time, such as 'seconds', 'minutes', 'hours' or 'days'.
=cut 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'}); }
=head2 edit_group_grace(filesystem, btime, bunits, ftime, funits)
Change the grace times for groups for blocks and files on some filesystem. The parameters are the same as edit_user_grace.
=cut 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'}); }
=head2 quota_input(name, value, [blocksize])
Returns an input for selecting a quota or unlimited, in a table. For internal use mainly.
=cut sub quota_input { return &ui_radio($_[0]."_def", $_[1] == 0 ? 1 : 0, [ [ 1, $text{'quota_unlimited'} ], [ 0, " " ] ])." ". "a_inputbox(@_); }
=head2 quota_inputbox(name, value, [blocksize])
Returns an input for selecting a quota. Mainly for internal use.
=cut 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); } }
=head2 quota_parse(name, [bsize], [nodef])
Parses inputs from the form generated by quota_input.
=cut 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]}); } }
=head2 can_edit_filesys(filesys)
Returns 1 if the current Webmin user can manage quotas on some filesystem.
=cut sub can_edit_filesys { local $fs; foreach $fs (split(/\s+/, $access{'filesys'})) { return 1 if ($fs eq "*" || $fs eq $_[0]); } return 0; }
=head2 can_edit_user(user)
Returns 1 if the current Webmin user can manage quotas for some Unix user.
=cut 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 %ucan = map { $_, 1 } split(/\s+/, $access{'users'}); return $access{'umode'} == 1 && $ucan{$_[0]} || $access{'umode'} == 2 && !$ucan{$_[0]}; } }
=head2 can_edit_group(group)
Returns 1 if the current Webmin user can manage quotas for some Unix group.
=cut sub can_edit_group { if ($access{'gmode'} == 0) { return 1; } elsif ($access{'gmode'} == 3) { return 0; } elsif ($access{'gmode'} == 4) { local @g = getgrnam($_[0]); return (!$access{'gmin'} || $g[2] >= $access{'gmin'}) && (!$access{'gmax'} || $g[2] <= $access{'gmax'}); } else { local %gcan = map { $_, 1 } split(/\s+/, $access{'groups'}); return $access{'gmode'} == 1 && $gcan{$_[0]} || $access{'gmode'} == 2 && !$gcan{$_[0]}; } }
=head2 filesystem_info(filesystem, &hash, count, [blocksize])
Returns two strings containing information about the amount of disk space granted and used on some filesystem. For internal use.
=cut 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" ); } }
=head2 block_size(dir, [for-filesys])
Returns the size (in bytes) of blocks on some filesystem, if known. All quota functions deal with blocks, so they must be multipled by the value returned by this function before display to users.
=cut 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; }
=head2 nice_limit(amount, bsize, no-blocks)
Internal function to show a quota limit nicely formatted.
=cut sub nice_limit { local ($amount, $bsize, $noblocks) = @_; return $amount == 0 ? $text{'quota_unlimited'} : $bsize && !$noblocks ? &nice_size($amount*$bsize) : $amount; }
=head2 find_email_job
Returns the cron job hash ref for the quota limit monitoring email job.
=cut 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; }
=head2 create_email_job
Creates the cron job for scheduled emailing, which runs every 10 minutes.
=cut 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)); } }
=head2 trunc_space(string)
Removes spaces from the start and end of a string.
=cut sub trunc_space { local $rv = $_[0]; $rv =~ s/^\s+//; $rv =~ s/\s+$//; return $rv; }
=head2 to_percent(used, total)
Converts an amount used and a total into a percentage.
=cut sub to_percent { if ($_[1]) { return $_[0]*100/$_[1]; } else { return 0; } }
=head2 select_grace_units(name, value)
Returns a menu for selecting grace time units.
=cut sub select_grace_units { local @uarr = &grace_units(); return &ui_select($_[0], $_[1], [ map { [ $_, $uarr[$_] ] } (0..$#uarr) ]); }
# resolve_and_simplify(path) # Resolve symlinks from a path, and simplify the result to remove dots sub resolve_and_simplify { my ($path) = @_; return &simplify_path(&resolve_links($path)); }
1;
|