[alt.sources] Smart News Expire Program

johnl@n3dmc.svr.md.us (John Limpert) (11/06/90)

I wrote this after becoming tired of file system overflows caused
by the use of a fixed cutoff time for expire.  News volume is
erratic enough to cause problems for systems with small disks.
This program will dynamically adjust the expire cutoff time and
only run expire when free space is marginal.  As currently
configured the program will expire the oldest 1/3 of news whenever
file system free space is less than 10% of total file system space.

The program uses the statfs(2) system call provided by System V
Release 3 to determine total and free space on the news file system.

Compile with:
	cc -O expired.c -o expired

Run it out of /etc/rc or your system's equivalent.

#!/bin/sh
# This is a shell archive (shar 3.32)
# made 11/06/1990 07:05 UTC by johnl@n3dmc.svr.md.us
# Source directory /usr/johnl
#
# existing files WILL be overwritten
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   4345 -rw-r--r-- expired.c
#
if touch 2>&1 | fgrep 'amc' > /dev/null
 then TOUCH=touch
 else TOUCH=true
fi
# ============= expired.c ==============
echo "x - extracting expired.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > expired.c &&
X/*
X * expired.c
X * 11/6/90
X * John A. Limpert (johnl@n3dmc.svr.md.us)
X *
X * 'smart' news expiration daemon for UNIX System V Release 3
X *
X * This program will expire the oldest 1/3 of news whenever
X * free space is less than 10% on the news filesystem.
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/statfs.h>
X#include <sys/stat.h>
X#include <signal.h>
X#include <errno.h>
X#include <time.h>
X#include <string.h>
X
X#ifndef SPOOL
X#define SPOOL	"/usr/spool/news"		/* news spool directory */
X#endif
X
X#ifndef ETFILE
X#define ETFILE	"/usr/lib/news/expire_time"	/* expiration cutoff time */
X#endif
X
X#ifndef LOGFILE
X#define LOGFILE	"/usr/lib/news/expired.log"	/* expired log file */
X#endif
X
X#ifndef MINFREE
X#define MINFREE	0.1				/* desired free space */
X#endif
X
X/* prototype expire command */
X#ifndef CMD
X#define CMD	"/bin/su news -c \"/usr/lib/news/expire -e%f -E%f\""
X#endif
X
X/* seconds in day */
X#define DAY	(24L*60L*60L)
X
Xstruct utimbuf {
X  time_t actime;	/* access time */
X  time_t modtime;	/* modification time */
X};
X
X/* external */
Xextern void exit();
Xextern void perror();
Xextern unsigned sleep();
Xextern time_t time();
X
X/* forward */
Xextern time_t get_mtime();
Xextern void log();
Xextern void set_mtime();
X
X/* program name */
Xchar *pname;
X
X/*ARGSUSED*/
Xint
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X  struct statfs part_stat;
X  time_t delta, now, oldest_news;
X  double keep;
X  char cmdbuf[256];
X  int pid;
X  long minfree;
X
X  pname = argv[0];
X
X  /* ignore user signals */
X  (void) signal(SIGHUP, SIG_IGN);
X  (void) signal(SIGINT, SIG_IGN);
X  (void) signal(SIGQUIT, SIG_IGN);
X
X  /* go into background */
X  if ((pid = fork()) < 0) {
X    perror(pname);
X    exit(1);
X  }
X  if (pid != 0)
X    exit(0);
X
X  log("running...");
X
X  for (;;) {
X    /* wait for exhaustion of disk space */
X    for (;;) {
X      if (statfs(SPOOL, &part_stat, sizeof(struct statfs), 0) < 0) {
X	perror(SPOOL);
X	exit(1);
X      }
X
X      minfree = part_stat.f_blocks*MINFREE;
X
X      if (part_stat.f_bfree < minfree)
X	break;
X
X      (void) sleep(60);
X    }
X
X    /* discard oldest 1/3 of news */
X    oldest_news = get_mtime(ETFILE);
X    now = time((time_t *) 0);
X    delta = now - oldest_news;
X    delta = (delta*2)/3;
X    oldest_news = now - delta;
X    set_mtime(ETFILE, oldest_news);
X    keep = ((double) delta)/((double) DAY);
X
X    /* generate expire command */
X    sprintf(cmdbuf, CMD, keep, keep);
X
X    /* update log file */
X    log(cmdbuf);
X
X    /* run expire */
X    if (system(cmdbuf) < 0) {
X      perror(pname);
X      exit(1);
X    }
X  }
X  /*NOTREACHED*/
X}
X
X/* get_mtime -- get modification time of specified file */
X
Xtime_t
Xget_mtime(path)
Xchar *path;
X{
X  struct stat file_stat;
X  struct utimbuf ut;
X  int fd;
X
X  /* does file exist? */
X  if (stat(path, &file_stat) < 0 && errno == ENOENT) {
X    /* create it */
X    if ((fd = creat(path, 0)) < 0) {
X      perror(path);
X      exit(1);
X    }
X    if (close(fd) < 0) {
X      perror(path);
X      exit(1);
X    }
X    /* backdate two weeks */
X    ut.actime = ut.modtime = time((time_t *) 0) - 14L*DAY;
X    if (utime(path, &ut) < 0) {
X      perror(path);
X      exit(1);
X    }
X  }
X
X  /* get inode info */
X  if (stat(path, &file_stat) < 0) {
X    perror(path);
X    exit(1);
X  }
X
X  /* return modification time */
X  return file_stat.st_mtime;
X}
X
X/* set_mtime -- set modification and access time of specified file */
X
Xvoid
Xset_mtime(path, t)
Xchar *path;
Xtime_t t;
X{
X  struct stat file_stat;
X  struct utimbuf ut;
X  int fd;
X
X  /* does file exist? */
X  if (stat(path, &file_stat) < 0 && errno == ENOENT) {
X    /* create it */
X    if ((fd = creat(path, 0)) < 0) {
X      perror(path);
X      exit(1);
X    }
X    if (close(fd) < 0) {
X      perror(path);
X      exit(1);
X    }
X  }
X
X  /* record time in file inode */
X  ut.actime = ut.modtime = t;
X  if (utime(path, &ut) < 0) {
X    perror(path);
X    exit(1);
X  }
X}
X
X/* log -- write time tagged string to log file */
X
Xvoid
Xlog(s)
Xchar *s;
X{
X  FILE *logf;
X  time_t t;
X  char *p, tbuf[32];
X
X  /* open log file */
X  if ((logf = fopen(LOGFILE, "a")) == NULL) {
X    fprintf(stderr, "%s: can't append to %s\n", pname, LOGFILE);
X    exit(1);
X  }
X
X  /* time in ASCII without newline */
X  t = time((time_t *) 0);
X  (void) strcpy(tbuf, ctime(&t));
X  if ((p = strchr(tbuf, '\n')) != NULL)
X      *p = '\0';
X
X  /* append time tagged entry to log file */
X  fprintf(logf, "%s: %s\n", tbuf, s);
X  fclose(logf);
X}
SHAR_EOF
$TOUCH -am 1106020590 expired.c &&
chmod 0644 expired.c ||
echo "restore of expired.c failed"
set `wc -c expired.c`;Wc_c=$1
if test "$Wc_c" != "4345"; then
	echo original size 4345, current size $Wc_c
fi
exit 0
-- 
John A. Limpert		The strongest reason for the people to retain the right
johnl@n3dmc.svr.md.us	to keep and bear arms is, as a last resort, to protect
uunet!n3dmc!johnl	themselves against tyranny in government.  T. Jefferson.