### ### Copyright 2000-2007 University of Illinois Board of Trustees ### All rights reserved. ### ### PSGConf::Control::logadm - psgconf control class for controlling log rotation/pruning for Solaris ### ### Campus Information Technologies and Educational Services ### University of Illinois at Urbana-Champaign ### package PSGConf::Control::logadm; use PSGConf::Action::GenerateFile::Literal; use PSGConf::Data::Boolean; use PSGConf::Data::Hash; use PSGConf::Data::Integer; use PSGConf::Data::List; use PSGConf::Data::String; ############################################################################### ### policies ############################################################################### sub _policy_merge_timestamps { my ($self, $psgconf) = @_; my ($line, $line2, $obj, $log, @data); local *FP; return if ($psgconf->data_obj('logadm_enable')->equals('false')); if (!open (FP, $psgconf->data_obj('logadm_conf_file')->get())) { warn "\n\t!!! can't open existing logadm conf file (%s)\n", $psgconf->data_obj('logadm_conf_file')->get() if ( $psgconf->{verbose} ); return; } @data = ; close FP; foreach $line ( @data ) { ### Skip this line if we do not have any timestamp info... next if ( $line !~ / -P / ); chomp $line; ### Find the log file we are working with $log = $line; $log =~ s/ .*$//; ### Now get the time stamp itself (w/o the single quotes). $line =~ s/^.* -P '//; $line =~ s/' .*$//; ### Validate that we have a good timestamp. next if ( $line != m/ ^ (\S\S\S) # Day of the week \s+ (\S\S\S) # Month \s+ (\d?\d) # Day \s+ (\d\d:\d\d:\d\d) # Time (HH:MM:SS) \s+ (\d\d\d\d) # Year $ /); ### Now put the timestamp back into our directives. ### See if we already have a line in logadm_files $line2 = $psgconf->data_obj('logadm_files')->find("^$log"); if ( defined $line2 ) { ### If we already have a timestamp in the config, just go on. next if ( $line2 =~ / -P / ); ### Search through the arguments to find out where ### to put this timestamp. my (@a) = split(/\s/, $line2); for (my $i=1; $i < scalar @a; $i++) { if ( $a[$i] =~ /^-[ACE]$/ ) { $i++; ### Loop through the -M 'some cmd' arguments } elsif ( $a[$i] eq '-M' ) { do { $i++ } while ( $a[$i] !~ /\'$/ ); } elsif ( $a[$i] ne '-N' ) { $obj = $line2; $obj =~ s/ $a[$i]/ -P '$line' $a[$i]/; $psgconf->data_obj('logadm_files')->replace( "^$line2", $obj ); ### Now exit out of this inner for loop... $i = scalar @a; } } ### Since we do not have an entry in logadm_files, ### store the value for use later. } else { $psgconf->data_obj('logadm_timestamps')->insert( { $log => $line } ); } } } sub _add_files { my ($psgconf, $cmd, @files) = @_; my ($file, $fullcmd); foreach $file ( @files ) { ### The logadm command will rewrite the logadm_conf_file ### with the arguments sorted in alphabetical order, so make ### sure we do that the first time. $fullcmd = ' -C ' . $psgconf->data_obj('logadm_file_cnt')->get(); $fullcmd .= ' -N ' if ( ! -f $file ); $fullcmd .= " -P '" . $psgconf->data_obj('logadm_timestamps')->find($file) . "'" if ( $psgconf->data_obj('logadm_timestamps')->exists($file) ); $fullcmd .= " -a '" . $cmd . "'" if ( defined $cmd ); $fullcmd .= ' -p 1d -z 0'; $psgconf->data_obj('logadm_files')->add ( $file . $fullcmd ); } } sub _policy_add_syslog_files { my ($self, $psgconf) = @_; my (@logs); return if ($psgconf->data_obj('syslog_enable')->equals('false') || $psgconf->data_obj('logadm_enable')->equals('false')); map { push @logs, $_ if ( -f $_ ); } keys %{$psgconf->data_obj('syslog')->get()}; &_add_files ($psgconf, "kill -HUP `cat " . $psgconf->data_obj('pidfile_dir')->get() . "/syslog.pid`", @logs ); } sub _policy_add_ftp_files { my ($self, $psgconf) = @_; return if ($psgconf->data_obj('anon_ftp_enable')->equals('false') || $psgconf->data_obj('logadm_enable')->equals('false')); &_add_files ($psgconf, undef, ( $psgconf->data_obj('log_dir')->get() . '/xferlog' )); } sub _policy_add_www_files { my ($self, $psgconf) = @_; my (@logs); return if ($psgconf->data_obj('www_enable')->equals('false') || $psgconf->data_obj('logadm_enable')->equals('false')); @logs = ( $psgconf->data_obj('www_log_dir')->get() . '/suexec', $psgconf->data_obj('www_log_dir')->get() . '/error_log', $psgconf->data_obj('www_log_dir')->get() . '/access_log' ); map { push @logs, $_; } values %{$psgconf->data_obj('www_vh_access_log')->get()}; push @logs, $psgconf->data_obj('www_log_dir')->get() . '/ssl_engine_log' if ( $psgconf->data_obj('www_vh_ssl')->count() ); push @logs, $psgconf->data_obj('www_jk_logfile')->get() if ( $psgconf->data_obj('www_jk_enable')->equals('true') ); ### ### FIXME: Need to add the bluestem and any other logs not in ### the stock psgconf modules. This really screams to be put ### into a method that other Control modules can call from w/i ### one of their policies. ### &_add_files ( $psgconf, $psgconf->data_obj('www_apachectl_path')->get() . " graceful > /dev/null 2>&1", @logs); } ############################################################################### ### ### new() constructor ### ############################################################################### sub new { my ($class, $psgconf) = @_; my ($self); $self = {}; bless($self, $class); $self->{name} = 'logadm'; $self->{enable} = $self->{name} . '_enable'; $self->{packages} = $self->{name} . '_packages'; $psgconf->register_data( 'logadm_enable' => PSGConf::Data::Boolean->new( 'value' => 'false' ), 'logadm_conf_file' => PSGConf::Data::String->new( 'value_abspath' => 1, 'value' => '/etc/logadm.conf' ), 'logadm_file_cnt' => PSGConf::Data::Integer->new( 'value' => 14 ), 'logadm_timestamps' => PSGConf::Data::Hash->new(), 'logadm_files' => PSGConf::Data::List->new( 'unique' => 1 ) ); ### ### Rotate the syslog/ftp/apache logs. Do not need to do the ### TSM logs as dsmc does it for us (by setting the retention ### in the config files). ### $psgconf->register_policy($self, logadm_merge_timestamps => '_policy_merge_timestamps', logadm_add_syslog_files => '_policy_add_syslog_files', logadm_add_ftp_files => '_policy_add_ftp_files', logadm_add_www_files => '_policy_add_www_files' ); return $self; } ############################################################################### ### ### decide() method ### ### generate logadm_conf_file based on files specified in psg.conf ### ############################################################################### sub decide { my ($self, $psgconf) = @_; my ($conffile); return if ($psgconf->data_obj('logadm_enable')->equals('false')); ### create logadm_conf_file $psgconf->register_actions( PSGConf::Action::GenerateFile::Literal->new( name => $psgconf->data_obj('logadm_conf_file')->get(), content => join("\n", @{$psgconf->data_obj('logadm_files')->get()}) . "\n", backup => 0 ) ) } 1; __END__ =head1 NAME PSGConf::Control::logadm - psgconf control class for controlling log rotation/pruning for Solaris =head1 SYNOPSIS In F: Control PSGConf::Control::logadm =head1 DESCRIPTION The B module provides a B control object for rotating system logs using the logadm facility. It supports the following methods: =over 4 =item new() The constructor. Its parameter is a reference to the B object. It registers the following data objects: =over 4 =item I A B object to enable/disable this feature =item I A B object defining the location of the C config file. Defaults to F. =item I A B object for the number of files we need to keep. The default is 14. =item I A B object of the commands to use to configure C. =back The constructor also registers the following policy methods: =over 4 =item I Requests that the C files be rotated. =item I Requests that the C log files be rotated. =item I Requests that the C log files be rotated. =back =item decide() Registers a B Action object to generate the F file. =back =head1 SEE ALSO Clogadm(8)E> L L L L L L L L L =cut