#!/usr/bin/perl -w #---------------------------------------------------------------------- # copyright (C) 2002 Mitel Networks Corporation # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Technical support for this program is available from Mitel Networks # Please visit our web site www.mitel.com/sme/ for details. #---------------------------------------------------------------------- package esmith; use strict; use Errno; use Quota; use esmith::AccountsDB; my $accounts = esmith::AccountsDB->open; my @users = (); my $event = $ARGV [0]; if ($event eq "bootstrap-console-save") { # For bootstrap-console-save, make sure that quota entries are # set for each user @users = $accounts->users; } else { # Otherwise just set quota for the named user. my $userName = $ARGV [1]; #------------------------------------------------------------ # Check the Unix account #------------------------------------------------------------ =begin testing use esmith::TestUtils qw(simulate_perl_program); my $exit = simulate_perl_program($Original_File, 'wibble-event', 'user_that_doesnt_exist'); is( $exit, 255 * 256, 'non-existent user - exit code' ); like( $@, qr{^Account "user_that_doesnt_exist" is not a user account}, ' failure message'); $exit = simulate_perl_program($Original_File, 'wibble-event' ); is( $exit, 255 * 256, 'forgotten user - exit code' ); like( $@, qr{^Username argument missing}, ' failure message'); =end testing =cut die "Username argument missing.\n" unless defined ($userName); my $user = $accounts->get($userName); if( !$user or $user->prop('type') ne 'user' ) { die qq{Account "$userName" is not a user account; modify } . "user quota failed.\n"; } @users = ($user); } =begin testing my $a_tmp = '50-e-smith-quota/accounts.conf'; $ENV{ESMITH_ACCOUNT_DB} = $a_tmp; END { unlink $a_tmp }; open(TMP, ">$a_tmp") || die $!; print TMP <<'OUT'; root=system|Gid|0|Uid|0 server-manager=url server-manual=url shared=system|Gid|500|Visible|internal shutdown=system slocate=system|Gid|21 user_quota=user|Gid|1000|Uid|1000|MaxBlocksSoftLim|10000|MaxBlocks|20000|MaxFilesSoftLim|1000|MaxFiles|2000 user_partial=user|Gid|1001|Uid|1001|MaxBlocksSoftLim|123456|MaxFiles|321 user_no_quota=user|Gid|1002|Uid|1002 OUT close TMP; # Quota properties in the order setqlim likes. my @QProps = qw(MaxBlocksSoftLim MaxBlocks MaxFilesSoftLim MaxFiles); my %curr_quota = ( 1000 => { MaxFilesSoftLim => 100 }, 1001 => { MaxBlocks => 30000, MaxBlocksSoftLim => 20000 }, 1002 => { MaxFiles => 2 }, ); # What we expect the new quotas to be my %expect_quotas = ( 1000 => { MaxBlocksSoftLim => 10000, MaxBlocks => 20000, MaxFilesSoftLim => 1000, MaxFiles => 2000 }, 1001 => { MaxBlocksSoftLim => 123456, MaxBlocks => 30000, MaxFilesSoftLim => 0, MaxFiles => 321 }, 1002 => { MaxBlocksSoftLim => 0, MaxBlocks => 0, MaxFilesSoftLim => 0, MaxFiles => 2 }, ); { # Since these users don't really exist, we have to fool getpwnam # into using the Uid from the dummy accounts DB. no warnings 'once'; local *CORE::GLOBAL::getpwnam = sub { esmith::AccountsDB->open->get($_[0])->prop('Uid'); }; # Override the Quota query and set functions since # 1) these users probably don't exist # 2) if they did, we don't want to screw with their quotas # 3) we need to know how each Quota function is called use Quota; no warnings 'redefine'; my %query; sub Quota::query { my($dev, $uid, $isgrp) = @_; $query{$uid} = { isgrp => $isgrp }; return (0, $curr_quota{$uid}{MaxBlocksSoftLim} || 0, $curr_quota{$uid}{MaxBlocks} || 0, 0, 0, $curr_quota{$uid}{MaxFilesSoftLim} || 0, $curr_quota{$uid}{MaxFiles} || 0, 0 ); } my %set_quota = (); sub Quota::setqlim { my($dev, $uid) = (shift, shift); my(@limits) = splice(@_, 0, 4); my($tlo) = shift; my %limits = (); @limits{@QProps} = @limits; $set_quota{$uid}{limits} = \%limits; $set_quota{$uid}{tlo} = $tlo; return 1; } $_STDOUT_ = ''; $_STDERR_ = ''; my $exit = simulate_perl_program($Original_File, 'bootstrap-console-save'); is( $exit, 0, 'bootstrap-console-save - exit code' ); is( $_STDOUT_, '' ); is( $_STDERR_, '' ); is( $@, '' ); is_deeply( [sort keys %set_quota], [sort qw(1000 1001 1002)] ); foreach my $uid (keys %set_quota) { is_deeply( $set_quota{$uid}{limits}, $expect_quotas{$uid}, "setqlim for $uid"); } } =end testing =cut # Quota properties in the order setqlim likes. my @QProps = qw(MaxBlocksSoftLim MaxBlocks MaxFilesSoftLim MaxFiles); foreach my $user (@users) { my $userName = $user->key; my $uid = getpwnam($userName); die qq{Could not get uid for user named "$userName"\n} unless $uid; my(%uquota, %curr_quota); foreach my $qprop (@QProps) { $uquota{$qprop} = $user->prop($qprop); } # Get a $dev value appropriate for use in Quota::query call. my $dev = Quota::getqcarg("/home/e-smith/files"); # Get current quota settings. @curr_quota{@QProps} = (Quota::query($dev, $uid, 0))[1,2,5,6]; if( !defined $curr_quota{MaxBlocks} ) # Quota::query failed { warn "Cannot query your quota for '$userName' on '$dev'\n"; warn "Quota error (are you using NFS?): ", Quota::strerr(), "\n"; next; } # Keep old values unless there are values defined in the account record foreach my $qprop (@QProps) { $uquota{$qprop} = $curr_quota{$qprop} unless defined $uquota{$qprop}; } # Set the new quota Quota::setqlim($dev, $uid, @uquota{@QProps}, 0); }