[alt.sources] cyclelog - trim logfiles to a manageable size

admin@cs.exeter.ac.uk (Khalid Sattar) (10/02/90)

A while back I picked up a shell script called agelog from the net.
This allowed a convient way of trimming logfiles.  Based on that idea I
have rewritten the script in perl with many more options.  The
most useful (to me) is compression of old logfiles.  Comments and
suggestions welcomed

#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 10/02/1990 10:38 UTC by admin@expya
# Source directory /u4/src/cyclelog
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   2782 -rw-r----- cyclelog.8
#   4329 -rwxr-x--x cyclelog
#
# ============= cyclelog.8 ==============
if test -f 'cyclelog.8' -a X"$1" != X"-c"; then
	echo 'x - skipping cyclelog.8 (File already exists)'
else
echo 'x - extracting cyclelog.8 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'cyclelog.8' &&
.\" -*-nroff-*-
.\" eg of a TH
.\" .TH submit 1 local "Updated: 20/09/90" "Exeter University"
.TH CYCLELOG 8 local "Updated: 20/Sep/90" "Exeter University"
.SH NAME
cyclelog - roll logfile within a given range
.SH SYNOPSIS
cyclelog [options] logfile\d1\u [logfile\d2\u ... ]
.SH DESCRIPTION
\fBcyclelog\fR is a program to help maintain logfiles within the
system.  Many programs generate large logfiles (eg syslog).  From time
to time these files have to be trimmed to stop filling up of disk
space.  \fBcyclelog\fR rolls the specified files by moving the
original \fIlogfile\fR to \fIlogfile\fR.1 and copying /dev/null to the
original file.  In fact you can specify how many old files to keep
(see option -n below) which means that you will have logfile.1 \(->
logfile.\fIn\fR.
.LP
Logfile can optionally be compressed and you can also specify from
which logfile to start (this is useful if you have other summary
generating programs that work on recent logfiles).
.SH OPTIONS
.IP "-\fBn\fR \fInum\fR"
How many logfiles to keep, 1 \(-> \fInum\fR.  It will thus roll
\fIlogfile\fR.n-1 \(-> \fIlogfile\fR.n ... \fIlogfile\fR to
\fIlogfile\fR.1. The default value is 1.  If \fIn\fR is 0 then simply
the original logfile will be truncated to 0 but no rolling is done
(i.e. no \fIlogfile\fR.1 etc.)
.IP "-\fBd\fR \fIdir\fR"
The directory where to stash the logfiles.  The default is the same
directory where the original logfile is.
.IP "-\fBo\fR \fIowner\fR"
Set the owner of the logfiles to \fIowner\fR.
.IP "-\fBg\fR \fIgroup\fR"
Set the group of the logfiles to \fIgroup\fR.
.IP "-\fBz\fR"
Keep the logifiles in compressed form.
.IP "-\fBs\fR \fIn\fR"
If compression mode is on then start compression from logfile \fIn\fR.
The default is 1.
.IP "-\fBm\fR mode"
The mode of the logfile is \fImode\fR (give octal representation).  If
this option is not specifed then the mode of the original logfile is
used.
.IP "-\fBv\fR"
Verbose mode - tells you what its doing.
.IP "-\fBV\fR"
Prints version number and then exits.
.SH EXAMPLES
To keep upto 8 logfile of the syslog file in /usr/spool/log directory.
.nf
X
X	cyclelog -n 8 /usr/spool/log/syslog
X
.fi
Keep 4 log files of \fBlog\fR and \fBerrlog\fR from /usr/lib/news
directory.  The logfiles are to be kept in /usr/local/logs with mode
640 and logfiles from 3 onwards are kept in compressed form:
.nf
X
X	cyclelog -n 4 -d /usr/local/logs -m 640 -z -s 3 /usr/lib/news/{log,errlog}
X
.fi
Thus the following files will be maintained in /usr/local/logs
.nf
X
X	log.1, log.2, log.3.Z, log.4.Z
X	errlog.1, errlog.2, errlog.3.Z, errlog.4.Z
.fi
.SH BUGS
Files that are too small to be compressed are simply renamed to have a
\&.Z suffix.  This can be confusing.
.SH AUTHOR
K.Sattar@uk.ac.exeter.cs
.br
Computer Science Dept.
.br
University of Exeter
SHAR_EOF
chmod 0640 cyclelog.8 ||
echo 'restore of cyclelog.8 failed'
Wc_c="`wc -c < 'cyclelog.8'`"
test 2782 -eq "$Wc_c" ||
	echo 'cyclelog.8: original size 2782, current size' "$Wc_c"
fi
# ============= cyclelog ==============
if test -f 'cyclelog' -a X"$1" != X"-c"; then
	echo 'x - skipping cyclelog (File already exists)'
else
echo 'x - extracting cyclelog (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'cyclelog' &&
#!/usr/bin/perl --  # -*-Perl-*-
#
# cyclelog - roll log file within a give number.   Thus logfile.n-1
#            => logfile.n, logfile.n-2 => logfile.n-1 ... logfile =>
#            logfile.1.
#            
#	-z	compress
#       -s n    start compression of files from nth logfile
#       -n n    keep n file starting at 1 .. n
#       -d dir  keep the logfile in dir directory
#       -v      verbose mode
#       -V    	print version and exit
#	-m mode mode of the logfile
#       -g grp 	group of the log file
#	-o owner owner of the logfile
#
X
#*** config part for different systems
$copy = "/bin/cp";
$compress = "/usr/ucb/compress";
#*** end config
X
do 'getopts.pl';
&Getopts("o:m:g:zn:d:s:Vv");
X
die '$Header: cyclelog,v 1.2 90/09/20 10:28:46 admin Exp $'."\n" if $opt_V;
X
# map owner to its uid
if ($opt_o)  {
  @entry=getpwnam($opt_o);
  if ($#entry == -1) {
    die "There is no user called \"$opt_o\"\n";
  }
  print "Owner setting: \"$opt_o\" maps to uid $entry[2]\n" if $opt_v;
  $opt_o = $entry[2];
}
X
# map group to its gid
if ($opt_g)  {
  @entry=getgrnam($opt_g);
  if ($#entry == -1) {
    die "There is no group called \"$opt_g\"\n";
  }
  print "Group setting: \"$opt_g\" maps to uid $entry[2]\n" if $opt_v;
  $opt_g = $entry[2];
}
X
if ($opt_m) {			# convert mode given in octal to decimal
  $opt_m = oct($opt_m);
}
X
$max = (defined($opt_n)) ? $opt_n : 1;	# how many logfiles, 1 ... n
$zstart = ($opt_s) ? $opt_s : 1; # if compressing then where to
                                 # start compression from
X
# for each logfile specified - roll
while ($file = shift) {
  print ">>> $file\n" if $opt_v;
  if (-e $file) {
    $dir = &setdir($file,$opt_d);
    &roll($file,$dir,$max);
  } else {
    warn "\t$file does not exist\n";
  }
}
  
# determine where the logfile are going to be statched
X
sub setdir {
  local($file,$dir) = @_;
X
  if (!$dir) {
    if ($file =~ /(.*\/).*/) {
      $dir = $1;
    } else {
      $dir = "./";
    }
  }
  if ($dir !~ /\/$/) {
    $dir .= "/";
  }
X
  if (! -w $dir) {
    warn "\t\"$dir\" - does not exist or is not writable - set to /tmp.\n";
    $dir = "/tmp/";
  }
  print "\tlogdir is \"$dir\"\n" if $opt_v;
  $dir;
}
X
# roll the file 
sub roll {
  local($file,$dir,$max) = @_;
  local($older,$error,$filepart,$dest) = ($max,0,'','');
    
# get just the filename - /a/b/c/d => d
  if ($file =~ /.*\//) {
    $filepart = $';		# ' ignore this comment
  } else {
    $filepart = $file;
  }
X
  $dest = "$dir$filepart";
  while ($older> 1) {
    $old = $older - 1;
    
    if ($opt_z) {
      if ($older > $zstart) {
        $sz = ".Z";
        $dz = ".Z";
      } elsif ($older == $zstart && -f "$dest.$old") {
        system("$compress $dest.$old");
        if (($? >> 8) == 2) {	# get exit value of compress
          $sz = "";
        } else {
          $sz = ".Z";
        }
        $dz = ".Z";
      } else {
        $sz = "";
        $dz = "";
      }
    }
    if (-f "$dest.$old$sz") {
      print "\tmv $dest.$old$sz => $dest.$older$dz\n" if $opt_v;
      rename("$dest.$old$sz","$dest.$older$dz") ||
X	warn "rename of $dest.$old$sz => $dest.older$dz failed: $!\n";
    }
    $older--;
  }
  if (-f $file) { 
    if ($max > 0) {
      print("\t$copy $file $dest.1\n") if $opt_v;
      system("$copy $file $dest.1");
      if (($? >> 8) == 0) {
X	@entry = stat($file);
X	if ($opt_o || $opt_g) {
X	  $owner = ($opt_o) ? $opt_o : $entry[4];
X	  $group = ($opt_g) ? $opt_g : $entry[5];
X	  printf "\tchown and group to $owner and $group\n" if $opt_v;
X	  chown($owner,$group,"$dest.1") || warn "\tchown failed: $!\n";
X	}
X	if ($opt_m) {
X	  chmod($opt_m,"$dest.1");
X	  printf("\tchmod %0o $dest.1\n",$opt_m) if $opt_v;
X	} else {
X	  printf("\tchmod %0o $dest.1\n",$entry[2]) if $opt_v;
X	  chmod($entry[2],"$dest.1") || warn "\tchmod failed: $!\n";
X	}
X	if ($opt_z && $zstart == 1) {
X	  system("$compress $dest.1");
X	  print("\t$compress $dest.1\n") if $opt_v;
X	  if (($? >> 8) == 2) {	# get exit value of compress
            rename("$dest.1","$dest.1.Z");
            print("\tDidn't compress, mv $dest.1 => $dest.1.Z\n") if $opt_v;
          }
X	}
      } else {
        warn "\tcopy of $file to $dest.1 failed: $!\n";
        $error=1;
      }
    }
    if (! $error) {
      system("$copy /dev/null $file");
      print("\t$copy /dev/null $file\n") if $opt_v;
    }
  }
}
SHAR_EOF
chmod 0751 cyclelog ||
echo 'restore of cyclelog failed'
Wc_c="`wc -c < 'cyclelog'`"
test 4329 -eq "$Wc_c" ||
	echo 'cyclelog: original size 4329, current size' "$Wc_c"
fi
exit 0
--
Khalid Sattar                   JANET    : K.Sattar@uk.ac.exeter.cs 
Computer Science Dept.          UUCP     : K.Sattar@expya.uucp
University of Exeter            INTERNET : K.Sattar@cs.exeter.ac.uk
Exeter, UK.                     Tel      : +44 392 264062