#!/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 and text quota files of the backup-home
# _ filesystem(s), doubling the data for the soft limits in the text file
# _ of the home filesystem and increasing the hard limits 20% over that.
#
# 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 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 "usage: $name [-C <config>] [-u|-g] [-t] [-q]"
	    echo "       -C: use alternate configuration file <config>"
	    echo "       -u: manipulate user quotas"
	    echo "       -g: manipulate group quotas"
	    echo "       -t: use the temporary input 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
	#
	# This script takes no arguments.
	else
	    #
	    # Print an error message.
	    echo "${name}: ERROR: takes no arguments"
	    exit 1
	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
#
# Source the configuration file; this must define the following variables:
# _ quotas_path; default_type; backup_flag; home_path; backup_root.
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    
#
# Set the automatic home backup flag.
set bflag = "$backup_flag"
#
# This program should operate only if the automatic
# _ home backup strategy is in effect.
if ( ! $bflag ) then
    echo "${name}: automatic home backup is not active"
    exit 0
endif
#
# Set the path the root of the backup tree; strip away
# _ any "/"'s at the extremes of the path.
set bpath = `echo "$backup_root" | sed -e 's|/\+$||g' -e 's|^/\+||g'`
#
# Define a lock file.
set lockfile = /var/lock/$name
#
# 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
#
# Loop over the path(s) to the home filesystem(s).
foreach hpath ( $home_path )
    #
    # Strip away any "/"'s at the extremes of the path.
    set hpath = `echo "$hpath" | sed -e 's|/\+$||g' -e 's|^/\+||g'`
    #
    # Set the name of the home filesystem.
    set fs = $hpath
    #
    # Give a warning about reseting all the quotas of the filesystem.
    if ( ! $tmpflag ) then
	echo "${name}: WARNING: text quota configuration file about to be"
	echo "modified; this will reset all quotas in the /$bpath/$fs"
	echo "filesystem, including the entries in its text configuration"
	echo "file, regardless of whether or not any entries have actually"
	echo "been modified in the text configuration file of the /$fs"
	echo "filesystem; in addition to this, all grace-period times will"
	echo -n "be reset to zero; are you sure you want to do this? [N]: "
	set idec = $<
	if ( "$idec" != y && "$idec" != Y ) goto continue
    endif
    #
    # Define the basic name of the home text quota file.
    set qname = `echo $fs | tr "/" "_"`
    #
    # Construct the corresponding 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 home quota file.
    if ( ! -f $pname ) then
	echo "${name}: ERROR: no file $pname"
	cleanexit 1
    endif
    #
    # Set the name of the backup-home filesystem.
    set bfs = $bpath/$hpath
    #
    # Define the basic name of the backup-home text quota file.
    set bqname = `echo $bfs | tr "/" "_"`
    #
    # Construct the corresponding quota filename.
    set bfname = $bqname.$fext
    set bpname = $qpath/$bfname
    #
    # Check for the existence of the backup-home quota file.
    if ( ! -f $bpname ) then
	echo "${name}: ERROR: no file $bpname"
	cleanexit 1
    endif
    #
    # Put the whole home 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 to /${bfs}: there is $nl $fext to fix: "
	else
	    echo -n "/$fs to /${bfs}: 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
	    #
	    # Fix the username.
	    if ( `echo -n $frec[$inm] | wc -c` < 8 ) then
		set quser = "$frec[$inm]$tab"
	    else
		set quser = $frec[$inm]
	    endif
	    #
	    # Double the soft quotas.
	    @ qsb = $frec[$isb] * 2
	    @ qsi = $frec[$isi] * 2
	    #
	    # Double the hard quotas.
	    @ qhb = $frec[$ihb] * 2
	    @ qhi = $frec[$ihi] * 2
	    #
	    # Add 20% more to the hard quotas.
	    @ qhb = $qhb + $qsb / 5
	    @ qhi = $qhi + $qsi / 5
	    #
	    # Update the text file of the backup-home filesystem.
	    #
	    # Make sure the grep search target ends with a space or a tab.
	    set suser = \'"$frec[$inm][ $tab]"\'
	    #
	    # Define the sed search text.
	    set st = "`grep ^$suser $bpname`"
	    #
	    # Check for a search error to avoid an error in sed later;
	    # _ that error could cause the loss of the target file.
	    if ( $status != 0 || "$st" == "" ) then
		echo -n "${name}: ERROR looking for ${fext}name"
		echo " $frec[$inm] in file $bpname"
		cleanexit 1
	    endif
	    #
	    # Define the sed replace text.
	    set rt = "$quser$tab$qsb$tab$tab$qhb$tab$tab$qsi$tab$tab$qhi"
	    #
	    # Use sed to edit the text quota file; note: do _not_
	    # _ use mv, in order not to change the soft links.
	    cat $bpname | sed -e "s|$st|$rt|g" >! $bpname.TMP
	    cp -pf $bpname.TMP $bpname
	    #
	    # Print out some progress report.
	    if ( $proflag ) then
		echo -n "."
	    endif
	    #
	    # Update the binary file of the backup-home filesystem.
	    quotatool -$qtype $frec[$inm] \
		-b -q $qsb -l $qhb \
		-i -q $qsi -l $qhi /$bfs
	    #
	    # If there is an error, exit cleanly with that error.
	    if ( $status != 0 ) then
		cleanexit $status
	    endif
	    #
	endif
	#
	# Increment the counter to the next username.
	@ inm = $inm + 5
    end
    #
    # Remove the temporary file.
    rm -f $bpname.TMP
    #
    # Finish the progress-report output.
    if ( $proflag ) then
	echo " done."
    endif
    #
    # A target to skip this iteration of the loop.
    continue:
    #
end
#
# Normal exit: remove the lock file.
normalexit:
cleanexit 0
