#!/opt/gnu/bin/perl
# $Id: rotatelogs.pl,v 1.10 2000/10/16 14:33:32 cgilmore Exp $
#
# Author          : Christian Gilmore
# Created On      : Wed Mar 19 13:36:59 EST 1997
# Status          : Functional
# 
# NAME
#       rotatelogs.pl
#    
# PURPOSE
#       Rotates logs created by apache on a regular interval defined by
#       webgpid's crontab on basket
#
# SWITCHES
#       none
# 
###############################################################################


# Location of non-standard libraries and included files
use lib qw(/opt/gnu/depot/tivwebtools-1.0/lib/perl);


# Required libraries
use strict;
use DirHandle;
use FileHandle;
use Time::Object;


# Environment Variables
$ENV{'PATH'} = q(/usr/bin:) . $ENV{'PATH'};


# Process globals


#Globals
use constant APACHEDIR => q(/opt/apache);
use constant LOGSDIR   => q(logs);
use constant STOP      => q(bin/stop);
use constant START     => q(bin/start);
my %LOGTYPES  =
(
 'access_log'       => 1, 
 'cgi_log'          => 1,
 'error_log'        => 1,
 'misc_log'         => 1,
 'raven_cipher_log' => 1,
 'raven_ssl_log'    => 1,
 'rewrite_log'      => 1,
 'script_log'       => 1,
 'ssl_log'          => 1,
 'suexec_log'       => 1,
);


###############################################################################
###############################################################################
# Main Program
###############################################################################
###############################################################################
{
  my $rate = shift(@ARGV) || 'daily';

  my $time = localtime;
  my ($file, $service) = undef;

  my $services = &get_services;
  my $movedir = &get_movedir($rate, $time);

  foreach $service (@$services) {
    &do_cleanup($service, $time);
    &create_dir("$service/@{[ LOGSDIR ]}/$movedir") 
      unless (-d "$service/@{[ LOGSDIR ]}$movedir");

    chdir("$service/@{[ LOGSDIR ]}") or next;
    opendir(DIR, ".") or next;
    my @allfiles = grep(!/^\./, readdir(DIR));

    my $stop = $service . q(/) . STOP;
    my $start = $service . q(/) . START;
    next unless (-f $stop);

    my @args = ($stop);
    if (&running($service)) {
      unless(system(@args) == 0) { 
	warn "system @args failed: $?\n";
	next;
      }
    }

    foreach $file (@allfiles) {
      if (exists($LOGTYPES{$file})) {
	my $movefile = $movedir . q(/) . $file . q(.) . $time->hms;
	@args = ('mv', $file, $movefile);
	system(@args) == 0 or
	  warn "system @args failed: $?\n";
	@args = ('touch', $file);
	system(@args) == 0 or warn "system @args failed: $?\n";
      }
    }

    my $i;
    for ($i = 0; $i < 60; $i++) {
      if (&running($service)) {
	sleep(1);
      }
    }
    @args = ($start);
    system(@args) == 0 or warn "system @args failed: $?\n";

    close(DIR);
  }

  exit(0);
}

###############################################################################
###############################################################################
# get_services: Get the set of web services on this host
###############################################################################
###############################################################################
sub get_services {
  my @servers = ();
  my @services = ();

  my $dir = DirHandle->new(APACHEDIR);
  die "Cannot open directory ", APACHEDIR, ": $!\n" unless defined($dir);
  while (defined($_ = $dir->read)) {
    unless (/^\./) {
      push(@servers, "@{[ APACHEDIR ]}/$_");
    }
  }
  $dir = undef;

  my $server = undef;
  foreach $server (@servers) {
    next unless -d $server;
    $dir = DirHandle->new($server);
    die "Cannot open directory $server: $!\n" unless defined($dir);
    while (defined($_ = $dir->read)) {
      if (/^\d+$/) {
	push(@services, "$server/$_");
      }
    }
  }

  return \@services;
}

###############################################################################
###############################################################################
# get_movedir: Get the directory to which we will move the logs
###############################################################################
###############################################################################
sub get_movedir {
  my ($rate, $time) = @_;
  my ($day, $mon, $movedir, $year) = undef;

  $year = $time->year;
  $mon = $time->mon if $time->mon > 9;
  $mon = q(0) . $time->mon if $time->mon < 10;
  $day = $time->mday if $time->mday > 9;
  $day = q(0) . $time->mday if $time->mday < 10;

  $movedir = $year . q(/) . $mon . q(/) . $day;
  
  return $movedir;
}

###############################################################################
###############################################################################
# do_cleanup: Cleanup old logs
###############################################################################
###############################################################################
sub do_cleanup {
  my ($service, $time) = @_;
  my ($deldir, $delmon, $delyear) = undef;

  if ($time->mon == 2) { 
    $delmon = 12;
    $delyear = $time->year - 1;
  } elsif ($time->mon == 1) { 
    $delmon = 11;
    $delyear = $time->year - 1;
  } else { 
    $delmon = $time->mon - 2; 
    $delyear = $time->year;
  }
  if ($delmon < 10) { 
    $delmon = "0$delmon"; 
  }

  $deldir = "$service/@{[ LOGSDIR ]}/$delyear/$delmon";
  if (-d $deldir) {
    my @args = ('rm', '-f', "$deldir/*");
    system(@args) == 0 or warn "system @args failed: $?\n";
  }
}

###############################################################################
###############################################################################
# create_dir: backward-recursively create a directory
###############################################################################
###############################################################################
sub create_dir {
  my ($dir) = @_;
  my ($parent);

  $dir =~ /(.*)\/[^\/]*$/;
  $parent = $1;
  unless (-d $parent) {
    &create_dir($parent);
  }
  mkdir($dir, 0755);
}

###############################################################################
###############################################################################
# running: determine if a service is running
###############################################################################
###############################################################################
sub running {
  my $service = shift;

  $service .= '/bin/httpd';
  my @ps = `ps -ef | grep $service | grep -v grep`;
  return scalar(@ps);
}

1;

__END__

# Documentation - try 'pod2text httpd_control'


=head1 NAME

rotatelogs.pl - rotate apache log files

=head1 SYNOPSIS

rotatelogs.pl rate

=head1 DESCRIPTION

Rotatelogs.pl rotates the various logs files generated by the
apache web server including, but not limited to, access_log and
error_log. The location to which rotatelogs.pl rotates these log
files is determined by the I<rate> argument.

This software is very site specific. It requires that all apache
web servers whose logs will be rotated exist in the
/opt/apache/<service_name>/<service_port> structure and that each
service has a bin directory that contains scripts named I<start>
and I<stop>.

=head1 OPERANDS

I<rate>
     The rate at which the log files are rotated. Valid
     rates are: hourly, daily, and monthly.

=head1 OPTIONS

Command-line options are ignored. 

=head1 EXAMPLE

The following command:

     % rotatelogs.pl daily

will stop all web services running on this host, rotate out the
log files to <year>/<month>/<day>/<logname>:HH:MM:SS under each
service's logs directory, and restart the web services.

=head1 AUTHOR

Christian Gilmore (C<cgilmore@tivoli.com>)

=head1 SEE ALSO

crontab(1), httpd(8), httpd_control(1)

=head1 NOTES

Rotatelogs.pl relies upon crontab to determine the schedule by
which rotatelogs.pl is run. Rotatelogs.pl uses the rate argument
solely to determine where it should deposit files. It does not us
the rate argument to determine whether is should move the files.

=cut

###############################################################################
###############################################################################
# $Log: rotatelogs.pl,v $
# Revision 1.10  2000/10/16 14:33:32  cgilmore
# appended /bin/httpd to service name during running checks
#
# Revision 1.9  2000/10/13 06:31:36  cgilmore
# uppded timeout on restarts to 60 seconds
#
# Revision 1.8  2000/07/26 15:10:32  cgilmore
# decided to make movedir always the same yyyy/mm/dd
#
# Revision 1.7  2000/07/23 20:37:16  cgilmore
# added documentation
#
# Revision 1.6  2000/07/23 20:02:36  cgilmore
# added rewrite_log to list
#
# Revision 1.5  2000/07/22 18:36:32  cgilmore
# added $file to movefile name. duh.
#
# Revision 1.4  2000/07/21 23:09:22  cgilmore
# added delay for restart if service is still running and added hms
# to movefile
#
# Revision 1.3  2000/07/21 21:55:46  cgilmore
# added raven logs to the list
#
# Revision 1.2  2000/07/21 16:41:54  cgilmore
# changed references to the Time::Relative package
#
# Revision 1.1  2000/07/21 15:59:06  cgilmore
# Initial revision
#
###############################################################################
###############################################################################
