All the News That Fits: Listings

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()

Print This Page


e-mail Send as e-mail

Research and Reports

Storage Virtualization Guide
May 2012

Network Computing: May 2012

TechWeb Careers