home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-04-02 | 33.4 KB | 1,170 lines |
- Newsgroups: alt.sources
- From: admerlev@immd4.informatik.uni-erlangen.de (Arnd Merlevede)
- Subject: Re: reap(8): expire news as space needed
- Message-ID: <1991Apr1.190028.14519@informatik.uni-erlangen.de>
- Date: Mon, 1 Apr 1991 19:00:28 GMT
-
- dt@yenta.alb.nm.us (David B. Thomas) writes:
-
- hallo andreas, vielleicht interessiert Dich
- die follgende Msg falls Dus nicht selbst gelesen hast.
-
- Uebrigns, liegt noch die Source von nn irgendwo ?
- Und ist des schwer die zu installieren ? Ich wuerd sie gerne
- im ET-CipPool installieren (ala faui09)
- ?
- Bis denn Arnd
-
-
- >This message contains the README, followed by the source:
-
- >README for reap version 1.1 by David B. Thomas (dt@yenta.alb.nm.us).
-
- >A Problem:
- > News volume fluctuates wildly...sites with small disks must either
- >expire aggresively, often deleting more than necessary, or worry that an
- >unexpected huge dose of news might overfill the disk.
-
-
- >A Solution:
- > Implement a tool that expires according to a user-defined scheme
- >until sufficient freespace is reclaimed, then stops, leaving as much
- >juicy news online as is feasible. Reap does this.
-
-
- >Expire Does Two Jobs:
- > Both Bnews and Cnews expires really do two jobs:
- > 1. trim history files
- > 2. delete outdated articles
- >Thanks to some inspired jootsing (acronym for "jumping out of the system")
- >by Mike Murphy (mrm@sceard.com) and others, it is more than possible to
- >separate those two functions. This is, of course, in keeping with the
- >unix philosophy of one tool doing one job well!
-
-
- >What Reap Does:
- > Reap only takes care of the second job: deleting old articles.
- >It works by checking freespace, and processing one line at a time from a
- >list of expire functions, until the desired freespace is attained.
- >Each expire function consists of an age limit in days (decimals okay)
- >and a list of newsgroups to process or not process, sys file style. Ex:
-
- > .5 alt.sex.pictures,talk,!talk.bizarre,junk
- > 1 rec,!rec.games,!rec.humor
-
- >This example would check freespace, and if more space is needed, expire
- >to .5 days everything in alt.sex.pictures, talk (except for talk.bizarre)
- >and junk. Then it would stop and check freespace again. If still more
- >space is needed, it would expire to 1 day everything in rec except
- >rec.games.* and rec.humor.*. It's that simple.
-
-
- >Okay...So How Do I Arrange To Trim The History Files, Since Reap Can't:
- > Included in this distribution is a shell script (mostly written
- >by Mike Murphy) to handle Cnews history files. It shouldn't be too
- >difficult to do something similar for Bnews, or you can give in and use
- >the original expire utility with options that tell it to expire the
- >history files only...but I think this will be slow. It just comes down
- >to removing lines from ordinary text files, based on their contents.
- >Murphy and I used awk.
-
-
- >But Is It Fast:
- > Yes, largely because it doesn't have to do much. Even "find | rm"
- >is slower because find is repeatedly exec-ing rm. "rm -rf" has me beat,
- >though, I'll bet! :-)
-
- > Since the functions of deleting articles and trimming history
- >are separate, I now run reap every six hours, but trim the history list
- >just once a day. That effectively keeps my disk space up to snuff, but
- >only thrashes at the history file in the middle of the night.
-
-
- >Credits:
- > I owe a lot to Mike Murphy for inspiring me with his "trasher"
- >system. I also owe a lot to all of your netters who will flood me with
- >more suggestions and improvements in the coming weeks (hint, hint!).
-
- > little david
- > dt@yenta.alb.nm.us
-
- >ps - reap is freeware. No strings(1) attached.
-
-
- >#!/bin/sh
- ># This is a shell archive (shar 3.44)
- ># made 03/28/1991 02:51 UTC by dt@yenta
- ># Source directory /u/dt/src/reap
- >#
- ># existing files will NOT be overwritten unless -c is specified
- >#
- ># This shar contains:
- ># length mode name
- ># ------ ---------- ------------------------------------------
- ># 934 -rw-rw-r-- Install
- ># 339 -rw-rw-r-- MANIFEST
- ># 900 -rw-rw-r-- Makefile
- ># 2918 -rw-rw-r-- README
- ># 969 -rwxrwxr-x exphist
- ># 3567 -rw-rw-r-- lib.c
- ># 1611 -rw-rw-r-- list.sample
- ># 2497 -rw-rw-r-- main.c
- ># 6129 -rw-r--r-- reap.8
- ># 2845 -rw-rw-r-- reap.c
- ># 1195 -rw-rw-r-- reap.h
- >#
- ># ============= Install ==============
- >if test -f 'Install' -a X"$1" != X"-c"; then
- > echo 'x - skipping Install (File already exists)'
- >else
- >echo 'x - extracting Install (Text)'
- >sed 's/^X//' << 'SHAR_EOF' > 'Install' &&
- >X
- >To install:
- >X
- >1. Edit tops of Makefile and reap.h to fit your system.
- >X [If you are installing this on a non-system-V machine, you will need
- >X to rewrite the freeblox() function at the top of lib.c. This should
- >X be very easy. Please email your working mods to me.]
- >2. make
- >3. Compose a sample function list file or use the sample provided to
- >X test reap (use the -n option to avoid really removing files).
- >4. su and make install.
- >5. Arrange to trim your news system's history list regularly. If you have
- >X Cnews, try the "exphist" script provided, run from cron. That
- >X script requires that a tiny file, /usr/lib/news/histdays, containing
- >X the number of days of history data to keep, or else you can hardcode
- >X in your favorite number. If you have Bnews, I don't have a nifty
- >X suggestion, other than using expire(8) with a ridiculously long
- >X article expire time, but a sane history expire time.
- >6. Arrange to run reap from cron.
- >SHAR_EOF
- >chmod 0664 Install ||
- >echo 'restore of Install failed'
- >Wc_c="`wc -c < 'Install'`"
- >test 934 -eq "$Wc_c" ||
- > echo 'Install: original size 934, current size' "$Wc_c"
- >fi
- ># ============= MANIFEST ==============
- >if test -f 'MANIFEST' -a X"$1" != X"-c"; then
- > echo 'x - skipping MANIFEST (File already exists)'
- >else
- >echo 'x - extracting MANIFEST (Text)'
- >sed 's/^X//' << 'SHAR_EOF' > 'MANIFEST' &&
- >Included with this distribution are:
- >X
- >README - general description and credits
- >Install - hints on how to install reap and get it going
- >Xexphist - history trimmer utility for Cnews
- >list.sample - sample function script file for reap
- >reap.8 - man page
- >lib.c - source
- >main.c - source
- >reap.c - source
- >reap.h - source
- >Makefile - makefile
- >SHAR_EOF
- >chmod 0664 MANIFEST ||
- >echo 'restore of MANIFEST failed'
- >Wc_c="`wc -c < 'MANIFEST'`"
- >test 339 -eq "$Wc_c" ||
- > echo 'MANIFEST: original size 339, current size' "$Wc_c"
- >fi
- ># ============= Makefile ==============
- >if test -f 'Makefile' -a X"$1" != X"-c"; then
- > echo 'x - skipping Makefile (File already exists)'
- >else
- >echo 'x - extracting Makefile (Text)'
- >sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
- >#----------------------------
- ># parameters for installation
- >#----------------------------
- >X
- ># directories where manual and executable are to be installed
- >BINDIR = /usr/lib/newsbin/expire
- >MANDIR = /usr/man/man8
- >X
- ># owner, group and file mode for manual and executable
- >EXEOWNER = bin
- >EXEGROUP = bin
- >EXEMODE = 775
- >MANOWNER = bin
- >MANGROUP = bin
- >MANMODE = 664
- >X
- >X
- ># your favorite C compiler
- >#CC = cc
- >CC = shcc
- >X
- ># directory access functions library, if not in standard C library.
- >LIB = -ldirent
- >X
- >X
- >#-------------
- ># boring stuff
- >#-------------
- >X
- >OBJ = main.o lib.o reap.o
- >X
- >reap: $(OBJ)
- >X $(CC) -s -o reap $(SHLIB) $(OBJ) $(LIB)
- >X
- >$(OBJ): reap.h
- >X
- >install: reap reap.8
- >X cp reap $(BINDIR)
- >X chown $(EXEOWNER) $(BINDIR)/reap
- >X chgrp $(EXEGROUP) $(BINDIR)/reap
- >X chmod $(EXEMODE) $(BINDIR)/reap
- >X cp reap.8 $(MANDIR)
- >X chmod $(MANMODE) $(MANDIR)/reap.8
- >X chown $(MANOWNER) $(MANDIR)/reap.8
- >X chgrp $(MANGROUP) $(MANDIR)/reap.8
- >SHAR_EOF
- >chmod 0664 Makefile ||
- >echo 'restore of Makefile failed'
- >Wc_c="`wc -c < 'Makefile'`"
- >test 900 -eq "$Wc_c" ||
- > echo 'Makefile: original size 900, current size' "$Wc_c"
- >fi
- ># ============= README ==============
- >if test -f 'README' -a X"$1" != X"-c"; then
- > echo 'x - skipping README (File already exists)'
- >else
- >echo 'x - extracting README (Text)'
- >sed 's/^X//' << 'SHAR_EOF' > 'README' &&
- >X
- >README for reap version 1.1 by David B. Thomas (dt@yenta.alb.nm.us).
- >X
- >A Problem:
- >X News volume fluctuates wildly...sites with small disks must either
- >Xexpire aggresively, often deleting more than necessary, or worry that an
- >unexpected huge dose of news might overfill the disk.
- >X
- >X
- >A Solution:
- >X Implement a tool that expires according to a user-defined scheme
- >until sufficient freespace is reclaimed, then stops, leaving as much
- >juicy news online as is feasible. Reap does this.
- >X
- >X
- >Expire Does Two Jobs:
- >X Both Bnews and Cnews expires really do two jobs:
- >X 1. trim history files
- >X 2. delete outdated articles
- >Thanks to some inspired jootsing (acronym for "jumping out of the system")
- >by Mike Murphy (mrm@sceard.com) and others, it is more than possible to
- >separate those two functions. This is, of course, in keeping with the
- >unix philosophy of one tool doing one job well!
- >X
- >X
- >What Reap Does:
- >X Reap only takes care of the second job: deleting old articles.
- >It works by checking freespace, and processing one line at a time from a
- >list of expire functions, until the desired freespace is attained.
- >Each expire function consists of an age limit in days (decimals okay)
- >and a list of newsgroups to process or not process, sys file style. Ex:
- >X
- >X .5 alt.sex.pictures,talk,!talk.bizarre,junk
- >X 1 rec,!rec.games,!rec.humor
- >X
- >This example would check freespace, and if more space is needed, expire
- >to .5 days everything in alt.sex.pictures, talk (except for talk.bizarre)
- >and junk. Then it would stop and check freespace again. If still more
- >space is needed, it would expire to 1 day everything in rec except
- >rec.games.* and rec.humor.*. It's that simple.
- >X
- >X
- >Okay...So How Do I Arrange To Trim The History Files, Since Reap Can't:
- >X Included in this distribution is a shell script (mostly written
- >by Mike Murphy) to handle Cnews history files. It shouldn't be too
- >difficult to do something similar for Bnews, or you can give in and use
- >the original expire utility with options that tell it to expire the
- >history files only...but I think this will be slow. It just comes down
- >to removing lines from ordinary text files, based on their contents.
- >Murphy and I used awk.
- >X
- >X
- >But Is It Fast:
- >X Yes, largely because it doesn't have to do much. Even "find | rm"
- >is slower because find is repeatedly exec-ing rm. "rm -rf" has me beat,
- >though, I'll bet! :-)
- >X
- >X Since the functions of deleting articles and trimming history
- >are separate, I now run reap every six hours, but trim the history list
- >just once a day. That effectively keeps my disk space up to snuff, but
- >only thrashes at the history file in the middle of the night.
- >X
- >X
- >Credits:
- >X I owe a lot to Mike Murphy for inspiring me with his "trasher"
- >system. I also owe a lot to all of your netters who will flood me with
- >more suggestions and improvements in the coming weeks (hint, hint!).
- >X
- >X little david
- >X dt@yenta.alb.nm.us
- >X
- >ps - reap is freeware. No strings(1) attached.
- >SHAR_EOF
- >chmod 0664 README ||
- >echo 'restore of README failed'
- >Wc_c="`wc -c < 'README'`"
- >test 2918 -eq "$Wc_c" ||
- > echo 'README: original size 2918, current size' "$Wc_c"
- >fi
- ># ============= exphist ==============
- >if test -f 'exphist' -a X"$1" != X"-c"; then
- > echo 'x - skipping exphist (File already exists)'
- >else
- >echo 'x - extracting exphist (Text)'
- >sed 's/^X//' << 'SHAR_EOF' > 'exphist' &&
- >#! /bin/sh
- ># exphist - expire history file
- >X
- ># =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
- >. ${NEWSCONFIG-/usr/lib/news/bin/config}
- >X
- >PATH=$NEWSCTL/bin:$NEWSBIN/expire:$NEWSBIN:$NEWSPATH ; export PATH
- >umask $NEWSUMASK
- >X
- >days=`cat /usr/lib/news/histdays`
- >X
- >lock="$NEWSCTL/LOCKexpire"
- >ltemp="$NEWSCTL/L.$$"
- >Xecho $$ >$ltemp
- >trap "rm -f $ltemp ; exit 0" 0 1 2 15
- >if newslock $ltemp $lock
- >then
- >X trap "rm -f $ltemp $lock ; exit 0" 0 1 2 15
- >Xelse
- >X echo "$0: expire apparently already running" | mail "$NEWSMASTER"
- >X exit 1
- >fi
- >X
- >cd $NEWSCTL
- >rm -f history.n history.n.pag history.n.dir
- >now=`getdate now`
- >age=`expr 86400 \* $days`
- >ago=`expr $now - $age`
- >awk "{split(\$2,dates,\"~\");if(dates[1]>$ago)print \$0}" history >history.n
- >mkdbm history.n
- >[ -s history.n ] &&
- >mv history history.o && # install new ASCII history file
- >mv history.n history &&
- >rm -f history.pag && # and related dbm files
- >rm -f history.dir &&
- >mv history.n.pag history.pag &&
- >mv history.n.dir history.dir
- >Xexit 0
- >SHAR_EOF
- >chmod 0775 exphist ||
- >echo 'restore of exphist failed'
- >Wc_c="`wc -c < 'exphist'`"
- >test 969 -eq "$Wc_c" ||
- > echo 'exphist: original size 969, current size' "$Wc_c"
- >fi
- ># ============= lib.c ==============
- >if test -f 'lib.c' -a X"$1" != X"-c"; then
- > echo 'x - skipping lib.c (File already exists)'
- >else
- >echo 'x - extracting lib.c (Text)'
- >sed 's/^X//' << 'SHAR_EOF' > 'lib.c' &&
- >X
- >/*
- >X * lib.c
- >X * subroutines needed by reap utility
- >X */
- >X
- >#include "reap.h"
- >X
- >/*
- >X * freeblox(devno)
- >X *
- >X * THIS WILL REQUIRE MODIFICATION TO WORK UNDER NON-SYSTEM-V UNIX.
- >X * IT SHOULD BE EASY. PLEASE EMAIL WORKING MODS TO THE AUTHOR:
- >X * dt@yenta.alb.nm.us
- >X *
- >X * assuming devno is the device number of a file system,
- >X * this function returns the free space on that file system,
- >X * in blocks (whatever that means for that filesystem) as an int.
- >X *
- >X */
- >X
- >freeblox(devno)
- >int devno;
- >{
- >X static struct ustat ust;
- >X
- >X if (ustat(devno, &ust))
- >X ouch ("%s: ustat() failed\n");
- >X
- >X return (ust.f_tfree);
- >X
- >} /* freeblox() */
- >X
- >X
- >X
- >X
- >/*
- >X * parse(cmd)
- >X * execute a line from the script file
- >X *
- >X * valid command lines:
- >X * a blank line is ignored
- >X * # comment (ignored)
- >X * days filespecs
- >X *
- >X * filespecs is a comma separated list of any combination of the following:
- >X * 1. a directory (newsgroup) to include, without recursion.
- >X * ex: alt.sources.
- >X * 2. a directory to include, recursively.
- >X * ex: alt.sources
- >X * 3. a directory to exclude, without recursion.
- >X * ex: !alt.sex.
- >X * 4. a directory to exclude, recursively.
- >X * ex: !alt.sex
- >X */
- >X
- >parse(cmd)
- >char *cmd;
- >{
- >X register int l;
- >X int recurseflag;
- >X double days;
- >X char *t,
- >X *p,
- >X *q,
- >X *seps = ",\n ";
- >X
- >X
- >/* skip initial whitespace */
- >X p = cmd;
- >X while (isspace(*p))
- >X ++p;
- >X
- >/* ignore blank lines or comments */
- >X if (*p == '\0' || *p == '#')
- >X return(1);
- >X
- >/* read the expire time from the line as a floating point number,
- >X * then figure out what the timestamp on a file that old would be */
- >X age = now - (time_t) (atof(p) * SECINDAY);
- >X
- >/* skip ahead to the filespec list */
- >X while (!isspace(*p))
- >X ++p;
- >X while (isspace(*p))
- >X ++p;
- >X
- >/* initialize exclusion list to null list */
- >X preclude();
- >X
- >/* for each filespec in list */
- >X for (t = strtok(p, seps); t; t = strtok(NULL, seps)) {
- >X
- >X /* forbid starting with a slash */
- >X if (*t == '/')
- >X *t = '.';
- >X
- >X /* change dots to slashes except in column 1 */
- >X while ( (q = strchr(t+1,'.')) != NULL)
- >X *q = '/';
- >X
- >X /* for final dot or slash, remove it, and shut off recursion */
- >X recurseflag = 1;
- >X if (t[l = (strlen(t) - 1)] == '/') {
- >X recurseflag = 0;
- >X t[l] = '\0';
- >X }
- >X
- >X if (*t == '!')
- >X exclude (t+1, recurseflag);
- >X else
- >X include (t, recurseflag);
- >X }
- >X
- >X reap();
- >X
- >X return (0);
- >X
- >} /* parse() */
- >X
- >X
- >X
- >/*
- >X * newnode,exclude, include, preclude
- >X *
- >X * functions to maintain global linked lists:
- >X * incl include this path in list of dirs to reap
- >X * excl leave out this directory
- >X (each entry can be recursive or not)
- >X *
- >X * the functions are:
- >X * include (text,rflag) add to incl list
- >X * exclude (text,rflag) add to excl list
- >X * preclude() clear both lists
- >X */
- >struct filspec *
- >newnode(text)
- >char *text;
- >{
- >X struct filspec *f;
- >X
- >X if ( (f = (struct filspec *) malloc (sizeof(struct filspec))) == NULL ||
- >X (f->name = malloc (strlen(text)+1)) == NULL)
- >X ouch ("%s: out of memory\n");
- >X
- >X strcpy (f->name, text);
- >X return (f);
- >}
- >Xexclude(text, rflag)
- >char *text;
- >int rflag;
- >{
- >X struct filspec *f;
- >X
- >X f = newnode(text);
- >X f->recurse = rflag;
- >X f->next = excl;
- >X excl = f;
- >}
- >include(text, rflag)
- >char *text;
- >int rflag;
- >{
- >X struct filspec *f;
- >X
- >X f = newnode(text);
- >X f->recurse = rflag;
- >X f->next = incl;
- >X incl = f;
- >}
- >preclude()
- >{
- >X struct filspec *p;
- >X
- >X while (incl != NULL) {
- >X p = incl;
- >X incl = incl->next;
- >X free (p->name);
- >X free (p);
- >X }
- >X while (excl != NULL) {
- >X p = excl;
- >X excl = excl->next;
- >X free (p->name);
- >X free (p);
- >X }
- >}
- >X
- >X
- >/*
- >X * ouch(fmt, arg)
- >X * outputs an error message and exits with error status
- >X */
- >X
- >ouch (fmt,arg)
- >char *fmt, *arg;
- >{
- >X fprintf (stderr, fmt, progname, arg);
- >X exit (-1);
- >}
- >SHAR_EOF
- >chmod 0664 lib.c ||
- >echo 'restore of lib.c failed'
- >Wc_c="`wc -c < 'lib.c'`"
- >test 3567 -eq "$Wc_c" ||
- > echo 'lib.c: original size 3567, current size' "$Wc_c"
- >fi
- ># ============= list.sample ==============
- >if test -f 'list.sample' -a X"$1" != X"-c"; then
- > echo 'x - skipping list.sample (File already exists)'
- >else
- >echo 'x - extracting list.sample (Text)'
- >sed 's/^X//' << 'SHAR_EOF' > 'list.sample' &&
- ># yenta's /usr/lib/news/reaplist function script file.
- >.1 junk,alt.flame,control,comp.binaries,alt.sex.pictures.,alt.fractals.pictures
- >.1 alt.desert-storm,alt.desert-shield,soc.motss,soc.culture
- >1 soc.singles,alt.activism,alt.romance.chat
- >.5 talk
- >1 sci,!sci.skeptic
- >2 sci.skeptic
- >.5 comp.text,comp.sys.atari,comp.windows,comp.os.vms
- >.5 comp.unix.sysv386
- >.5 misc.jobs,misc.handicap
- >2 soc,!soc.singles,!soc.motss,!soc.culture
- >.5 rec,!rec.arts.anime,!rec.arts.animation,!rec.arts.movies,!rec.games.hack,!rec.radio.amateur,!rec.autos,!rec.arts.tv,!rec.audio,!rec.video,!rec.music,!rec.skydiving
- >1 rec.music,!rec.music.synth
- >3 rec.music.synth,rec.skydiving
- >2 alt.tv
- >2 rec.arts.anime,rec.arts.animation,rec.arts.movies,rec.radio.amateur,rec.autos,rec.arts.tv,rec.audio,rec.video
- >3 rec.games.hack
- >1 misc.headlines,misc.consumers,misc.kids,misc.legal
- >1 alt.sex,!alt.sex.bondage,!alt.sex.pictures.
- >1.5 comp,!comp.dcom.telecom,!comp.binaries,!comp.text,!comp.sys.atari,!comp.windows,!comp.os.vms,!comp.sys.att,!comp.sys.3b1,!comp.sources.3b1
- >3 comp.dcom.telecom
- >1 comp.binaries
- >1 alt.sources
- >1 news,!news.announce.newusers
- >3 biz
- >3 misc
- >3 alt,!alt.sources,!alt.tv,!alt.desert-shield,!alt.activism,!alt.fractals.pictures,!alt.desert-storm,!alt.romance.chat
- >3 comp.sys.att
- >5 comp.sys.3b1
- >5 comp.sources.3b1
- >7 general
- ># up to here is "normal expire"... now let's get desparate
- >.1 alt.sex.pictures
- >.1 rec.arts.anime,rec.arts.animation,rec.arts.movies,rec.ham-radio,rec.autos,rec.arts.tv,rec.audio,rec.video
- >.1 biz
- >.1 talk
- >.1 news
- >.1 soc
- >.1 sci
- >.1 comp
- >.1 alt
- >.1 misc
- ># if we got here, we're in big trouble -- wipe it all!
- >0 .
- >SHAR_EOF
- >chmod 0664 list.sample ||
- >echo 'restore of list.sample failed'
- >Wc_c="`wc -c < 'list.sample'`"
- >test 1611 -eq "$Wc_c" ||
- > echo 'list.sample: original size 1611, current size' "$Wc_c"
- >fi
- ># ============= main.c ==============
- >if test -f 'main.c' -a X"$1" != X"-c"; then
- > echo 'x - skipping main.c (File already exists)'
- >else
- >echo 'x - extracting main.c (Text)'
- >sed 's/^X//' << 'SHAR_EOF' > 'main.c' &&
- >X
- >/*
- >X * main.c
- >X * main routine and globals for reap utility, version 1.1
- >X */
- >X
- >X
- >#include "reap.h"
- >X
- >X
- >/* linked lists for included and excluded file specs */
- >struct filspec
- >X *incl = NULL,
- >X *excl = NULL
- >;
- >char
- >X *scriptfile = SCRIPT, /* path of function script */
- >X *progname, /* argv[0] for errors */
- >X *newsdir = NEWSDIR /* news root directory */
- >;
- >int
- >X verbose = 0, /* verbosity (-v) flag */
- >X dryrun = 0 /* do-not-unlink (-n) flag */
- >;
- >time_t
- >X age, /* unlink files older than this */
- >X now /* current time */
- >;
- >X
- >X
- >/************************
- >X * MAIN FUNCTION *
- >X ************************/
- >X
- >main(argc, argv)
- >int argc;
- >char *argv[];
- >{
- >X int device, /* device # containing newsdir */
- >X c,
- >X lineno = 0,
- >X summary = 0,
- >X thenfree,
- >X errflag = 0;
- >X long wantblox; /* desired free space */
- >X char *p;
- >X static char line[MAXLINE];
- >X FILE *script; /* file ptr for function script */
- >X struct stat st;
- >X
- >X
- >/* save argv[0] for error spewings */
- >X progname = argv[0];
- >X
- >/* parse args */
- >X while ( (c=getopt(argc,argv,"vsnf:")) != EOF)
- >X switch(c) {
- >X case 'n':
- >X ++dryrun;
- >X break;
- >X case 'v':
- >X ++verbose;
- >X break;
- >X case 'f':
- >X scriptfile = optarg;
- >X break;
- >X case 's':
- >X ++summary;
- >X break;
- >X default:
- >X ++errflag;
- >X break;
- >X }
- >X
- >X if (argc - optind != 1 ||
- >X sscanf(argv[optind], "%ld", &wantblox) != 1 )
- >X ++errflag;
- >X
- >X if (errflag) {
- >X fprintf (stderr,
- >X "usage: %s [-v] [-s] [-n] [-f funclist] freeblocks\n",
- >X progname);
- >X exit (-1);
- >X }
- >X
- >X
- >/* stat newsdir to find the number of the device it's on */
- >X if (stat(newsdir, &st))
- >X ouch ("%s: can't stat %s\n", newsdir);
- >X device = st.st_dev;
- >X
- >/* open function script file for reading */
- >X if ( (script = fopen (scriptfile, "r")) == NULL)
- >X ouch ("%s: can't read %s\n", scriptfile);
- >X
- >/* Record the current time, for deciding what gets the axe. */
- >X time (&now);
- >X
- >/* chdir to newsdir */
- >X chdir (newsdir);
- >X
- >/* record initial freespace if summary is desired */
- >X if (summary)
- >X thenfree = freeblox(device);
- >X
- >/* main loop ... process until goal reached or end of script */
- >X
- >X while (freeblox(device) < wantblox &&
- >X (p = fgets (line, MAXLINE, script)) != NULL )
- >X parse (line), ++lineno;
- >X
- >X fclose (script);
- >X
- >X if (summary) {
- >X c = freeblox(device);
- >X printf ("Freespace was %d, now %d. Cleared %d.\n",
- >X thenfree, c, c - thenfree);
- >X printf ("Stopped after line %d in %s\n", lineno,
- >X scriptfile);
- >X }
- >X
- >/* return 0 if freespace goal was met at exit, 1 if not */
- >X exit (freeblox(device) >= wantblox ? 0 : 1);
- >X
- >} /* main() */
- >X
- >SHAR_EOF
- >chmod 0664 main.c ||
- >echo 'restore of main.c failed'
- >Wc_c="`wc -c < 'main.c'`"
- >test 2497 -eq "$Wc_c" ||
- > echo 'main.c: original size 2497, current size' "$Wc_c"
- >fi
- ># ============= reap.8 ==============
- >if test -f 'reap.8' -a X"$1" != X"-c"; then
- > echo 'x - skipping reap.8 (File already exists)'
- >else
- >echo 'x - extracting reap.8 (Text)'
- >sed 's/^X//' << 'SHAR_EOF' > 'reap.8' &&
- >.TH REAP 8 LOCAL
- >.SH NAME
- >reap - remove news articles as space needed
- >.SH SYNOPSIS
- >.B reap
- >[-v] [-s] [-n] [-f scriptfile] freeblocks
- >.SH DESCRIPTION
- >.I Reap
- >checks disk freespace and deletes netnews articles
- >according to a flexible user-specified
- >scheme until
- >.I freeblocks
- >minimum freespace is available.
- >It does this by sequentially reading commands (expire functions) from a
- >text file (function script), and executing them one at a time.
- >.PP
- >Each expire function consists of an age limit and a list of newsgroups
- >to expire to that limit.
- >Before executing
- >Xeach new expire function, reap checks the freespace on the news spool
- >device. Reap will exit when either the desired freespace is attained, or
- >the end of the function script file is reached (the latter case is considered
- >an unsuccessful exit).
- >By carefully designing the function script, a news administrator can
- >automate a wide variety of expiring policies.
- >.PP
- >The
- >.B -n
- >causes a dry run (as in make(1)). When this
- >option is specified, reap merely reports which articles it would delete if
- >the option were left off. This is useful for debugging function scripts.
- >However, since no space is actually freed in this mode,
- >it will either do nothing
- >(there was enough space to begin with) or proceed through the entire function
- >script file, indicating that reap would delete all applicable articles.
- >.PP
- >With the
- >.B -v
- >option, reap prints a verbose commentary on its progress to the standard
- >output.
- >.PP
- >The
- >.B -s
- >option causes reap to print a brief summary of blocks freed to the standard
- >output just before exiting. It also indicates how much of the script file
- >was processed. This is independent of -v.
- >.PP
- >By default, reap looks in /usr/lib/news/reaplist for its list of functions.
- >The
- >.B -f
- >option is used to specify an alternate function script file.
- >.SH FUNCTION SCRIPT FILE FORMAT
- >A function script file consists of a series of expire functions, one per line.
- >Each expire function contains an age limit (in days, decimals okay), followed
- >by a comma-separated list of newsgroup specifications, similar to the
- >sys file format.
- >.PP
- >There are four types of valid newsgroup specifications that can go in the list:
- >.PP
- >(1) An ordinary newsgroup name (alt.sex) indicates that any articles in that
- >newsgroup and any of its descendants (such as alt.sex.pictures), which are
- >older than the age limit, should be expired.
- >.PP
- >(2) A newsgroup name with a trailing dot (alt.sex.) indicates that any articles
- >in that newsgroup, which are older than the age limit, should be expired.
- >However, recursion is not implied. Articles in descendants of that group
- >(such as alt.sex.pictures) are not affected.
- >.PP
- >(3) A newsgroup name with a preceding exclamation point (!alt.sex.pictures)
- >indicates that that newsgroup and all of its descendants should be excluded
- >from the list.
- >For example, "1 alt.sex,!alt.sex.pictures" means to expire everything subsumed
- >under alt.sex to 1 day, but do not touch anything subsumed under
- >alt.sex.pictures.
- >.PP
- >(4) A newsgroup name with both a preceding exclamation point and a trailing
- >dot (!alt.sex.pictures.) indicates that that newsgroup should be excluded
- >from the list, but its descendants should remain in the list. For example,
- >"1 alt.sex,!alt.sex.pictures." means to expire everything subsumed under
- >alt.sex to 1 day, including the contents of any subgroups of alt.sex.pictures
- >(like alt.sex.pictures.d), but do not touch the articles in the newsgroup
- >alt.sex.pictures.
- >.PP
- >Blank lines and lines beginning with a "#" are ignored.
- >A sample function script file:
- >.PP
- >.nf
- >X # my first function script file
- >X 0.5 talk,junk,alt.sex.pictures.
- >X 2 rec,!rec.games,!rec.humor
- >X 2 misc
- >.fi
- >.PP
- >In the example,
- >if space is needed, reap
- >Xexpires to .5 days the entire talk and junk
- >hierarchies, and alt.sex.pictures (not touching any subgroups of
- >alt.sex.pictures, such as alt.sex.pictures.d).
- >If still more space is needed, the
- >rec hierarchy (excepting all of rec.games.* and rec.humor.*) is expired
- >to 2 days. If freespace is still short, reap then expires all of misc
- >to 2 days.
- >.PP
- >Note that, while it would be possible to consolidate the 2-day
- >lines, leaving them separate makes it possible for reap to stop
- >in between them if sufficient space is cleared.
- >.PP
- >A practical function script file would directly or indirectly
- >include every group carried on the system, with some age limit. Otherwise,
- >the spool directory will inevitably overflow without operator intervention.
- >.PP
- >It is valid to specify a dot all by itself (.) in the newsgroup list field.
- >This is taken to mean the entire spool directory hierarchy, so "14 ." means
- >to expire all news to 14 days. Be warned that reap must search the entire
- >news hierarchy when this feature is used. Still, it is probably a good
- >idea to end all function script files with a "0 .", so that, in absolute
- >desperation, all news would be removed.
- >.SH FILES
- >.TP 25
- >/usr/spool/news
- >News spool directory
- >.TP 25
- >/usr/lib/news/reaplist
- >Default function list file
- >.SH DIAGNOSTICS
- >Returns zero if sufficient space was free at exit, 1 if the entire function
- >script was executed without freeing enough space, and -1 on an error
- >condition.
- >.SH CAVEATS
- >What constitutes a disk "block" is implementation-dependent.
- >.PP
- >History files are not updated. That must be performed as a separate operation.
- >.PP
- >For best performance, exclude recursively (without the dot) whenever
- >possible. Otherwise, reap will have to search the excluded directory
- >for any subdirectories which might not have been excluded, which is slow.
- >.SH BUGS
- >The use of the ustat() system call is not very portable, and your humble
- >author isn't aware of its non-system-V equivalents.
- >.PP
- >Lines in the function file are limited to 1024 characters.
- >.PP
- >The "cleared" figure in the summary merely indicates the difference in
- >freespace before and after the run, not necessarily the actual number of
- >blocks liberated by reap.
- >.SH AUTHOR
- >Reap is freeware by David B. Thomas (dt@yenta.alb.nm.us). You are free
- >to copy, distribute, staple, bend, fold or mutilate this package to your
- >heart's content. Please email any enhancements or ideas for enhancements.
- >SHAR_EOF
- >chmod 0644 reap.8 ||
- >echo 'restore of reap.8 failed'
- >Wc_c="`wc -c < 'reap.8'`"
- >test 6129 -eq "$Wc_c" ||
- > echo 'reap.8: original size 6129, current size' "$Wc_c"
- >fi
- ># ============= reap.c ==============
- >if test -f 'reap.c' -a X"$1" != X"-c"; then
- > echo 'x - skipping reap.c (File already exists)'
- >else
- >echo 'x - extracting reap.c (Text)'
- >sed 's/^X//' << 'SHAR_EOF' > 'reap.c' &&
- >X
- >/*
- >X * reap.c
- >X * contains the reap() function.
- >X *
- >X * Once the global linked lists incl and excl have been stuffed,
- >X * reap() actually scans the filesystem for files that meet the specs
- >X * and unlinks them if they are older than the age global variable.
- >X */
- >X
- >#include "reap.h"
- >X
- >X
- >reap()
- >{
- >X struct filspec *f;
- >X
- >X for (f = incl; f != NULL; f = f->next) {
- >X if (verbose)
- >X printf ("scanning %s ...\n", f->name);
- >X dodir (f->name, f->recurse);
- >X }
- >X
- >} /* reap() */
- >X
- >X
- >X
- >dodir(name, rflag)
- >char *name;
- >int rflag;
- >{
- >X /* the following can be overwritten safely during recursion */
- >X static struct filspec *e;
- >X static struct stat st;
- >X static struct dirent *dp;
- >X static char thisname[MAXFILENAME+1];
- >X /* the following must be preserved through recursion */
- >X char *fullpath;
- >X int eflag = 0;
- >X DIR *dirp;
- >X
- >X
- >/* open directory for reading */
- >X if ( (dirp = opendir(name)) == NULL)
- >X ouch ("%s: can't read directory %s\n", name);
- >X
- >X
- >/* see if this directory is excluded.
- >X * If it's excluded recursively, quit here.
- >X * If it's excluded non-recursively, set a flag, so we won't consider
- >X * deleting any files in it, but we'll still explore subdirectories.
- >X */
- >X for (e = excl; e != NULL; e = e->next)
- >X if (!strcmp (name, e->name))
- >X break;
- >X if (e != NULL) {
- >X if (e->recurse)
- >X return;
- >X else
- >X ++eflag;
- >X }
- >X
- >X
- >/* loop for each directory entry */
- >X while ( (dp = readdir(dirp)) != NULL) {
- >X
- >X /* name might be exactly MAXFILENAME characters long, and thus
- >X * might not be null-terminated. Some insurance:
- >X */
- >X strncpy (thisname, dp->d_name, MAXFILENAME);
- >X thisname[MAXFILENAME] = '\0';
- >X
- >X /* skip dot and dotdot */
- >X if (!strcmp(thisname, ".") || !strcmp(thisname, ".."))
- >X continue;
- >X
- >X /* build the full pathname of current object */
- >X if ( (fullpath =
- >X malloc(strlen(name)+strlen(thisname)+2)) == NULL)
- >X ouch ("%s: out of memory\n");
- >X
- >X sprintf (fullpath, "%s/%s", name, thisname);
- >X
- >X /* try to stat the object */
- >X if (stat(fullpath,&st)) {
- >X fprintf (stderr, "%s: can't stat %s\n",
- >X progname, fullpath);
- >X free (fullpath);
- >X continue;
- >X }
- >X
- >X /* maybe recurse if it's a directory */
- >X if ( st.st_mode & S_IFDIR ) {
- >X if (rflag)
- >X dodir (fullpath, 1);
- >X free (fullpath);
- >X continue;
- >X }
- >X
- >X /* it's a file ... is this a non-recursively excluded directory?
- >X * if so, there's nothing to do to this file
- >X */
- >X if (eflag)
- >X continue;
- >X
- >X /* leave it alone if this directory is excluded, or
- >X * if it's new enough.
- >X */
- >X if (eflag || st.st_mtime > age) {
- >X free (fullpath);
- >X continue;
- >X }
- >X
- >X /* reap this file! */
- >X if (dryrun) {
- >X printf ("Would unlink %s\n", fullpath);
- >X free (fullpath);
- >X continue;
- >X }
- >X if (verbose)
- >X printf ("Unlinking %s\n", fullpath);
- >X
- >X if (unlink (fullpath) == -1)
- >X fprintf (stderr,
- >X "%s: cannot unlink %s\n", progname, fullpath);
- >X
- >X free (fullpath);
- >X
- >X } /* while */
- >X
- >X closedir (dirp);
- >X
- >} /* dodir() */
- >SHAR_EOF
- >chmod 0664 reap.c ||
- >echo 'restore of reap.c failed'
- >Wc_c="`wc -c < 'reap.c'`"
- >test 2845 -eq "$Wc_c" ||
- > echo 'reap.c: original size 2845, current size' "$Wc_c"
- >fi
- ># ============= reap.h ==============
- >if test -f 'reap.h' -a X"$1" != X"-c"; then
- > echo 'x - skipping reap.h (File already exists)'
- >else
- >echo 'x - extracting reap.h (Text)'
- >sed 's/^X//' << 'SHAR_EOF' > 'reap.h' &&
- >X
- >/*
- >X * reap.h
- >X * header file for reap utility
- >X */
- >X
- >/* set MAXFILENAME to the maximum number of characters in a filename for
- >X * your system. Typically 14 or infinity, where infinity equals
- >X * 256 characters. :-)
- >X */
- >#define MAXFILENAME 14
- >X
- >/* set NEWSDIR to the directory containing news on your system.
- >X * Very commonly /usr/spool/news
- >X */
- >#define NEWSDIR "/usr/spool/news"
- >X
- >/* set SCRIPT to the path of the default function script file
- >X * Usually this is /usr/lib/news/reaplist
- >X */
- >#define SCRIPT "/usr/lib/news/reaplist"
- >X
- >X
- >X
- >X
- >#include <stdio.h>
- >#include <string.h>
- >#include <ctype.h>
- >#include <time.h>
- >#include <malloc.h>
- >#include <sys/types.h>
- >#include <sys/stat.h>
- >#include <ustat.h>
- >#include <dirent.h>
- >X
- >#define MAXLINE 1024 /* max len of line in script */
- >#define SECINDAY (3600 * 24) /* seconds in a day */
- >X
- >/* structure for linked lists of included and excluded file specs */
- >struct filspec {
- >X char *name;
- >X int recurse;
- >X struct filspec *next;
- >};
- >X
- >Xextern struct filspec
- >X *incl,
- >X *excl
- >;
- >Xextern char
- >X *progname,
- >X *scriptfile,
- >X *newsdir
- >;
- >Xextern int
- >X verbose,
- >X dryrun,
- >X optind
- >;
- >Xextern char *optarg;
- >Xextern double atof();
- >Xextern long freeblox();
- >Xextern time_t
- >X age,
- >X now
- >;
- >SHAR_EOF
- >chmod 0664 reap.h ||
- >echo 'restore of reap.h failed'
- >Wc_c="`wc -c < 'reap.h'`"
- >test 1195 -eq "$Wc_c" ||
- > echo 'reap.h: original size 1195, current size' "$Wc_c"
- >fi
- >exit 0
- >--
- >Bottom of stack = 0x40000
- >Stack pointer = 0x3fffe
- >Don't push it!
- ---
- reply to : admerlev@faui43.informatik.uni-erlangen.de
-