24-Jan-86 23:53:43-MST,5553;000000000001
Return-Path: <[email protected]>
Received: from BRL-TGR.ARPA by SIMTEL20.ARPA with TCP; Fri 24 Jan 86 23:53:31-MST
Received: from usenet by TGR.BRL.ARPA id a007733; 25 Jan 86 0:00 EST
From: [email protected]
Newsgroups: mod.sources
Subject: prune.c - prunes log files
Message-ID: <[email protected]>
Date: 24 Jan 86 14:04:13 GMT
Sender: [email protected]
Approved: [email protected]
To:       [email protected]

Mod.sources:  Volume 3, Issue 95
Submitted by: genrad!ihnp4!infoswx!bees (Ray Davis)


John,

The following is a program I wrote to "prune" log files.  The purpose
of this is to keep files that keep getting larger from getting too
large.  I became annoyed at having to search and remember where these
files are, then make them smaller by hand, every time disk space gets
tight.  I also didn't like the idea of having a separate cron entry for
every log file I wanted to deal with.

While prune is not extremely robust, it is very functional.  It
compiles and runs as is under 4.2BSD.  I have not tested it under
System * or Xenix, however I believe it should run as is or with little
modification.

       Ray Davis               Teknekron Infoswitch Corporation
       ihnp4!infoswx!bees      1784 Firman Drive
       (214)644-0570           Richardson, Texas   75081

. . . . . . . . . . . . . . . . Clip Here . . . . . . . . . . . . . . . . .
/*
*      prune - clips off the tops of a list of files described in the
*              file /etc/prune_list. Designed to be run periodically
*              from cron, the idea is to automatically shorten log
*              files that grow forever. This file contains a list of
*              files (full pathname), and the number of blocks that
*              should be retained.  To retain some sanity, prune will
*              clip the file after the next newline. The file
*              /etc/prune_list should look something like:
*
*                      /usr/adm/aculog         10
*                      /usr/adm/leo.log        5
*                      /usr/adm/messages       200
*                      /usr/adm/sup_log        5
*
*              The crontab entry on infoswx for prune looks like:
*
*                      0 5 * * * /etc/prune >/usr/adm/prune.log 2>&1
*
*              Compile with:  cc -O -o prune prune.c
*
*              The following defines may be adjusted to suit your taste
*              and your system block size.
*
*      Ray Davis  infoswx!bees  09/25/85
*/

#define PRUNELIST       "/etc/prune_list"
#define BLOCKSIZE       1024

#ifdef USG      /* for System III, System V, or Xenix */
#define index           strchr
#endif

#define FALSE           (0)
#define TRUE            (~0)
#define REWIND(F)       (lseek(F,0,0))

#include        <sys/types.h>
#include        <sys/stat.h>
#include        <sys/file.h>
#include        <stdio.h>

extern  int     errno;
extern  char    *index();
char    tempfile[] = "/usr/tmp/prune:XXXXXX";

main(argc, argv)
int     argc;
char    **argv;
{
       int     pfd,
               tfd,
               cfd,
               nblocks,
               new_line_found,
               bytes_read,
               nlbytes;
       char    file[128],
               block[BLOCKSIZE+1],
               *nl;
       long    nbytes;
       FILE    *pstream;
       struct  stat    cstat;

       block[BLOCKSIZE] = '\0';

       /* open prune list */
       if ((pfd = open(PRUNELIST, O_RDONLY)) < 0)
               errabort(*argv, "open", PRUNELIST, TRUE);
       pstream = fdopen(pfd, "r");

       /* create unique tempfile */
       mktemp(tempfile);

       /* while read each filename & #blocks */
       while ((fscanf(pstream, "%s%d", file, &nblocks)) != EOF) {
               fprintf(stderr, "pruning %s to %d blocks\n", file, nblocks);
               /* open filename */
               if ((cfd = open(file, O_RDWR)) < 0) {
                       errabort(*argv, "open", file, FALSE);
                       continue;
               }
               /* seek #blocks from the end of file */
               nbytes = - (nblocks * BLOCKSIZE);
               if ((fstat(cfd, &cstat)) < 0) {
                       errabort(*argv, "fstat", file, FALSE);
               } else {
                       if (cstat.st_size <= -(nbytes)) {
                               fprintf(stderr, "%s: %s: not large enough to prune\n", *argv, file);
                       } else {
                               if ((lseek(cfd, nbytes, 2)) < 0) {
                                       fprintf(stderr, "%s: %s: error on seek\n", *argv, file);
                               } else {
                                       /* open tempfile */
                                       if ((tfd = open(tempfile, O_CREAT|O_RDWR|O_TRUNC, 0600)) < 0)
                                               errabort(*argv, "open", tempfile, TRUE);
                                       /* copy to tempfile */
                                       new_line_found = FALSE;
                                       while ((bytes_read = read(cfd, block, BLOCKSIZE)) > 0) {
                                               if (new_line_found) {
                                                       if ((write(tfd, block, bytes_read)) != bytes_read)
                                                               errabort(*argv, "write", tempfile, FALSE);
                                               } else {
                                                       if ((nl = index(block, '\n')) == NULL) {
                                                               nl = block;
                                                       } else {
                                                               nl++;
                                                               new_line_found = TRUE;
                                                       }
                                                       nlbytes = bytes_read - (nl - block);
                                                       if ((write(tfd, nl, nlbytes)) != nlbytes)
                                                               errabort(*argv, "write", tempfile, FALSE);
                                               }
                                       }
                                       if (bytes_read < 0) {
                                               errabort(*argv, "read", file, FALSE);
                                       } else {
                                               /* re-open filename to truncate */
                                               close(cfd);
                                               if ((cfd = open(file, O_RDWR|O_TRUNC)) < 0) {
                                                       errabort(*argv, "re-open", file, FALSE);
                                                       continue;
                                               }
                                               /* overwrite file with tempfile */
                                               REWIND(tfd);
                                               while ((bytes_read = read(tfd, block, BLOCKSIZE)) > 0) {
                                                       if ((write(cfd, block, bytes_read)) != bytes_read)
                                                               errabort(*argv, "write", file, FALSE);
                                               }
                                               if (bytes_read < 0)
                                                       errabort(*argv, "read", tempfile, FALSE);
                                       }
                               }
                       }
               }
               close(cfd);
               close(tfd);
       }
       /* remove tempfile */
       unlink(tempfile);
       exit(0);
}

errabort(program, function, filename, should_exit)
char    *program,
       *function,
       *filename;
int     should_exit;
{
       char    errbuff[128];

       sprintf(errbuff, "%s: %s(%s)", program, function, filename);
       perror(errbuff);
       if (should_exit)
               exit(errno);
}
/* end of prune.c */