home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3146 < prev    next >
Encoding:
Internet Message Format  |  1991-03-28  |  31.8 KB

  1. From: dt@yenta.alb.nm.us (David B. Thomas)
  2. Newsgroups: alt.sources
  3. Subject: reap(8): expire news as space needed
  4. Message-ID: <1991Mar28.025957.1976@yenta.alb.nm.us>
  5. Date: 28 Mar 91 02:59:57 GMT
  6.  
  7. This message contains the README, followed by the source:
  8.  
  9. README for reap version 1.1 by David B. Thomas (dt@yenta.alb.nm.us).
  10.  
  11. A Problem:
  12.     News volume fluctuates wildly...sites with small disks must either
  13. expire aggresively, often deleting more than necessary, or worry that an
  14. unexpected huge dose of news might overfill the disk.
  15.  
  16.  
  17. A Solution:
  18.     Implement a tool that expires according to a user-defined scheme
  19. until sufficient freespace is reclaimed, then stops, leaving as much
  20. juicy news online as is feasible.  Reap does this.
  21.  
  22.  
  23. Expire Does Two Jobs:
  24.     Both Bnews and Cnews expires really do two jobs:
  25.         1. trim history files
  26.         2. delete outdated articles
  27. Thanks to some inspired jootsing (acronym for "jumping out of the system")
  28. by Mike Murphy (mrm@sceard.com) and others, it is more than possible to
  29. separate those two functions.  This is, of course, in keeping with the
  30. unix philosophy of one tool doing one job well!
  31.  
  32.  
  33. What Reap Does:
  34.     Reap only takes care of the second job: deleting old articles.
  35. It works by checking freespace, and processing one line at a time from a
  36. list of expire functions, until the desired freespace is attained.
  37. Each expire function consists of an age limit in days (decimals okay)
  38. and a list of newsgroups to process or not process, sys file style.  Ex:
  39.  
  40.     .5    alt.sex.pictures,talk,!talk.bizarre,junk
  41.     1    rec,!rec.games,!rec.humor
  42.  
  43. This example would check freespace, and if more space is needed, expire
  44. to .5 days everything in alt.sex.pictures, talk (except for talk.bizarre)
  45. and junk.  Then it would stop and check freespace again.  If still more
  46. space is needed, it would expire to 1 day everything in rec except
  47. rec.games.* and rec.humor.*.  It's that simple.
  48.  
  49.  
  50. Okay...So How Do I Arrange To Trim The History Files, Since Reap Can't:
  51.     Included in this distribution is a shell script (mostly written
  52. by Mike Murphy) to handle Cnews history files.  It shouldn't be too
  53. difficult to do something similar for Bnews, or you can give in and use
  54. the original expire utility with options that tell it to expire the
  55. history files only...but I think this will be slow.  It just comes down
  56. to removing lines from ordinary text files, based on their contents.
  57. Murphy and I used awk.
  58.  
  59.  
  60. But Is It Fast:
  61.     Yes, largely because it doesn't have to do much.  Even "find | rm"
  62. is slower because find is repeatedly exec-ing rm.  "rm -rf" has me beat,
  63. though, I'll bet!  :-)
  64.  
  65.     Since the functions of deleting articles and trimming history
  66. are separate, I now run reap every six hours, but trim the history list
  67. just once a day.  That effectively keeps my disk space up to snuff, but
  68. only thrashes at the history file in the middle of the night.
  69.  
  70.  
  71. Credits:
  72.     I owe a lot to Mike Murphy for inspiring me with his "trasher"
  73. system.  I also owe a lot to all of your netters who will flood me with
  74. more suggestions and improvements in the coming weeks (hint, hint!).
  75.  
  76.                         little david
  77.                         dt@yenta.alb.nm.us
  78.  
  79. ps - reap is freeware.  No strings(1) attached.
  80.  
  81.  
  82. #!/bin/sh
  83. # This is a shell archive (shar 3.44)
  84. # made 03/28/1991 02:51 UTC by dt@yenta
  85. # Source directory /u/dt/src/reap
  86. #
  87. # existing files will NOT be overwritten unless -c is specified
  88. #
  89. # This shar contains:
  90. # length  mode       name
  91. # ------ ---------- ------------------------------------------
  92. #    934 -rw-rw-r-- Install
  93. #    339 -rw-rw-r-- MANIFEST
  94. #    900 -rw-rw-r-- Makefile
  95. #   2918 -rw-rw-r-- README
  96. #    969 -rwxrwxr-x exphist
  97. #   3567 -rw-rw-r-- lib.c
  98. #   1611 -rw-rw-r-- list.sample
  99. #   2497 -rw-rw-r-- main.c
  100. #   6129 -rw-r--r-- reap.8
  101. #   2845 -rw-rw-r-- reap.c
  102. #   1195 -rw-rw-r-- reap.h
  103. #
  104. # ============= Install ==============
  105. if test -f 'Install' -a X"$1" != X"-c"; then
  106.     echo 'x - skipping Install (File already exists)'
  107. else
  108. echo 'x - extracting Install (Text)'
  109. sed 's/^X//' << 'SHAR_EOF' > 'Install' &&
  110. X
  111. To install:
  112. X
  113. 1. Edit tops of Makefile and reap.h to fit your system.
  114. X   [If you are installing this on a non-system-V machine, you will need
  115. X   to rewrite the freeblox() function at the top of lib.c.  This should
  116. X   be very easy.  Please email your working mods to me.]
  117. 2. make
  118. 3. Compose a sample function list file or use the sample provided to
  119. X    test reap (use the -n option to avoid really removing files).
  120. 4. su and make install.
  121. 5. Arrange to trim your news system's history list regularly.  If you have
  122. X    Cnews, try the "exphist" script provided, run from cron.  That
  123. X    script requires that a tiny file, /usr/lib/news/histdays, containing
  124. X    the number of days of history data to keep, or else you can hardcode
  125. X    in your favorite number.  If you have Bnews, I don't have a nifty
  126. X    suggestion, other than using expire(8) with a ridiculously long
  127. X    article expire time, but a sane history expire time.
  128. 6. Arrange to run reap from cron.
  129. SHAR_EOF
  130. chmod 0664 Install ||
  131. echo 'restore of Install failed'
  132. Wc_c="`wc -c < 'Install'`"
  133. test 934 -eq "$Wc_c" ||
  134.     echo 'Install: original size 934, current size' "$Wc_c"
  135. fi
  136. # ============= MANIFEST ==============
  137. if test -f 'MANIFEST' -a X"$1" != X"-c"; then
  138.     echo 'x - skipping MANIFEST (File already exists)'
  139. else
  140. echo 'x - extracting MANIFEST (Text)'
  141. sed 's/^X//' << 'SHAR_EOF' > 'MANIFEST' &&
  142. Included with this distribution are:
  143. X
  144. README        - general description and credits
  145. Install        - hints on how to install reap and get it going
  146. Xexphist        - history trimmer utility for Cnews
  147. list.sample    - sample function script file for reap
  148. reap.8        - man page
  149. lib.c        - source
  150. main.c        - source
  151. reap.c        - source
  152. reap.h        - source
  153. Makefile    - makefile
  154. SHAR_EOF
  155. chmod 0664 MANIFEST ||
  156. echo 'restore of MANIFEST failed'
  157. Wc_c="`wc -c < 'MANIFEST'`"
  158. test 339 -eq "$Wc_c" ||
  159.     echo 'MANIFEST: original size 339, current size' "$Wc_c"
  160. fi
  161. # ============= Makefile ==============
  162. if test -f 'Makefile' -a X"$1" != X"-c"; then
  163.     echo 'x - skipping Makefile (File already exists)'
  164. else
  165. echo 'x - extracting Makefile (Text)'
  166. sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
  167. #----------------------------
  168. # parameters for installation
  169. #----------------------------
  170. X
  171. # directories where manual and executable are to be installed
  172. BINDIR = /usr/lib/newsbin/expire
  173. MANDIR = /usr/man/man8
  174. X
  175. # owner, group and file mode for manual and executable
  176. EXEOWNER = bin
  177. EXEGROUP = bin
  178. EXEMODE = 775
  179. MANOWNER = bin
  180. MANGROUP = bin
  181. MANMODE = 664
  182. X
  183. X
  184. # your favorite C compiler
  185. #CC = cc
  186. CC = shcc
  187. X
  188. # directory access functions library, if not in standard C library.
  189. LIB = -ldirent
  190. X
  191. X
  192. #-------------
  193. # boring stuff
  194. #-------------
  195. X
  196. OBJ = main.o lib.o reap.o
  197. X
  198. reap: $(OBJ)
  199. X    $(CC) -s -o reap $(SHLIB) $(OBJ) $(LIB)
  200. X
  201. $(OBJ): reap.h
  202. X
  203. install: reap reap.8
  204. X    cp reap $(BINDIR)
  205. X    chown $(EXEOWNER) $(BINDIR)/reap
  206. X    chgrp $(EXEGROUP) $(BINDIR)/reap
  207. X    chmod $(EXEMODE) $(BINDIR)/reap
  208. X    cp reap.8 $(MANDIR)
  209. X    chmod $(MANMODE) $(MANDIR)/reap.8
  210. X    chown $(MANOWNER) $(MANDIR)/reap.8
  211. X    chgrp $(MANGROUP) $(MANDIR)/reap.8
  212. SHAR_EOF
  213. chmod 0664 Makefile ||
  214. echo 'restore of Makefile failed'
  215. Wc_c="`wc -c < 'Makefile'`"
  216. test 900 -eq "$Wc_c" ||
  217.     echo 'Makefile: original size 900, current size' "$Wc_c"
  218. fi
  219. # ============= README ==============
  220. if test -f 'README' -a X"$1" != X"-c"; then
  221.     echo 'x - skipping README (File already exists)'
  222. else
  223. echo 'x - extracting README (Text)'
  224. sed 's/^X//' << 'SHAR_EOF' > 'README' &&
  225. X
  226. README for reap version 1.1 by David B. Thomas (dt@yenta.alb.nm.us).
  227. X
  228. A Problem:
  229. X    News volume fluctuates wildly...sites with small disks must either
  230. Xexpire aggresively, often deleting more than necessary, or worry that an
  231. unexpected huge dose of news might overfill the disk.
  232. X
  233. X
  234. A Solution:
  235. X    Implement a tool that expires according to a user-defined scheme
  236. until sufficient freespace is reclaimed, then stops, leaving as much
  237. juicy news online as is feasible.  Reap does this.
  238. X
  239. X
  240. Expire Does Two Jobs:
  241. X    Both Bnews and Cnews expires really do two jobs:
  242. X        1. trim history files
  243. X        2. delete outdated articles
  244. Thanks to some inspired jootsing (acronym for "jumping out of the system")
  245. by Mike Murphy (mrm@sceard.com) and others, it is more than possible to
  246. separate those two functions.  This is, of course, in keeping with the
  247. unix philosophy of one tool doing one job well!
  248. X
  249. X
  250. What Reap Does:
  251. X    Reap only takes care of the second job: deleting old articles.
  252. It works by checking freespace, and processing one line at a time from a
  253. list of expire functions, until the desired freespace is attained.
  254. Each expire function consists of an age limit in days (decimals okay)
  255. and a list of newsgroups to process or not process, sys file style.  Ex:
  256. X
  257. X    .5    alt.sex.pictures,talk,!talk.bizarre,junk
  258. X    1    rec,!rec.games,!rec.humor
  259. X
  260. This example would check freespace, and if more space is needed, expire
  261. to .5 days everything in alt.sex.pictures, talk (except for talk.bizarre)
  262. and junk.  Then it would stop and check freespace again.  If still more
  263. space is needed, it would expire to 1 day everything in rec except
  264. rec.games.* and rec.humor.*.  It's that simple.
  265. X
  266. X
  267. Okay...So How Do I Arrange To Trim The History Files, Since Reap Can't:
  268. X    Included in this distribution is a shell script (mostly written
  269. by Mike Murphy) to handle Cnews history files.  It shouldn't be too
  270. difficult to do something similar for Bnews, or you can give in and use
  271. the original expire utility with options that tell it to expire the
  272. history files only...but I think this will be slow.  It just comes down
  273. to removing lines from ordinary text files, based on their contents.
  274. Murphy and I used awk.
  275. X
  276. X
  277. But Is It Fast:
  278. X    Yes, largely because it doesn't have to do much.  Even "find | rm"
  279. is slower because find is repeatedly exec-ing rm.  "rm -rf" has me beat,
  280. though, I'll bet!  :-)
  281. X
  282. X    Since the functions of deleting articles and trimming history
  283. are separate, I now run reap every six hours, but trim the history list
  284. just once a day.  That effectively keeps my disk space up to snuff, but
  285. only thrashes at the history file in the middle of the night.
  286. X
  287. X
  288. Credits:
  289. X    I owe a lot to Mike Murphy for inspiring me with his "trasher"
  290. system.  I also owe a lot to all of your netters who will flood me with
  291. more suggestions and improvements in the coming weeks (hint, hint!).
  292. X
  293. X                        little david
  294. X                        dt@yenta.alb.nm.us
  295. X
  296. ps - reap is freeware.  No strings(1) attached.
  297. SHAR_EOF
  298. chmod 0664 README ||
  299. echo 'restore of README failed'
  300. Wc_c="`wc -c < 'README'`"
  301. test 2918 -eq "$Wc_c" ||
  302.     echo 'README: original size 2918, current size' "$Wc_c"
  303. fi
  304. # ============= exphist ==============
  305. if test -f 'exphist' -a X"$1" != X"-c"; then
  306.     echo 'x - skipping exphist (File already exists)'
  307. else
  308. echo 'x - extracting exphist (Text)'
  309. sed 's/^X//' << 'SHAR_EOF' > 'exphist' &&
  310. #! /bin/sh
  311. # exphist - expire history file
  312. X
  313. # =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
  314. . ${NEWSCONFIG-/usr/lib/news/bin/config}
  315. X
  316. PATH=$NEWSCTL/bin:$NEWSBIN/expire:$NEWSBIN:$NEWSPATH ; export PATH
  317. umask $NEWSUMASK
  318. X
  319. days=`cat /usr/lib/news/histdays`
  320. X
  321. lock="$NEWSCTL/LOCKexpire"
  322. ltemp="$NEWSCTL/L.$$"
  323. Xecho $$ >$ltemp
  324. trap "rm -f $ltemp ; exit 0" 0 1 2 15
  325. if newslock $ltemp $lock
  326. then
  327. X    trap "rm -f $ltemp $lock ; exit 0" 0 1 2 15
  328. Xelse
  329. X    echo "$0: expire apparently already running" | mail "$NEWSMASTER"
  330. X    exit 1
  331. fi
  332. X
  333. cd $NEWSCTL
  334. rm -f history.n history.n.pag history.n.dir
  335. now=`getdate now`
  336. age=`expr 86400 \* $days`
  337. ago=`expr $now - $age`
  338. awk "{split(\$2,dates,\"~\");if(dates[1]>$ago)print \$0}" history >history.n
  339. mkdbm history.n
  340. [ -s history.n ] &&
  341. mv history history.o &&    # install new ASCII history file
  342. mv history.n history &&
  343. rm -f history.pag &&       # and related dbm files
  344. rm -f history.dir &&
  345. mv history.n.pag history.pag &&
  346. mv history.n.dir history.dir
  347. Xexit 0
  348. SHAR_EOF
  349. chmod 0775 exphist ||
  350. echo 'restore of exphist failed'
  351. Wc_c="`wc -c < 'exphist'`"
  352. test 969 -eq "$Wc_c" ||
  353.     echo 'exphist: original size 969, current size' "$Wc_c"
  354. fi
  355. # ============= lib.c ==============
  356. if test -f 'lib.c' -a X"$1" != X"-c"; then
  357.     echo 'x - skipping lib.c (File already exists)'
  358. else
  359. echo 'x - extracting lib.c (Text)'
  360. sed 's/^X//' << 'SHAR_EOF' > 'lib.c' &&
  361. X
  362. /*
  363. X * lib.c
  364. X *    subroutines needed by reap utility
  365. X */
  366. X
  367. #include "reap.h"
  368. X
  369. /*
  370. X * freeblox(devno)
  371. X *
  372. X * THIS WILL REQUIRE MODIFICATION TO WORK UNDER NON-SYSTEM-V UNIX.
  373. X * IT SHOULD BE EASY.  PLEASE EMAIL WORKING MODS TO THE AUTHOR:
  374. X *            dt@yenta.alb.nm.us
  375. X *
  376. X *    assuming devno is the device number of a file system,
  377. X *    this function returns the free space on that file system,
  378. X *    in blocks (whatever that means for that filesystem) as an int.
  379. X *
  380. X */
  381. X
  382. freeblox(devno)
  383. int    devno;
  384. {
  385. X    static struct ustat    ust;
  386. X
  387. X    if (ustat(devno, &ust))
  388. X        ouch ("%s: ustat() failed\n");
  389. X
  390. X    return (ust.f_tfree);
  391. X
  392. } /* freeblox() */
  393. X
  394. X
  395. X
  396. X
  397. /*
  398. X * parse(cmd)
  399. X *    execute a line from the script file
  400. X *
  401. X * valid command lines:
  402. X *    a blank line is ignored
  403. X *    # comment (ignored)
  404. X *    days filespecs
  405. X *
  406. X * filespecs is a comma separated list of any combination of the following:
  407. X * 1. a directory (newsgroup) to include, without recursion.
  408. X *    ex:  alt.sources.
  409. X * 2. a directory to include, recursively.
  410. X *    ex:  alt.sources
  411. X * 3. a directory to exclude, without recursion.
  412. X *    ex:  !alt.sex.
  413. X * 4. a directory to exclude, recursively.
  414. X *    ex:  !alt.sex
  415. X */
  416. X
  417. parse(cmd)
  418. char    *cmd;
  419. {
  420. X    register int    l;
  421. X    int        recurseflag;
  422. X    double        days;
  423. X    char        *t,
  424. X            *p,
  425. X            *q,
  426. X            *seps = ",\n ";
  427. X
  428. X
  429. /* skip initial whitespace */
  430. X    p = cmd;
  431. X    while (isspace(*p))
  432. X        ++p;
  433. X
  434. /* ignore blank lines or comments */
  435. X    if (*p == '\0' || *p == '#')
  436. X        return(1);
  437. X
  438. /* read the expire time from the line as a floating point number,
  439. X * then figure out what the timestamp on a file that old would be */
  440. X    age = now - (time_t) (atof(p) * SECINDAY);
  441. X
  442. /* skip ahead to the filespec list */
  443. X    while (!isspace(*p))
  444. X        ++p;
  445. X    while (isspace(*p))
  446. X        ++p;
  447. X
  448. /* initialize exclusion list to null list */
  449. X    preclude();
  450. X
  451. /* for each filespec in list */
  452. X    for (t = strtok(p, seps); t; t = strtok(NULL, seps)) {
  453. X
  454. X    /* forbid starting with a slash */
  455. X        if (*t == '/')
  456. X            *t = '.';
  457. X
  458. X    /* change dots to slashes except in column 1 */
  459. X        while ( (q = strchr(t+1,'.')) != NULL)
  460. X            *q = '/';
  461. X
  462. X    /* for final dot or slash, remove it, and shut off recursion */
  463. X        recurseflag = 1;
  464. X        if (t[l = (strlen(t) - 1)] == '/') {
  465. X            recurseflag = 0;
  466. X            t[l] = '\0';
  467. X        }
  468. X
  469. X        if (*t == '!')
  470. X            exclude (t+1, recurseflag);
  471. X        else
  472. X            include (t, recurseflag);
  473. X    }
  474. X
  475. X    reap();
  476. X
  477. X    return (0);
  478. X
  479. } /* parse() */
  480. X
  481. X
  482. X
  483. /*
  484. X * newnode,exclude, include, preclude
  485. X *
  486. X *    functions to maintain global linked lists:
  487. X *        incl    include this path in list of dirs to reap
  488. X *        excl    leave out this directory
  489. X            (each entry can be recursive or not)
  490. X *
  491. X *    the functions are:
  492. X *        include (text,rflag)    add to incl list
  493. X *        exclude (text,rflag)    add to excl list
  494. X *        preclude()        clear both lists
  495. X */
  496. struct filspec *
  497. newnode(text)
  498. char    *text;
  499. {
  500. X    struct filspec    *f;
  501. X
  502. X    if ( (f = (struct filspec *) malloc (sizeof(struct filspec))) == NULL ||
  503. X        (f->name = malloc (strlen(text)+1)) == NULL)
  504. X        ouch ("%s: out of memory\n");
  505. X
  506. X    strcpy (f->name, text);
  507. X    return (f);
  508. }
  509. Xexclude(text, rflag)
  510. char    *text;
  511. int    rflag;
  512. {
  513. X    struct filspec    *f;
  514. X
  515. X    f = newnode(text);
  516. X    f->recurse = rflag;
  517. X    f->next = excl;
  518. X    excl = f;
  519. }
  520. include(text, rflag)
  521. char    *text;
  522. int    rflag;
  523. {
  524. X    struct filspec    *f;
  525. X
  526. X    f = newnode(text);
  527. X    f->recurse = rflag;
  528. X    f->next = incl;
  529. X    incl = f;
  530. }
  531. preclude()
  532. {
  533. X    struct filspec    *p;
  534. X
  535. X    while (incl != NULL) {
  536. X        p = incl;
  537. X        incl = incl->next;
  538. X        free (p->name);
  539. X        free (p);
  540. X    }
  541. X    while (excl != NULL) {
  542. X        p = excl;
  543. X        excl = excl->next;
  544. X        free (p->name);
  545. X        free (p);
  546. X    }
  547. }
  548. X
  549. X
  550. /*
  551. X * ouch(fmt, arg)
  552. X *    outputs an error message and exits with error status
  553. X */
  554. X
  555. ouch (fmt,arg)
  556. char    *fmt, *arg;
  557. {
  558. X    fprintf (stderr, fmt, progname, arg);
  559. X    exit (-1);
  560. }
  561. SHAR_EOF
  562. chmod 0664 lib.c ||
  563. echo 'restore of lib.c failed'
  564. Wc_c="`wc -c < 'lib.c'`"
  565. test 3567 -eq "$Wc_c" ||
  566.     echo 'lib.c: original size 3567, current size' "$Wc_c"
  567. fi
  568. # ============= list.sample ==============
  569. if test -f 'list.sample' -a X"$1" != X"-c"; then
  570.     echo 'x - skipping list.sample (File already exists)'
  571. else
  572. echo 'x - extracting list.sample (Text)'
  573. sed 's/^X//' << 'SHAR_EOF' > 'list.sample' &&
  574. # yenta's /usr/lib/news/reaplist function script file.
  575. .1 junk,alt.flame,control,comp.binaries,alt.sex.pictures.,alt.fractals.pictures
  576. .1 alt.desert-storm,alt.desert-shield,soc.motss,soc.culture
  577. 1 soc.singles,alt.activism,alt.romance.chat
  578. .5 talk
  579. 1 sci,!sci.skeptic
  580. 2 sci.skeptic
  581. .5 comp.text,comp.sys.atari,comp.windows,comp.os.vms
  582. .5 comp.unix.sysv386
  583. .5 misc.jobs,misc.handicap
  584. 2 soc,!soc.singles,!soc.motss,!soc.culture
  585. .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
  586. 1 rec.music,!rec.music.synth
  587. 3 rec.music.synth,rec.skydiving
  588. 2 alt.tv
  589. 2 rec.arts.anime,rec.arts.animation,rec.arts.movies,rec.radio.amateur,rec.autos,rec.arts.tv,rec.audio,rec.video
  590. 3 rec.games.hack
  591. 1 misc.headlines,misc.consumers,misc.kids,misc.legal
  592. 1 alt.sex,!alt.sex.bondage,!alt.sex.pictures.
  593. 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
  594. 3 comp.dcom.telecom
  595. 1 comp.binaries
  596. 1 alt.sources
  597. 1 news,!news.announce.newusers
  598. 3 biz
  599. 3 misc
  600. 3 alt,!alt.sources,!alt.tv,!alt.desert-shield,!alt.activism,!alt.fractals.pictures,!alt.desert-storm,!alt.romance.chat
  601. 3 comp.sys.att
  602. 5 comp.sys.3b1
  603. 5 comp.sources.3b1
  604. 7 general
  605. # up to here is "normal expire"... now let's get desparate
  606. .1 alt.sex.pictures
  607. .1 rec.arts.anime,rec.arts.animation,rec.arts.movies,rec.ham-radio,rec.autos,rec.arts.tv,rec.audio,rec.video
  608. .1 biz
  609. .1 talk
  610. .1 news
  611. .1 soc
  612. .1 sci
  613. .1 comp
  614. .1 alt
  615. .1 misc
  616. # if we got here, we're in big trouble -- wipe it all!
  617. 0 .
  618. SHAR_EOF
  619. chmod 0664 list.sample ||
  620. echo 'restore of list.sample failed'
  621. Wc_c="`wc -c < 'list.sample'`"
  622. test 1611 -eq "$Wc_c" ||
  623.     echo 'list.sample: original size 1611, current size' "$Wc_c"
  624. fi
  625. # ============= main.c ==============
  626. if test -f 'main.c' -a X"$1" != X"-c"; then
  627.     echo 'x - skipping main.c (File already exists)'
  628. else
  629. echo 'x - extracting main.c (Text)'
  630. sed 's/^X//' << 'SHAR_EOF' > 'main.c' &&
  631. X
  632. /*
  633. X * main.c
  634. X *    main routine and globals for reap utility, version 1.1
  635. X */
  636. X
  637. X
  638. #include "reap.h"
  639. X
  640. X
  641. /* linked lists for included and excluded file specs */
  642. struct filspec
  643. X        *incl = NULL,
  644. X        *excl = NULL
  645. ;
  646. char
  647. X        *scriptfile = SCRIPT,    /* path of function script    */
  648. X        *progname,        /* argv[0] for errors        */
  649. X        *newsdir = NEWSDIR    /* news root directory        */
  650. ;
  651. int
  652. X        verbose = 0,        /* verbosity (-v) flag        */
  653. X        dryrun = 0        /* do-not-unlink (-n) flag    */
  654. ;
  655. time_t
  656. X        age,            /* unlink files older than this    */
  657. X        now            /* current time            */
  658. ;
  659. X
  660. X
  661. /************************
  662. X *    MAIN FUNCTION    *
  663. X ************************/
  664. X
  665. main(argc, argv)
  666. int    argc;
  667. char    *argv[];
  668. {
  669. X    int        device,        /* device # containing newsdir    */
  670. X            c,
  671. X            lineno = 0,
  672. X            summary = 0,
  673. X            thenfree,
  674. X            errflag = 0;
  675. X    long        wantblox;    /* desired free space        */
  676. X    char        *p;
  677. X    static char    line[MAXLINE];
  678. X    FILE        *script;    /* file ptr for function script    */
  679. X    struct stat    st;
  680. X
  681. X
  682. /* save argv[0] for error spewings */
  683. X    progname = argv[0];
  684. X
  685. /* parse args */
  686. X    while ( (c=getopt(argc,argv,"vsnf:")) != EOF)
  687. X        switch(c) {
  688. X        case 'n':
  689. X            ++dryrun;
  690. X            break;
  691. X        case 'v':
  692. X            ++verbose;
  693. X            break;
  694. X        case 'f':
  695. X            scriptfile = optarg;
  696. X            break;
  697. X        case 's':
  698. X            ++summary;
  699. X            break;
  700. X        default:
  701. X            ++errflag;
  702. X            break;
  703. X        }
  704. X    
  705. X    if (argc - optind != 1 ||
  706. X        sscanf(argv[optind], "%ld", &wantblox) != 1 )
  707. X        ++errflag;
  708. X
  709. X    if (errflag) {
  710. X        fprintf (stderr,
  711. X            "usage: %s [-v] [-s] [-n] [-f funclist] freeblocks\n",
  712. X            progname);
  713. X        exit (-1);
  714. X    }
  715. X
  716. X
  717. /* stat newsdir to find the number of the device it's on */
  718. X    if (stat(newsdir, &st))
  719. X        ouch ("%s: can't stat %s\n", newsdir);
  720. X    device = st.st_dev;
  721. X
  722. /* open function script file for reading */
  723. X    if ( (script = fopen (scriptfile, "r")) == NULL)
  724. X        ouch ("%s: can't read %s\n", scriptfile);
  725. X
  726. /* Record the current time, for deciding what gets the axe. */
  727. X    time (&now);
  728. X
  729. /* chdir to newsdir */
  730. X    chdir (newsdir);
  731. X
  732. /* record initial freespace if summary is desired */
  733. X    if (summary)
  734. X        thenfree = freeblox(device);
  735. X
  736. /* main loop ... process until goal reached or end of script */
  737. X
  738. X    while (freeblox(device) < wantblox &&
  739. X        (p = fgets (line, MAXLINE, script)) != NULL )
  740. X        parse (line), ++lineno;
  741. X
  742. X    fclose (script);
  743. X
  744. X    if (summary) {
  745. X        c = freeblox(device);
  746. X        printf ("Freespace was %d, now %d.  Cleared %d.\n",
  747. X            thenfree, c, c - thenfree);
  748. X        printf ("Stopped after line %d in %s\n", lineno,
  749. X            scriptfile);
  750. X    }
  751. X
  752. /* return 0 if freespace goal was met at exit, 1 if not */
  753. X    exit (freeblox(device) >= wantblox ? 0 : 1);
  754. X
  755. } /* main() */
  756. X
  757. SHAR_EOF
  758. chmod 0664 main.c ||
  759. echo 'restore of main.c failed'
  760. Wc_c="`wc -c < 'main.c'`"
  761. test 2497 -eq "$Wc_c" ||
  762.     echo 'main.c: original size 2497, current size' "$Wc_c"
  763. fi
  764. # ============= reap.8 ==============
  765. if test -f 'reap.8' -a X"$1" != X"-c"; then
  766.     echo 'x - skipping reap.8 (File already exists)'
  767. else
  768. echo 'x - extracting reap.8 (Text)'
  769. sed 's/^X//' << 'SHAR_EOF' > 'reap.8' &&
  770. .TH REAP 8 LOCAL
  771. .SH NAME
  772. reap - remove news articles as space needed
  773. .SH SYNOPSIS
  774. .B reap
  775. [-v] [-s] [-n] [-f scriptfile] freeblocks
  776. .SH DESCRIPTION
  777. .I Reap
  778. checks disk freespace and deletes netnews articles
  779. according to a flexible user-specified
  780. scheme until
  781. .I freeblocks
  782. minimum freespace is available.
  783. It does this by sequentially reading commands (expire functions) from a
  784. text file (function script), and executing them one at a time.
  785. .PP
  786. Each expire function consists of an age limit and a list of newsgroups
  787. to expire to that limit.
  788. Before executing
  789. Xeach new expire function, reap checks the freespace on the news spool
  790. device.  Reap will exit when either the desired freespace is attained, or
  791. the end of the function script file is reached (the latter case is considered
  792. an unsuccessful exit).
  793. By carefully designing the function script, a news administrator can
  794. automate a wide variety of expiring policies.
  795. .PP
  796. The
  797. .B -n
  798. causes a dry run (as in make(1)).  When this
  799. option is specified, reap merely reports which articles it would delete if
  800. the option were left off.  This is useful for debugging function scripts.
  801. However, since no space is actually freed in this mode,
  802. it will either do nothing
  803. (there was enough space to begin with) or proceed through the entire function
  804. script file, indicating that reap would delete all applicable articles.
  805. .PP
  806. With the
  807. .B -v
  808. option, reap prints a verbose commentary on its progress to the standard
  809. output.
  810. .PP
  811. The
  812. .B -s
  813. option causes reap to print a brief summary of blocks freed to the standard
  814. output just before exiting.  It also indicates how much of the script file
  815. was processed.  This is independent of -v.
  816. .PP
  817. By default, reap looks in /usr/lib/news/reaplist for its list of functions.
  818. The
  819. .B -f
  820. option is used to specify an alternate function script file.
  821. .SH FUNCTION SCRIPT FILE FORMAT
  822. A function script file consists of a series of expire functions, one per line.
  823. Each expire function contains an age limit (in days, decimals okay), followed
  824. by a comma-separated list of newsgroup specifications, similar to the
  825. sys file format.
  826. .PP
  827. There are four types of valid newsgroup specifications that can go in the list:
  828. .PP
  829. (1) An ordinary newsgroup name (alt.sex) indicates that any articles in that
  830. newsgroup and any of its descendants (such as alt.sex.pictures), which are
  831. older than the age limit, should be expired.
  832. .PP
  833. (2) A newsgroup name with a trailing dot (alt.sex.) indicates that any articles
  834. in that newsgroup, which are older than the age limit, should be expired.
  835. However, recursion is not implied.  Articles in descendants of that group
  836. (such as alt.sex.pictures) are not affected.
  837. .PP
  838. (3) A newsgroup name with a preceding exclamation point (!alt.sex.pictures)
  839. indicates that that newsgroup and all of its descendants should be excluded
  840. from the list.
  841. For example, "1 alt.sex,!alt.sex.pictures" means to expire everything subsumed
  842. under alt.sex to 1 day, but do not touch anything subsumed under
  843. alt.sex.pictures.
  844. .PP
  845. (4) A newsgroup name with both a preceding exclamation point and a trailing
  846. dot (!alt.sex.pictures.) indicates that that newsgroup should be excluded
  847. from the list, but its descendants should remain in the list.  For example,
  848. "1 alt.sex,!alt.sex.pictures." means to expire everything subsumed under
  849. alt.sex to 1 day, including the contents of any subgroups of alt.sex.pictures
  850. (like alt.sex.pictures.d), but do not touch the articles in the newsgroup
  851. alt.sex.pictures.
  852. .PP
  853. Blank lines and lines beginning with a "#" are ignored.
  854. A sample function script file:
  855. .PP
  856. .nf
  857. X    # my first function script file
  858. X    0.5    talk,junk,alt.sex.pictures.
  859. X    2    rec,!rec.games,!rec.humor
  860. X    2    misc
  861. .fi
  862. .PP
  863. In the example,
  864. if space is needed, reap
  865. Xexpires to .5 days the entire talk and junk
  866. hierarchies, and alt.sex.pictures (not touching any subgroups of
  867. alt.sex.pictures, such as alt.sex.pictures.d).
  868. If still more space is needed, the
  869. rec hierarchy (excepting all of rec.games.* and rec.humor.*) is expired
  870. to 2 days.  If freespace is still short, reap then expires all of misc
  871. to 2 days.
  872. .PP
  873. Note that, while it would be possible to consolidate the 2-day
  874. lines, leaving them separate makes it possible for reap to stop
  875. in between them if sufficient space is cleared.
  876. .PP
  877. A practical function script file would directly or indirectly
  878. include every group carried on the system, with some age limit.  Otherwise,
  879. the spool directory will inevitably overflow without operator intervention.
  880. .PP
  881. It is valid to specify a dot all by itself (.) in the newsgroup list field.
  882. This is taken to mean the entire spool directory hierarchy, so "14 ." means
  883. to expire all news to 14 days.  Be warned that reap must search the entire
  884. news hierarchy when this feature is used.  Still, it is probably a good
  885. idea to end all function script files with a "0 .", so that, in absolute
  886. desperation, all news would be removed.
  887. .SH FILES
  888. .TP 25
  889. /usr/spool/news
  890. News spool directory
  891. .TP 25
  892. /usr/lib/news/reaplist
  893. Default function list file
  894. .SH DIAGNOSTICS
  895. Returns zero if sufficient space was free at exit, 1 if the entire function
  896. script was executed without freeing enough space, and -1 on an error
  897. condition.
  898. .SH CAVEATS
  899. What constitutes a disk "block" is implementation-dependent.
  900. .PP
  901. History files are not updated.  That must be performed as a separate operation.
  902. .PP
  903. For best performance, exclude recursively (without the dot) whenever
  904. possible.  Otherwise, reap will have to search the excluded directory
  905. for any subdirectories which might not have been excluded, which is slow.
  906. .SH BUGS
  907. The use of the ustat() system call is not very portable, and your humble
  908. author isn't aware of its non-system-V equivalents.
  909. .PP
  910. Lines in the function file are limited to 1024 characters.
  911. .PP
  912. The "cleared" figure in the summary merely indicates the difference in
  913. freespace before and after the run, not necessarily the actual number of
  914. blocks liberated by reap.
  915. .SH AUTHOR
  916. Reap is freeware by David B. Thomas (dt@yenta.alb.nm.us).  You are free
  917. to copy, distribute, staple, bend, fold or mutilate this package to your
  918. heart's content.  Please email any enhancements or ideas for enhancements.
  919. SHAR_EOF
  920. chmod 0644 reap.8 ||
  921. echo 'restore of reap.8 failed'
  922. Wc_c="`wc -c < 'reap.8'`"
  923. test 6129 -eq "$Wc_c" ||
  924.     echo 'reap.8: original size 6129, current size' "$Wc_c"
  925. fi
  926. # ============= reap.c ==============
  927. if test -f 'reap.c' -a X"$1" != X"-c"; then
  928.     echo 'x - skipping reap.c (File already exists)'
  929. else
  930. echo 'x - extracting reap.c (Text)'
  931. sed 's/^X//' << 'SHAR_EOF' > 'reap.c' &&
  932. X
  933. /*
  934. X * reap.c
  935. X *    contains the reap() function.
  936. X *
  937. X * Once the global linked lists incl and excl have been stuffed,
  938. X * reap() actually scans the filesystem for files that meet the specs
  939. X * and unlinks them if they are older than the age global variable.
  940. X */
  941. X
  942. #include "reap.h"
  943. X
  944. X
  945. reap()
  946. {
  947. X    struct filspec    *f;
  948. X
  949. X    for (f = incl; f != NULL; f = f->next) {
  950. X        if (verbose)
  951. X            printf ("scanning %s ...\n", f->name);
  952. X        dodir (f->name, f->recurse);
  953. X    }
  954. X
  955. } /* reap() */
  956. X
  957. X
  958. X
  959. dodir(name, rflag)
  960. char    *name;
  961. int    rflag;
  962. {
  963. X    /* the following can be overwritten safely during recursion */
  964. X    static struct filspec    *e;
  965. X    static struct stat    st;
  966. X    static struct dirent    *dp;
  967. X    static char        thisname[MAXFILENAME+1];
  968. X    /* the following must be preserved through recursion */
  969. X    char            *fullpath;
  970. X    int            eflag = 0;
  971. X    DIR            *dirp;
  972. X
  973. X
  974. /* open directory for reading */
  975. X    if ( (dirp = opendir(name)) == NULL)
  976. X        ouch ("%s: can't read directory %s\n", name);
  977. X
  978. X
  979. /* see if this directory is excluded.
  980. X * If it's excluded recursively, quit here.
  981. X * If it's excluded non-recursively, set a flag, so we won't consider
  982. X *    deleting any files in it, but we'll still explore subdirectories.
  983. X */
  984. X    for (e = excl; e != NULL; e = e->next)
  985. X        if (!strcmp (name, e->name))
  986. X            break;
  987. X    if (e != NULL) {
  988. X        if (e->recurse)
  989. X            return;
  990. X        else
  991. X            ++eflag;
  992. X    }
  993. X
  994. X
  995. /* loop for each directory entry */
  996. X    while ( (dp = readdir(dirp)) != NULL) {
  997. X
  998. X    /* name might be exactly MAXFILENAME characters long, and thus
  999. X     * might not be null-terminated.  Some insurance:
  1000. X     */
  1001. X        strncpy (thisname, dp->d_name, MAXFILENAME);
  1002. X        thisname[MAXFILENAME] = '\0';
  1003. X
  1004. X    /* skip dot and dotdot */
  1005. X        if (!strcmp(thisname, ".") || !strcmp(thisname, ".."))
  1006. X            continue;
  1007. X
  1008. X    /* build the full pathname of current object */
  1009. X        if ( (fullpath =
  1010. X            malloc(strlen(name)+strlen(thisname)+2)) == NULL)
  1011. X            ouch ("%s: out of memory\n");
  1012. X
  1013. X        sprintf (fullpath, "%s/%s", name, thisname);
  1014. X
  1015. X    /* try to stat the object */
  1016. X        if (stat(fullpath,&st)) {
  1017. X            fprintf (stderr, "%s: can't stat %s\n",
  1018. X                progname, fullpath);
  1019. X            free (fullpath);
  1020. X            continue;
  1021. X        }
  1022. X
  1023. X    /* maybe recurse if it's a directory */
  1024. X        if ( st.st_mode & S_IFDIR ) {
  1025. X            if (rflag)
  1026. X                dodir (fullpath, 1);
  1027. X            free (fullpath);
  1028. X            continue;
  1029. X        }
  1030. X
  1031. X    /* it's a file ...  is this a non-recursively excluded directory?
  1032. X     * if so, there's nothing to do to this file
  1033. X     */
  1034. X        if (eflag)
  1035. X            continue;
  1036. X
  1037. X    /* leave it alone if this directory is excluded, or
  1038. X     * if it's new enough.
  1039. X     */
  1040. X        if (eflag || st.st_mtime > age) {
  1041. X            free (fullpath);
  1042. X            continue;
  1043. X        }
  1044. X
  1045. X    /* reap this file! */
  1046. X        if (dryrun) {
  1047. X            printf ("Would unlink %s\n", fullpath);
  1048. X            free (fullpath);
  1049. X            continue;
  1050. X        }
  1051. X        if (verbose)
  1052. X            printf ("Unlinking %s\n", fullpath);
  1053. X
  1054. X        if (unlink (fullpath) == -1)
  1055. X            fprintf (stderr,
  1056. X                "%s: cannot unlink %s\n", progname, fullpath);
  1057. X
  1058. X        free (fullpath);
  1059. X
  1060. X    } /* while */
  1061. X
  1062. X    closedir (dirp);
  1063. X
  1064. } /* dodir() */
  1065. SHAR_EOF
  1066. chmod 0664 reap.c ||
  1067. echo 'restore of reap.c failed'
  1068. Wc_c="`wc -c < 'reap.c'`"
  1069. test 2845 -eq "$Wc_c" ||
  1070.     echo 'reap.c: original size 2845, current size' "$Wc_c"
  1071. fi
  1072. # ============= reap.h ==============
  1073. if test -f 'reap.h' -a X"$1" != X"-c"; then
  1074.     echo 'x - skipping reap.h (File already exists)'
  1075. else
  1076. echo 'x - extracting reap.h (Text)'
  1077. sed 's/^X//' << 'SHAR_EOF' > 'reap.h' &&
  1078. X
  1079. /*
  1080. X * reap.h
  1081. X *    header file for reap utility
  1082. X */
  1083. X
  1084. /* set MAXFILENAME to the maximum number of characters in a filename for
  1085. X * your system.  Typically 14 or infinity, where infinity equals
  1086. X * 256 characters. :-)
  1087. X */
  1088. #define MAXFILENAME    14
  1089. X
  1090. /* set NEWSDIR to the directory containing news on your system.
  1091. X * Very commonly /usr/spool/news
  1092. X */
  1093. #define NEWSDIR        "/usr/spool/news"
  1094. X
  1095. /* set SCRIPT to the path of the default function script file
  1096. X * Usually this is /usr/lib/news/reaplist
  1097. X */
  1098. #define SCRIPT        "/usr/lib/news/reaplist"
  1099. X
  1100. X
  1101. X
  1102. X
  1103. #include <stdio.h>
  1104. #include <string.h>
  1105. #include <ctype.h>
  1106. #include <time.h>
  1107. #include <malloc.h>
  1108. #include <sys/types.h>
  1109. #include <sys/stat.h>
  1110. #include <ustat.h>
  1111. #include <dirent.h>
  1112. X
  1113. #define MAXLINE        1024        /* max len of line in script    */
  1114. #define SECINDAY    (3600 * 24)    /* seconds in a day        */
  1115. X
  1116. /* structure for linked lists of included and excluded file specs */
  1117. struct filspec {
  1118. X    char        *name;
  1119. X    int        recurse;
  1120. X    struct filspec    *next;
  1121. };
  1122. X
  1123. Xextern struct filspec
  1124. X        *incl,
  1125. X        *excl
  1126. ;
  1127. Xextern char
  1128. X        *progname,
  1129. X        *scriptfile,
  1130. X        *newsdir
  1131. ;
  1132. Xextern int
  1133. X        verbose,
  1134. X        dryrun,
  1135. X        optind
  1136. ;
  1137. Xextern char    *optarg;
  1138. Xextern double    atof();
  1139. Xextern long    freeblox();
  1140. Xextern time_t
  1141. X        age,
  1142. X        now
  1143. ;
  1144. SHAR_EOF
  1145. chmod 0664 reap.h ||
  1146. echo 'restore of reap.h failed'
  1147. Wc_c="`wc -c < 'reap.h'`"
  1148. test 1195 -eq "$Wc_c" ||
  1149.     echo 'reap.h: original size 1195, current size' "$Wc_c"
  1150. fi
  1151. exit 0
  1152. -- 
  1153. Bottom of stack = 0x40000
  1154. Stack pointer   = 0x3fffe
  1155. Don't push it!
  1156.