#!/bin/tcsh -f
# JLdL 21Jan11.
#
# Copyright (C) 2006-2011 by Jorge L. deLyra <delyra@fma.if.usp.br>.
# This program may be copied and/or distributed freely. See the
# _ terms and conditions in /usr/share/doc/<package>/copyright.
#
# This program fixes the binary quota file of a filesystem, based
# _ on the data in the corresponding text file.
#
# Record the name this script was called with.
set name = `basename $0`
#
# Define a variable with the tab character.
set tab = "`echo -n '\t'`"
#
# Initialize variables for the configuration file.
set conflag = 0
#
# Set the default configuration file.
set confile = "/etc/quotas.conf"
#
# Set a flag for the single argument needed.
set argflag = 0
#
# Set a flag for the use of the temporary text file.
set tmpflag = 0
#
# Set a flag for the progress-report output, default is up.
set proflag = 1
#
# Process the command-line arguments.
foreach cla ( $* )
    #
    # Detect options.
    if ( "`echo -n $cla | cut -c 1`" == "-" ) then
	#
	# If we got here with conflag up, there is an error.
	if ( $conflag == 1 ) then
	    echo "${name}: ERROR: option -C requires an argument"
	    exit 1
	endif
	#
	# Now process the options.
	switch ( $cla )
	case "-h":
	case "--help":
	    #
	    # Print a usage message.
	    echo -n "usage: $name [-C <config>] [-u|-g] [-t] [-q]"
	    echo    " </path/to/fs/root>"
	    echo "       -C: use alternate configuration file <config>"
	    echo "       -u: manipulate user quotas"
	    echo "       -g: manipulate group quotas"
	    echo "       -t: use the temporary text quota file"
	    echo "       -q: run quietly, no progress reporting"
	    exit 0
	    breaksw
	case "-C":
	case "--Config-file":
	    #
	    # Raise the flag.
	    set conflag = 1
	    breaksw
	case "-u":
	case "--usrquota":
	    #
	    # Set the type of quota.
	    set qtype = u
	    #
	    # Set the file extension.
	    set fext = user
	    breaksw
	case "-g":
	case "--grpquota":
	    #
	    # Set the type of quota.
	    set qtype = g
	    #
	    # Set the file extension.
	    set fext = group
	    breaksw
	case "-t":
	case "--temporary-file":
	    #
	    # Set the temporary flag.
	    set tmpflag = 1
	    breaksw
	case "-q":
	case "--quiet":
	    #
	    # Unset the progress-report flag.
	    set proflag = 0
	    breaksw
	default:
	    #
	    # Print an error message.
	    echo "${name}: ERROR: unknown option $cla"
	    exit 1
	    breaksw
	endsw
    #
    # Process non-option arguments.
    else
	#
	# Get the arguments of options.
	if ( $conflag == 1 ) then
	    #
	    # Set the configuration file.
	    set confile = $cla
	    #
	    # Lower the flag.
	    set conflag = 0
	else
	    #
	    # Get the filesystem from the command line argument.
	    if ( $argflag ) then
		echo "${name}: ERROR: too many arguments"
		exit 1
	    else
		set fs = $cla
		#
		# Lower the flag.
		set argflag = 1
	    endif
	endif
    endif
end
#
# If we got here with conflag up, there is an error.
if ( $conflag == 1 ) then
    echo "${name}: ERROR: option -C requires an argument"
    exit 1
endif
#
# Check for the single argument needed.
if ( ! $argflag ) then
    echo "${name}: ERROR: needs 1 argument: the filesystem"
    exit 1
endif
#
# Source the configuration file; this must define the following variables:
# _ quotas_path; default_type.
if ( -r $confile ) then
    source $confile
else
    echo "${name}: ERROR: cannot read configuration file $confile"
    exit 1
endif
#
# Set the location of the text quota files.
set qpath = "$quotas_path"
#
# If no quota-type options were entered, set the default type
# _ of quota, as defined in the configuration file.
if ( ! $?qtype ) then
    #
    # Set the type of quota.
    set qtype = `echo "$default_type" | cut -c 1`
    #
    # Set the file extension.
    set fext = "$default_type"
endif    
#
# Strip away any "/"'s at the extremes of the filesystem path.
set fs = `echo $fs | sed -e 's|/\+$||g' -e 's|^/\+||g'`
#
# Give a warning about reseting all the quotas of the filesystem.
if ( ! $tmpflag ) then
    echo "${name}: WARNING: this will reset all quotas in the /$fs"
    echo "filesystem, regardless of whether or not they have really been"
    echo "modified in the text configuration file; in addition to this,"
    echo "all grace-period times will be reset to zero; are you sure you"
    echo -n "want to do this? [N]: "
    set idec = $<
    if ( "$idec" != y && "$idec" != Y ) exit 0
endif
#
# Define the basic name of the text quota file.
set qname = `echo $fs | tr "/" "_"`
#
# Construct the quota filename.
if ( $tmpflag ) then
    set fname = $qname.$fext.TMP
else
    set fname = $qname.$fext
endif
set pname = $qpath/$fname
#
# Check for the existence of the quota file.
if ( ! -f $pname ) then
    echo "${name}: ERROR: no file $pname"
    exit 1
endif
#
# Define a lock file.
set lockfile = /var/lock/$name-$fname
#
# Check for a lock file.
if ( -f $lockfile ) then
    echo "${name}: this script is already running"
    exit 0
endif
#
# Make a lock file.
touch $lockfile
#
# Alias defining a macro for exiting cleanly.
alias cleanexit "\rm -f $lockfile >& /dev/null ; exit \!*"
#
# What to do on interrupts: do a clean exit.
onintr normalexit
#
# Put the whole text quota file, except headers,
# _ on a single record.
set frec = `cat $pname | grep -v "^[ $tab]*#"`
#
# The number of elements on the record.
set nc = $#frec
#
# The number of data lines in the quota file.
@ nl = $#frec / 5
#
# Print out an informative message.
if ( $proflag ) then
    if ( $nl == 1 ) then
	echo -n "/${fs}: there is $nl $fext to fix: "
    else
	echo -n "/${fs}: there are $nl ${fext}s to fix: "
    endif
endif
#
# Start a counter; inm is always the index of a name.
set inm = 1
#
# Loop over the elements.
while ( $inm <= $nc )
    #
    # Check whether the user or group exists in the system.
    #
    # The user case.
    if ( $qtype == u ) then
	#
	# The local case.
	grep "^${frec[$inm]}:" /etc/passwd >& /dev/null
	set stat1 = $status
	#
	# The NIS case.
	#
	# Check whether NIS is available.
	if ( -x /usr/bin/ypmatch ) then
	    ypmatch $frec[$inm] passwd >& /dev/null
	    set stat2 = $status
	else
	    set stat2 = 1
	endif
    #
    # The group case.
    else
	#
	# The local case.
	grep "^${frec[$inm]}:" /etc/group >& /dev/null
	set stat1 = $status
	#
	# The NIS case.
	#
	# Check whether NIS is available.
	if ( -x /usr/bin/ypmatch ) then
	    ypmatch $frec[$inm] group >& /dev/null
	    set stat2 = $status
	else
	    set stat2 = 1
	endif
    endif
    #
    # The user or group must be found somewhere; if not, then
    # _ write out a warning message and skip the entry.
    if ( $stat1 != 0 && $stat2 != 0 ) then 
	#
	# The user case.
	if ( $qtype == u ) then
	    echo ""
	    echo "${name}: warning: user $frec[$inm] does not exist in system"
	#
	# The group case.
	else
	    echo ""
	    echo "${name}: warning: group $frec[$inm] does not exist in system"
	endif
    else
	#
	# The soft block quota is the first element after the name.
	@ isb = $inm + 1
	#
	# The hard block quota is the second element after the name.
	@ ihb = $inm + 2
	#
	# The soft inode quota is the third element after the name.
	@ isi = $inm + 3
	#
	# The hard inode quota is the fourth element after the name.
	@ ihi = $inm + 4
	#
	# Print out some progress report.
	if ( $proflag ) then
	    echo -n "."
	endif
	#
	# Update the binary file of this filesystem.
	quotatool -$qtype $frec[$inm] \
	    -b -q $frec[$isb] -l $frec[$ihb] \
	    -i -q $frec[$isi] -l $frec[$ihi] /$fs
	#
	# If there is an error, exit cleanly.
	if ( $status != 0 ) then
	    cleanexit $status
	endif
	#
    endif
    #
    # Increment the counter to the next username.
    @ inm = $inm + 5
end
#
# Finish the progress-report output.
if ( $proflag ) then
    echo " done."
endif
#
# Normal exit: remove the lock file.
normalexit:
cleanexit 0
