#! /usr/bin/perl -w
use strict;

# $Id: logrotate.perl,v 1.6 2002/01/28 14:43:53 khera Exp $

use constant USAGE => "usage:logrotate [-z] [-p PID] [-s SIG] -r N file...\n";

use IO::File;
use Getopt::Std;

my %opt = ();
getopts('zp:s:r:',\%opt);

scalar(@ARGV) or die USAGE;	# are there files specified?
die USAGE unless $opt{'r'};

# rotate the named log file and archive $howmany old versions.  eg,
#   rotate("foo",3);
# will move foo -> foo.0 -> foo.1 -> foo.2 -> foo.3
# and remove old foo.3, then create empty foo.

sub rotate ($$) {
  my($file,$howmany) = @_;
  my($cur);

  return if ($howmany < 0);

  unlink ("$file.$howmany","$file.$howmany.gz"); # remove topmost one.

  for ($cur = $howmany; $cur > 0; $cur--) {
    my $prev = $cur - 1;
    rename("$file.$prev","$file.$cur") if (-f "$file.$prev");
    rename("$file.$prev.gz","$file.$cur.gz") if (-f "$file.$prev.gz");
  }

  rename("$file","$file.0");    # move original one

  # create the new one!
  my $fh = new IO::File $file, O_WRONLY|O_CREAT, 0644;
  $fh->close();
}

# first rotate the files
foreach my $file (@ARGV) {
  rotate ($file,$opt{'r'});
}

# now send the signal, if necessary.  Default signal is HUP.
if ($opt{'p'}) {
  my $sig = $opt{'s'} || 'HUP';
  unless (kill $sig, $opt{'p'}) {
    warn "Failed to send $sig to $opt{'p'}\n";
    warn " -- disabling compression of file\n" if (delete $opt{'z'});
  }
}

# and finally compress the newly rotated files, if requested
if ($opt{'z'}) {
  foreach my $file (@ARGV) {
    system "gzip $file.0";
  }
}

exit(0);

__END__
=pod

=head1 NAME

logrotate - rotate and compress log files

usage: C<logrotate [-z] [-p PID] [-s SIG] -r N file...>

=head1 README

Rotate log files and optionally send a signal (default is HUP) to the
specified process ID, then optionally compress the newly rotated log
file(s).  As many different log files may be specified on the command line
as desired.

Command line options:

=over 4

=item -z

This option causes the newly rotated log file to be gzip compressed.

=item -p PID

Sends a signal, default C<HUP>, to the C<PID> specified after the
rotation is done, but before optional compression is started.

=item -s SIG

Changes the signal sent under the C<-p> option to the one named (either
symbolic or numeric).

=item -r N

Keep C<N> old log files named as F<file.0>, F<file.1>, ..., F<file.N>.

This flag is mandatory.

=back

=head1 PREREQUISITES

Requires C<IO::File> and C<Getopt::Std>.  Also required F<gzip> if you
want to compress your files.  I suppose it would make sense to use a
Perl gzip module to do the compression, but they were not available when
I first wrote this program.

=head1 SCRIPT CATEGORIES

UNIX/System_administration

=head1 BUGS

Very lazy about error checking of renames and file creations.

=head1 AUTHOR

Vivek Khera <vivek@khera.org>

Copyright 1999-2001 Vivek Khera.  This program is distributed under the
same terms as Perl itself.  Please refer to the Perl license for
details.

=cut