### ### Copyright 2000-2007 University of Illinois Board of Trustees ### All rights reserved. ### ### syslog.pm - syslog module for psgconf ### ### Campus Information Technologies and Educational Services ### University of Illinois at Urbana-Champaign ### package PSGConf::Control::syslog; use strict; use PSGConf::Action::GenerateFile::EnvFile; use PSGConf::Action::GenerateFile::Literal; use PSGConf::Action::GenerateFile::syslog_conf; use PSGConf::Action::MkDir; use PSGConf::Action::CreateFile; use PSGConf::Action::ModifyFile; use PSGConf::Action::RestartDaemon; use PSGConf::Data::Boolean; use PSGConf::Data::Hash; use PSGConf::Data::List; use PSGConf::Data::String; use PSGConf::Control::Packages qw(_add_pkgs); ############################################################################### ### policy methods ############################################################################### require Exporter; our @ISA = qw (Exporter); our %EXPORT_TAGS = ( 'all' => [ qw( _add_syslog) ] ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} }); our @EXPORT = qw(); ### To be called from other Control modules sub _add_syslog { my ($self, $psgconf) = @_; if (!exists($self->{enable}) || $self->{enable} eq '' ) { warn "\t!!!Control::syslog->_add_syslog(): no enable attribute(s)\n"; return; } return if ($psgconf->data_obj($self->{enable})->equals('false')); ### Now check to make sure we are adding defined values in. if ( !exists($self->{syslog}) || $self->{syslog} eq ''|| !exists($self->{facility}) || $self->{facility} eq '') { warn "\t!!!Control::syslog->_add_syslog(): no syslog/facility attribute(s)\n"; return; } $psgconf->data_obj('syslog')->insert( { $self->{syslog} => $self->{facility} } ) if (!defined $psgconf->data_obj('syslog')->find($self->{syslog})); } ### set default location for syslog_dir sub _policy_default_dir { my ($self, $psgconf) = @_; return if ($psgconf->data_obj('syslog_enable')->equals('false')); $psgconf->data_obj('syslog_dir')->prepend( $psgconf->data_obj('log_dir')->get() . '/' ) if ( ! $psgconf->data_obj('syslog_dir')->match('^/')); } ### set absolute path to log files sub _policy_canonify_logfiles { my ($self, $psgconf) = @_; my ($log, $new_log); return if ($psgconf->data_obj('syslog_enable')->equals('false')); foreach $log (keys %{$psgconf->data_obj('syslog')->get()}) { if (substr($log, 0, 1) ne '/' && substr($log, 0, 1) ne '@') { $new_log = $psgconf->data_obj('syslog_dir')->get() . "/$log"; $psgconf->data_obj('syslog')->insert( { $new_log => $psgconf->data_obj('syslog')->find($log) } ); $psgconf->data_obj('syslog')->delete($log); } } } ### handle platforms with "authpriv" facility sub _policy_add_authpriv_facility { my ($self, $psgconf) = @_; my ($target, $value); return if ($psgconf->data_obj('syslog_enable')->equals('false') || $psgconf->data_obj('platform')->match('solaris')); foreach $target (sort keys %{$psgconf->data_obj('syslog')->get()}) { $value = $psgconf->data_obj('syslog')->find($target); $value =~ s/\bauth\b/$&,authpriv/; $psgconf->data_obj('syslog')->insert( { $target => $value } ); } foreach $target (sort keys %{$psgconf->data_obj('syslog_literal')->get()}) { $value = $psgconf->data_obj('syslog_literal')->find($target); $value =~ s/\bauth\b/$&,authpriv/; $psgconf->data_obj('syslog_literal')->insert( { $target => $value } ); } } ### expand USED_FACILITIES token sub _policy_expand_used_facilities { my ($self, $psgconf) = @_; my ($log, $levels, $facilities, %used_facilities, $default); return if ($psgconf->data_obj('syslog_enable')->equals('false')); foreach $log (keys %{$psgconf->data_obj('syslog')->get()}) { if ($psgconf->data_obj('syslog')->find($log) =~ m/USED_FACILITIES/) { $default = $log; next; } foreach $levels (split(';', $psgconf->data_obj('syslog')->find($log))) { $levels =~ s/\.\w+//; map { $used_facilities{$_}++; } split(',', $levels); } } if (defined($default)) { $facilities = join(',', sort keys %used_facilities); $log = $psgconf->data_obj('syslog')->find($default); $log =~ s/USED_FACILITIES/$facilities/; $psgconf->data_obj('syslog')->insert( { $default => $log } ); } } sub _policy_add_remote_servers { my ($self, $psgconf) = @_; map { $psgconf->data_obj('syslog')->insert( { '@' . $_ => '*.info' } ); } @{$psgconf->data_obj('syslog_servers')->get()}; } sub _policy_enable_rc_scripts { my ($self, $psgconf) = @_; my ($args); if ( $psgconf->data_obj('syslog_enable')->equals('true') ) { $psgconf->data_obj('rc_scripts')->insert( { 'syslogd' => { 'state' => 'enable' }} ); if ( $psgconf->data_obj('platform')->match('freebsd') ) { $args = $psgconf->data_obj('syslog_remote_enable')->equals('true') ? '' : ($psgconf->data_obj('syslog_servers')->count() ### Turn off accepting packets remotely ? '-s ' ### Turn off sending packets remotely, since ### we do not have any syslog_servers defined. : '-ss '); $psgconf->data_obj('rc_vars')->insert( { 'syslogd_flags' => $args . '-vv' } ); } } } ############################################################################### ### ModfileFile plugin to edit /etc/rc.tcpip ############################################################################### sub _modify_rc_tcpip { my ($action, $infh, $fh, $psgconf) = @_; my ($line); while ($line = <$infh>) { $line = 'start /usr/sbin/syslogd "$src_running"' . ($psgconf->data_obj('syslog_remote_enable')->equals('true') ? '': ' -r') . "\n" if ($line =~ m|^start /usr/sbin/syslogd "\$src_running"( -r)?$| ); print $fh $line; } return 1; } ############################################################################### ### decide() method ############################################################################### sub decide { my ($self, $psgconf) = @_; my ($file); return if ($psgconf->data_obj('syslog_enable')->equals('false')); $psgconf->register_actions( PSGConf::Action::GenerateFile::syslog_conf->new( 'name' => $psgconf->data_obj('syslog_file')->get(), 'description' => 'syslogd configuration file', 'syslog' => { %{$psgconf->data_obj('syslog')->get()}, %{$psgconf->data_obj('syslog_literal')->get()} } ), PSGConf::Action::MkDir->new( 'name' => $psgconf->data_obj('syslog_dir')->get() ) ); foreach $file ( keys %{$psgconf->data_obj('syslog')->get()}) { if (substr($file, 0, 1) eq '/') { $psgconf->register_actions( PSGConf::Action::CreateFile->new( 'name' => $file ) ); } } ### Turn off accepting packets remotely $psgconf->register_actions( PSGConf::Action::GenerateFile::Literal->new( 'name' => '/etc/default/syslogd', 'content' => 'LOG_FROM_REMOTE=' . ($psgconf->data_obj('syslog_remote_enable')->equals('true') ? 'YES' : 'NO') . "\n" ) ) if ( $psgconf->data_obj('platform')->match('solaris')); $psgconf->register_actions( PSGConf::Action::GenerateFile::EnvFile->new( 'name' => '/etc/sysconfig/syslog', 'quote_values' => 1, 'vars' => { 'SYSLOGD_OPTIONS' => '-m 0' . ($psgconf->data_obj('syslog_remote_enable')->equals('true')? ' -r': ''), 'KLOGD_OPTIONS' => '-x' } ) ) if ($psgconf->data_obj('platform')->match('(-rhel-)|(-rhl-)|(-fc-)')); ### Turn off accepting packets remotely $psgconf->register_actions( PSGConf::Action::ModifyFile->new( 'name' => '/etc/rc.tcpip', 'modify_func' => \&_modify_rc_tcpip, 'uid' => 0, 'gid' => 0, 'mode' => 0774 ) ) if ( $psgconf->data_obj('platform')->match('aix')); ### Make sure we restart syslogd after we create all the files $psgconf->register_actions( PSGConf::Action::RestartDaemon->new( name => 'syslogd', filename => [ $psgconf->data_obj('syslog_dir')->get(), $psgconf->data_obj('syslog_file')->get() ], pidfile => $psgconf->data_obj('pidfile_dir')->get() . '/syslog.pid' ) ); } ############################################################################### ### Constructor ############################################################################### sub new { my ($class, $psgconf) = @_; my ($self); $self = {}; bless($self, $class); ### So that _add_pkgs knows which directives to look at $self->{name} = 'syslog'; $self->{enable} = $self->{name} . '_enable'; $self->{packages} = $self->{name} . '_packages'; $psgconf->register_data( 'syslog_enable' => PSGConf::Data::Boolean->new( value => 'true' ), 'syslog_remote_enable' => PSGConf::Data::Boolean->new( value => 'false' ), 'syslog' => PSGConf::Data::Hash->new(), 'syslog_file' => PSGConf::Data::String->new( 'value_abspath' => 1, 'value' => '/etc/syslog.conf' ), 'syslog_dir' => PSGConf::Data::String->new( 'value' => 'syslog' ), 'syslog_literal' => PSGConf::Data::Hash->new(), 'syslog_packages' => PSGConf::Data::List->new(), 'syslog_servers' => PSGConf::Data::List->new() ); $psgconf->register_policy($self, syslog_default_dir => '_policy_default_dir', syslog_canonify_logfiles => '_policy_canonify_logfiles', syslog_add_authpriv_facility => '_policy_add_authpriv_facility', syslog_expand_used_facilities => '_policy_expand_used_facilities', syslog_enable_rc_scripts => '_policy_enable_rc_scripts', syslog_add_packages => '_add_pkgs', syslog_add_remote_servers => '_policy_add_remote_servers' ); return $self; } ############################################################################### ### documentation ############################################################################### 1; __END__ =head1 NAME PSGConf::Control::syslog - psgconf control class for syslog =head1 SYNOPSIS In F: Control PSGConf::Control::syslog =head1 DESCRIPTION The B module provides a B control object for configuring C. 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 that indicates whether C should be configured. The default is true. =item I A B object that indicates whether C should accept remote packats. The default is false. =item I A B object that lists all packages to install. =item I A B object that contains log file entries for F. The hash key is the name of the file to create, and the value is the facility and priority specification. =item I A B object that contains the path for the syslog config file. The default is F. =item I A B object that contains the path to the directory where log files will be stored. If not an absolute path, it is relative to the value of the I object, which is supplied by the B module. =item I A B object that lists all remote syslog servers to send data to. =item I A B object that contains non-file entries for I. The hash key is the target (e.g., a login name or a C<*>), and the value is the facility and priority specification. =back The constructor also registers the following policy methods: =over 4 =item I If I is not set to an absolute path, prepend the value of the I object, which is provided by the B module. =item I For each entry in the I object that is not an absolute path, prepend the value of the I object. =item I On platforms other than Solaris, add the C facility to any entry in I or I that already specifies the C facility. =item I Expands the token C in the I data object with the list of facilities used by other entries in I. =item I Modifies the I data object (provided by B) to enable C. Also modifies the I data object (provided by B) to set the C startup flags to be C<-s -vv> or C<-ss -vv> if there are or are not I defined, respectively. =back =item decide() If the I data object is set, instantiates and registers action objects, as follows: =over 4 =item * Registers a new B object to create I. =item * Registers a new B object to create I on C systems. =item * Registers a new B object to create the I directory. =item * Registers new B objects for each file in the I object. =item * Registers new B object for the F file on AIX systems to add the C<-r> flag to the startup of C. =back =back =head1 SEE ALSO syslog.conf(4) L L L L L L L L L L L L L L L L L =cut