
Listing 1: An automatic article expiration
utility for C News.
A.
Listing of the autoexpire script:
1 #!/bin/sh
2 # @(#) autoexpire Manage C News expiration schedule automatically
3 # Author: "James R. Hamilton" <jrh@jrh.guild.org> (1993.02.21)
4 # Last modified by Becca Thomas, May 1994
5 #
6 # Depends on C News "spacefor <filesize> archive" command, which
7 # returns how many files of <filesize> bytes can fit in news spool.
8 # This script must be run under the news administrative account.
9
10 # Configuration section:
11 minFreeSpace=40m # Free space low-water mark to trigger expiration.
12 maxFreeSpace=60m # Free space high-water mark to stop expiration.
13 maxDays=30 # Max expiration period.
14 minDays=3 # Min expiration period.
15
16 # Set variables defined in the C News configuration file:
17 . ${NEWSCONFIG-/usr/lib/news/bin/config}
18
19 # Define IFS and command search path for better security:
20 IFS="
21 " # Space, tab, newline between quotes.
22 PATH="/bin:/usr/bin:$NEWSBIN:$NEWSBIN/expire:/usr/ucb:/usr/local/bin"
23
24 # func KandMtoUnits() converts number[kK], number[mM] to number units
25 KandMtoUnits() {
26 numeric_part=`echo $1|sed 's/[kKmM]//'`
27 case "$1" in
28 [0-9]*[Kk]) result=`expr $numeric_part \* 1024` ;;
29 [0-9]*[Mm]) result=`expr $numeric_part \* 1048576` ;;
30 [0-9]*) result=$1 ;;
31 *) result="-1" ;; # Unrecognized
32 esac
33 echo $result
34 } # end of function KandMtoUnits()
35
36 # func ErrorExit() sends argument string to news admin and exits
37 ErrorExit() {
38 echo "$*" | mail $NEWSMASTER
39 exit 100 # failure code returned.
40 } # end of function ErrorExit()
41
42 # func ChgNewsExp() changes the "all" entry in the expire control file
43 ChgNewsExp() {
44 expDelta="$1" # Get expire change (n or -n).
45 # Bracketed expressions ([ ]) contain a tab and a space:
46 set -- `grep "^all[ ]" <explist 2>&1`
47 [ $? != 0 ] && ErrorExit "
48 ERROR: Autoexpire unable to find the explist file
49 or the file doesn't have an \"all\" field."
50 Expiry=$3
51 # Parse the Expiry variable, which contains Y, Y-Z, or X-Y-Z):
52 oldIFS="$IFS" # Save for later restoration
53 IFS='-' # Will split at "-"
54 set $Expiry # Place Expiry elements in posn. parameters
55 IFS="$oldIFS" # Restore IFS
56 case $# in
57 1) curExp="$1" ;;
58 2) curExp="$1"; Purge="-$2" ;;
59 3) Retent="$1-"; curExp="$2"; Purge="-$3" ;;
60 esac
61
62 newExp=`expr $curExp + $expDelta`
63
64 # if increasing expiration and already at or above maxdays, quit.
65 [ "$expDelta" -gt 0 ] && [ "$newExp" -gt "$maxDays" ] && exit 0
66
67 # If reducing expiration and already at or below minDays, complain.
68 if [ "$expDelta" -lt 0 ] && [ "$newExp" -lt "$minDays" ]; then
69 ErrorExit "
70 URGENT: Autoexpire unable to reduce the expiration
71 period further and the news spool space is nearly full."
72 else # Bracketed expressions ([ ]) contain a tab and a space:
73 sed "s/^\(all[ ]*.[ ]*\)$Expiry/\1$Retent$newExp$Purge/" \
74 <explist >explist.$$
75 if [ $? -ne 0 ]; then ErrorExit "
76 ERROR: Unable to edit $NEWSBIN/explist."
77 else
78 cp explist.$$ explist && rm explist.$$
79 [ $? -ne 0 ] && ErrorExit "
80 ERROR: Can't rename explist.$$ to explist."
81 fi
82 fi
83 } # End of function ChgNewsExp()
84
85 # Main program begins ...
86 cd $NEWSCTL
87 minBytesFree=`KandMtoUnits $minFreeSpace`
88 maxBytesFree=`KandMtoUnits $maxFreeSpace`
89
90 if [ `spacefor $minBytesFree archive` -lt 1 ]; then
91 doexpire
92 if [ `spacefor $minBytesFree archive` -lt 1 ]; then
93 ChgNewsExp -1 # Reduce expiration period.
94 doexpire
95 fi
96 else
97 changedToday=`find explist -mtime -1 -print`
98 [ -z "$changedToday" ] && ChgNewsExp 1 # incr expiration period.
99 fi
100 exit 0
B. Sample ``all'' field entry.
all x 5-10-30 -
C. Using df to display the
free blocks and inodes on an SVR4.0.3 system:
$ df $NEWSARTS
/usr/spool/news (/dev/dsk/1s1 ): 76 blocks 7835 files
$ []
D. Script fragments modified to monitor
free inodes as well as free disk space for a system whose
df command operates as shown in Part C:
Add to configuration section:
minInodes=20k # Minimum number of inodes free.
Add this function definition, which is designed for the df
output format shown in Part C:
# func GetFreeCounts sets the freeBytes and freeInodes variables
# ALERT: Non-portable function; change as necessary for your system
GetFreeCounts() {
set -- `df $NEWSARTS`
freeBytes=`expr $4 \* 512` ; freeInodes=$6
}
New main program:
# Main program begins ...
cd $NEWSCTL
minBytesFree=`KandMtoUnits $minFreeSpace`
maxBytesFree=`KandMtoUnits $maxFreeSpace`
minInodes=`KandMtoUnits $minInodes`
GetFreeCounts # Sets freeBytes and freeInodes values
if [ $freeBytes -lt $minBytesFree ] || [ $freeInodes -lt $minInodes ]; then
doexpire # Free up disk resources
GetFreeCounts # Sets freeBytes and freeInodes values
if [ $freeBytes -lt $minBytesFree ]||[ $freeInodes -lt $minInodes ]; then
ChgNewsExp -1 # Reduce expiration period.
doexpire # At first you don't succeed, try again
fi
else
changedToday=`find explist -mtime -1 -print`
[ -z "$changedToday" ] && ChgNewsExp 1 # increase expiration period
fi
exit 0
E. Script fragments modified to monitor
individual newsgroups as well as the ``all'' expiration-control
file entry:
Add this code at the beginning of the program:
Status=0 # Default exit status (success)
# Set traps to announce signal receipt; erase temporary files:
trap 'echo "Interrupted..."; exit' 1 2 3 15
trap 'echo "Exiting..."; rm -f explist.$$ $var_set_file; exit $Status' 0
Add this variable to the Configuration section:
var_set_file=/tmp/autoexp.$$ # Redirected while-loop variable definition.
Add these two function definitions:
# func ParseExpiry() Parses the expiry (third) field of
# expiration-control file entry, placing subfield values in variables
ParseExpiry() {
Entry=$1
set -- $Entry # Place fields of argument into positional parameters
[ $# != 4 ] && ErrorExit "
Corrupted expiration-control file line: $Entry"
Fld1=$1 ; Fld2=$2 ; Expiry=$3 ; Fld4=$4
# Parse the Expiry variable, which contains E, E-P, or R-E-P):
Retent="" ; Purge="" # Reset from last usage
oldIFS="$IFS" # Save for later restoration
IFS='-' # Will split at "-"
set -- $Expiry # Place Expiry elements in positional parameters
IFS="$oldIFS" # Restore IFS
case $# in
1) curExp="$1" ;;
2) curExp="$1"; Purge="-$2" ;;
3) Retent="$1-"; curExp="$2"; Purge="-$3" ;;
esac
}
# func ChgNewsExp() Update expiration-control file entries:
ChgNewsExp() {
expDelta="$1" # save expire change (1 or -1)
echo "Changed=F" > $var_set_file # assume can't change
while read Line ; do # examine explist file lines
if echo $Line | egrep '^#|^$|^/expired/' >/dev/null; then
echo $Line # write out unchanged
elif echo $Line | grep '^/bounds/' >/dev/null; then
ParseExpiry "$Line" # get "bounds" Expiry values
defRetent=$Retent # save default retention value
echo $Line # but write line unchanged
else # Reconstruct a newsgroup or "all" entry line:
ParseExpiry "$Line"
if [ "$curExp" = "never" ]; then
echo "$Fld1\t$Fld2\t$Expiry\t$Fld4" # No change allowed
else
newExp=`expr $curExp + $expDelta` # new expirn value
Changed="T" # Will be changed
# Check against minDays, explicit, default retention:
if [ $newExp -lt $minDays ]; then # below low-water?
newExp=$minDays # don't decrease further
Changed="F" # not changed afterall
elif [ -n "$Retent" ]; then # explicit retention value?
chkRet=`echo $Retent | sed 's/-$//'` # remove -
if [ $newExp -lt $chkRet ]; then # below value?
newExp=$chkRet # don't decrease further
Changed="F" # not changed afterall
fi
elif [ -n "$defRetent" ]; then # default retent value?
chkRet=`echo $defRetent | sed 's/-$//'` # remove -
if [ $newExp -lt $chkRet ]; then # below value
newExp=$chkRet # don't decrease further
Changed="F" # not changed afterall
fi
fi
[ "$Changed" = "T" ] && echo "Changed=T" >$var_set_file
# Write out (possibly) adjusted line:
echo "$Fld1\t$Fld2\t$Retent$newExp$Purge\t$Fld4"
fi
fi
done <explist >explist.$$ # intermediate file
[ -s explist.$$ ] || ErrorExit "
Exiting ... autoexpire didn't create intermediate
expiration control file (explist.$$)."
cp explist.$$ explist # update expiration-control file
# If increasing expiration and already at or above maxdays, quit.
[ "$expDelta" -gt 0 ] && [ "$newExp" -gt "$maxDays" ] && exit 0
. $var_set_file # get "Changed" variable definition
# If reducing expiration, but couldn't change any entries:
[ "$expDelta" -lt 0 ] && [ "$Changed" = "F" ] &&
ErrorExit "
Autoexpire unable to reduce any expiration
periods further and the news spool space is nearly full."
} # End of function ChgNewsExp()
|