#!/usr/bin/perl # rpm helper scriptlet to add a syslog entry (sysklogd and syslog-ng) # $Id$ use Getopt::Std; use strict; my %opts = ( s => '/dev/log', f => undef, m => 'debug', M => 'emerg' ); getopts('s:f:m:M:', \%opts); my ($source, $facility, $min, $max) = @opts{qw/s f m M/}; die < Available options: -s source (default: /dev/log) -f facility (default: first local available) -m min priority (default: debug) -M max priority (default: emerg) EOF my ($package, $number, $dest) = @ARGV; # don't do anything for upgrade exit(0) if $number == 2; # check arguments my @facilities = qw/auth authpriv cron daemon \ kern lpr mail mark news syslog \ user uucp local0 local1 local2 \ local3 local4 local5 local6 local7/; my %facilities = map { $_ => 1 } @facilities; die "invalid facility '$facility'" if $facility && !$facilities{$facility}; my $i; my @priorities = qw/debug info notice warning err crit alert emerg/; my %priorities = map { $_ => $i++ } @priorities; die "invalid min priority '$min'" if $min && ! defined $priorities{$min}; die "invalid max priority '$max'" if $max && ! defined $priorities{$max}; die "maximum priority '$max' lower than minimum priority '$min'" if $min && $max && ($priorities{$max} < $priorities{$min}); if (!$facility) { my @local_facilities; # parse all configuration files, and count occurences of local facilities if (-f '/etc/syslog.conf') { open(my $in, '<', '/etc/syslog.conf') or die "Can't open /etc/syslog.conf for reading: $!"; while (my $line = <$in>) { $local_facilities[$1]++ if $line =~ /^local(\d)/; } close($in); } if (-f '/etc/syslog-ng.conf') { open(my $in, '<', '/etc/syslog-ng.conf') or die "Can't open /etc/syslog-ng.conf for reading: $!"; while (my $line = <$in>) { $local_facilities[$1]++ if $line =~ /facility\(local(\d)\)/; } close($in); } # use first facility without occurences for my $i (1 .. 7) { next unless $local_facilities[$i] == 0; $facility = "local$i"; last; } die "no available free facility" unless $facility; } add_sysklogd_entry($package, $source, $dest, $facility, $min, $max) if -f '/etc/syslog.conf'; add_syslogng_entry($package, $source, $dest, $facility, $min, $max) if -f '/etc/syslog-ng.conf'; # output used facility as feedback print $facility; sub add_sysklogd_entry { my ($package, $source, $dest, $facility, $min, $max) = @_; # ensure source is configured if ($source ne '/dev/log') { my ($content, $changed); open(my $in, '<', '/etc/sysconfig/syslog') or die "Can't open /etc/sysconfig/syslog for reading: $!"; while (my $line = <$in>) { if ($line =~ /^SYSLOGD_OPTIONS=(["'])?(.*)\1/) { my $quote = $1; my $options = $2; if ($options !~ /-a\s+$source/) { $options .= " -a $source"; $changed = 1; } $content .= "SYSLOGD_OPTIONS=" . $quote . $options. $quote . "\n"; } else { $content .= $line; } } close($in); if ($changed) { open(my $out, '>', '/etc/sysconfig/syslog') or die "Can't open /etc/sysconfig/syslog for writing: $!"; print $out $content; close($out); } } # compute selector my $selector; if ($max eq 'emerg') { if ($min eq 'debug') { $selector = "$facility.*"; } else { $selector = "$facility.$min"; } } else { for my $i ($priorities{$min} .. $priorities{$max}) { $selector .= ';' if $selector; $selector .= "$facility.=$priorities[$i]"; } } # compute spacing to keep default configuration file formatting my $tabs = length($selector) < 48 ? ((48 - length($selector)) / 8) : 1; # append entry open(my $out, '>>', '/etc/syslog.conf') or die "Can't open /etc/syslog.conf for appending: $!"; print $out "# BEGIN: Automatically added by $package installation\n"; print $out $selector . ("\t" x $tabs) . '-' . $dest . "\n"; print $out "# END\n"; close($out); # relaunch syslog system('service syslog condrestart 2>&1 >/dev/null'); } sub add_syslogng_entry { my ($package, $source, $dest, $facility, $min, $max) = @_; # read it first to check its content my ($source_id, $destination_id, $facility_id, $level_id); my $level = $min eq $max ? $max : "$min..$max"; open(my $fh, '<', '/etc/syslog-ng.conf') or die "Can't open /etc/syslog-ng.conf for reading: $!"; while (my $line = <$fh>) { if ($line =~ /^source \s+ (\S+) \s+ {/x) { # source block my $id = $1; SOURCE: while (1) { if ($line =~ /(?:unix-stream|file) \s* \( (["']) ([^\1]+) \1/x) { my $value = $2; $source_id = $id if $source eq $value; } last SOURCE if $line =~ /};/; $line = <$fh>; last SOURCE if !$line; } } elsif ($line =~ /^destination \s+ (\S+) \s+ {/x) { # destination block my $id = $1; DESTINATION: while (1) { if ($line =~ /file \s* \( (["']) ([^\1]+) \1/x) { my $value = $2; $destination_id = $id if $dest eq $value; } last DESTINATION if $line =~ /};/; $line = <$fh>; last DESTINATION if !$line; } } elsif ($line =~ /^filter \s+ (\S+) \s+ {/x) { # filter block my $id = $1; FILTER: while (1) { if ($line =~ /facility \s* \( ([^)]+) \)/x) { my $value = $1; $facility_id = $id if $facility eq $value; } if ($line =~ /level \s* \( ([^)]+) \)/x) { my $value = $1; $level_id = $id if $level eq $value; } last FILTER if $line =~ /};/; $line = <$fh>; last FILTER if !$line; } } } close($fh); # then append what is needed open(my $out, '>>', '/etc/syslog-ng.conf') or die "Can't open /etc/syslog-ng.conf for appending: $!"; print $out "# BEGIN: Automatically added by $package installation\n"; if (!$source_id) { $source_id = 's_' . $package; print $out "source $source_id { unix-stream('$source'); };\n"; } if (!$destination_id) { $destination_id = 'd_' . $package; print $out "destination $destination_id { file('$dest'); };\n"; } if (!$facility_id) { $facility_id = 'f_facility_' . $package; print $out "filter $facility_id { facility($facility); };\n"; } if (!$level_id) { $level_id = 'f_level_' . $package; print $out "filter $level_id { level($level); };\n"; } print $out "log { source($source_id);" . " filter($facility_id);" . " filter($level_id);" . " destination($destination_id); };\n"; print $out "# END\n"; close($out); # relaunch syslog-ng system('service syslog-ng condrestart 2>&1 >/dev/null'); }