xcat-core/xCAT-rmc/scripts/monaixsyslog
2010-03-02 17:13:59 +00:00

510 lines
13 KiB
Perl
Executable File

#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#------------------------------------------------------------------------------
=head1 monaixsyslog
=head2
=cut
#------------------------------------------------------------------------------
use locale;
use Getopt::Long;
my $dirname = "xcat_aix_syslog";
my $vardir = "/var/opt/$dirname";
my $default_runfile = "$vardir/.monaixsyslog_run";
my $default_file = "$vardir/syslog.out";
my $default_pri = "*.warn";
$::MAX_SENSOR_STRING = 65535;
my ($facility_priority, $logfile, $runfile) = &getArgs();
my ($syslogconf, $embedinfo);
$syslogconf = "/etc/syslog.conf";
$embedinfo = "$facility_priority $logfile rotate size 4m files 1";
if (!-d $vardir) { mkdir($vardir); }
#check to see if this is the first time this script has been run
if (!-e $runfile)
{ #first time
if ($^O =~ /^aix/i)
{
runcmd("grep \"$embedinfo\" $syslogconf", -1);
if ($::RUNCMD_RC == 1)
{ #grep did not find embedinfo
#update syslog.conf
if (!-d $vardir) { mkdir($vardir); }
if (!-e $logfile)
{
touchFile($logfile);
}
runcmd("echo \"$embedinfo\" >> $syslogconf");
my $cmd = "refresh -s syslogd";
runcmd($cmd);
}
touchFile($runfile);
}
else
{
print "non-AIX platform, this scripts should not be ran.\n";
exit 1;
}
}
#Check for errors
if ($^O =~ /^aix/i)
{
unless (open(RUNFILE, "<$runfile"))
{
print "Cannot open file $runfile\n";
exit 1;
}
my $marker = <RUNFILE>;
close(RUNFILE);
my ($new_number, $new_content, $to_rfile);
# If the $runfile is empty, then we should read the $logfile from the beginning.
if (!$marker)
{
($new_number, $new_content, $to_rfile) = &refreshSensorFromLogfile($logfile, 0, undef);
}
else
{
my @info = split ':::', $marker;
my ($last_modified_time, $line_number, $mark_content) = @info;
my @stats = stat($logfile);
my $time = $stats[9];
if ($time == $last_modified_time)
{
# The log file has not been updated since last modified.
exit 0;
}
($new_number, $new_content, $to_rfile) = &refreshSensorFromLogfile($logfile, $line_number, $mark_content);
# If the $to_rfile is set, then we should refresh the info from rotated file to Sensor first.
if ($to_rfile)
{
# Read the rotated file first.
my $rotated_file = "$logfile" . ".0";
($new_number, $new_content, $to_rfile) = &refreshSensorFromLogfile($rotated_file, $line_number, $mark_content);
# Then read the log file just from the beginning to refresh the Sensor.
($new_number, $new_content, $to_rfile) = &refreshSensorFromLogfile($logfile, 0, undef);
}
}
# Get the last modified time for this log file
my @stats = stat($logfile);
my $new_time = $stats[9];
&updateRunfile($new_time, $new_number, $new_content, $runfile);
}
else
{
print "non-AIX platform, this scripts should not be ran.\n";
exit 1;
}
exit 0;
#-------------------------------------------------------------------------------
=head3 getArgs
parse the command line and check the values
paras:
-p : <facility>.<priority>, the default value is "*.warn"
-f : <fifo_name>, the default value is "/var/opt/xcat_aix_syslog/syslog_fifo"
=cut
#-------------------------------------------------------------------------------
sub getArgs()
{
my $routine = "getArgs";
print "ENTERING: $routine\n" if $::DEBUG;
my @command_line = ();
@command_line = @ARGV;
# Checks case in GetOptions
$Getopt::Long::ignorecase = 0;
my ($facility_priority, $file, $runfile);
if (
!GetOptions(
'p=s' => \$facility_priority,
'f=s' => \$file,
)
)
{
print "LEAVING: $routine\n" if $::DEBUG;
exit 1;
}
# Set runfile mark file
if ($facility_priority || $file)
{
my @para = split '/', $file;
my $newpara = join '-', @para;
$runfile = "$vardir/.monaixsyslog_run" . "-$facility_priority". "-$newpara";
}
else
{
$runfile = $default_runfile;
}
if (!$file)
{
$file = $default_file;
}
if (!$facility_priority)
{
$facility_priority = $default_pri;
}
return ($facility_priority, $file, $runfile);
}
#-------------------------------------------------------------------------------
=head3 refreshSensorFromLogfile
read the log file line by line to refresh the Sensor
Args:
$file - the log file
$bgnline - the beginning line number that we should read from
$bgncontent - the line content related to $line
Return:
$i - the line number that has been read and refreshed to Sensor.
$mark_content - the line content related to $i
$to_rfile - the flag that indicates whether we need to read from the
rotated file.
=cut
#-------------------------------------------------------------------------------
sub refreshSensorFromLogfile()
{
my ($file, $bgnline, $bgncontent) = @_;
unless (open(FILE, "<$file"))
{
# The file may be opened by syslogd.
exit 0;
}
my $i = 0;
my $matchflag = 0;
my $to_rfile = 0;
my $mark_content;
my $allinfo = "";
while (my $line = <FILE>)
{
if ($matchflag || $bgnline == 0)
{
# Start reading the file from this line and push it to the sensor
# and update the mark file
$allinfo .= $line;
$i = $i + 1;
$mark_content = $line;
}
else
{
if ($i != $bgnline - 1)
{
$i = $i + 1;
next;
}
if ($line eq $bgncontent)
{
$matchflag = 1;
$i = $i + 1;
next;
}
else
{
# The line number is the same, but the content is different
# that indicates the log file has been rotated.
$to_rfile = 1;
last;
}
}
}
if ($allinfo)
{
my $strlen = length($allinfo);
# The condition/response can not handle
# the long sensor String very well,
# use file to pass messages.
# file name: /var/opt/xcat_aix_syslog/tmplogmsg_$$
if ($strlen > $::MAX_SENSOR_STRING)
{
srand(time | $$);
my $filename = "$vardir/tmplogmsg_$$";
while (-e $filename)
{
$filename = createRandomName($filename);
}
if (open(TMPLOG, ">$filename"))
{
print TMPLOG $allinfo;
close TMPLOG;
print "XCAT_MONAIXSYSLOG_FILE:$filename";
}
else
{
#open failed, why?
print "OPEN_FILE_FAILED: $filename";
}
}
else
{
print $allinfo;
}
}
close(FILE);
return ($i, $mark_content, $to_rfile);
}
#-------------------------------------------------------------------------------
=head3 updateRunfile
use the new marker line to update the runfile
Args:
$time - last mofidied time
$line - line number
$content - line content
$file - the run file
Return:
$i - the line number that has been read and refreshed to Sensor.
$mark_content - the line content related to $i
=cut
#-------------------------------------------------------------------------------
sub updateRunfile()
{
my ($time, $line, $content, $file) = @_;
# the marker line is something like "last_modified_time:::line_number:::mark_content"
my $new_marker = join(":::", $time, $line, $content);
runcmd("echo \"$new_marker\" > $file");
}
#--------------------------------------------------------------------------------
=head3 runcmd
Run the given cmd and return the output in an array (already chopped). Alternatively,
if this function is used in a scalar context, the output is joined into a single string
with the newlines separating the lines.
Arguments:
command, exitcode and reference to output
Returns:
see below
Error:
Normally, if there is an error running the cmd, it will display the error msg
and exit with the cmds exit code, unless exitcode is given one of the
following values:
0: display error msg, DO NOT exit on error, but set
$::RUNCMD_RC to the exit code.
-1: DO NOT display error msg and DO NOT exit on error, but set
$::RUNCMD_RC to the exit code.
-2: DO the default behavior (display error msg and exit with cmds
exit code.
number > 0: Display error msg and exit with the given code
Example:
my $outref = runcmd($cmd, -2, 1);
Comments:
If refoutput is true, then the output will be returned as a reference to
an array for efficiency.
=cut
#--------------------------------------------------------------------------------
sub runcmd
{
my ($cmd, $exitcode, $refoutput) = @_;
$::RUNCMD_RC = 0;
if (!($cmd =~ /2>&1$/)) { $cmd .= ' 2>&1'; }
my $outref = [];
@$outref = `$cmd`;
if ($?)
{
$::RUNCMD_RC = $? >> 8;
my $displayerror = 1;
my $rc;
if (defined($exitcode) && length($exitcode) && $exitcode != -2)
{
if ($exitcode > 0)
{
$rc = $exitcode;
} # if not zero, exit with specified code
elsif ($exitcode <= 0)
{
$rc = ''; # if zero or negative, do not exit
if ($exitcode < 0) { $displayerror = 0; }
}
}
else
{
$rc = $::RUNCMD_RC;
} # if exitcode not specified, use cmd exit code
if ($displayerror)
{
my $errmsg = '';
if (($^O =~ /^linux/i) && $::RUNCMD_RC == 139)
{
$errmsg = "Segmentation fault $errmsg";
}
else
{
# The error msgs from the -api cmds are pretty messy. Clean them up a little.
filterRmcApiOutput($cmd, $outref);
$errmsg = join('', @$outref);
chomp $errmsg;
}
print "Exit code $::RUNCMD_RC from command: $cmd\nError message from cmd: $errmsg\n"
}
}
if ($refoutput)
{
chomp(@$outref);
return $outref;
}
elsif (wantarray)
{
chomp(@$outref);
return @$outref;
}
else
{
my $line = join('', @$outref);
chomp $line;
return $line;
}
}
#--------------------------------------------------------------------------------
=head3 filterRmcApiOutput
filter RMC Api Output
Arguments:
RMC command
Output reference
Returns:
none
Globals:
none
Error:
none
Example:
filterRmcApiOutput($cmd, $outref);
Comments:
The error msgs from the RPM -api cmds are pretty messy.
This routine cleans them up a little bit.
=cut
#--------------------------------------------------------------------------------
sub filterRmcApiOutput
{
my ($cmd, $outref) = @_;
if (!($cmd =~ m|^/usr/bin/\S+-api |)) {
return;
} # give as much info as possible, if verbose
# Figure out the output delimiter
my ($d) = $cmd =~ / -D\s+(\S+)/;
if (length($d)) {
$d =~ s/^(\'|\")(.*)(\"|\')$/$2/; # remove any surrounding quotes
# escape any chars perl pattern matching would intepret as special chars
$d =~ s/([\|\^\*\+\?\.])/\\$1/g;
}
else
{
$d = '::';
} # this is the default output delimiter for the -api cmds
$$outref[0] =~ s/^ERROR${d}.*${d}.*${d}.*${d}.*${d}//;
}
#--------------------------------------------------------------------------------
=head3 touchFile
Arguments: $filename, $donotExit
Returns: non zero return code indicates error
Example: touchFile("/var/opt/xcat/touch");
=cut
#--------------------------------------------------------------------------------
sub touchFile
{
my ($filename, $donotExit) = @_;
my $fh;
my $rc = 0;
if (!-e $filename) {
#if the file doesn't exist we need to open and close it
open($fh, ">>$filename") or $rc++;
if ($rc > 0 && !$donotExit) {
print "Touch of file $filename failed with: $!\n";
return $rc;
}
close($fh) or $rc++;
}
else {
#if the file does exist we can just utime it (see the perlfunc man page entry on utime)
my $now = time;
utime($now, $now, $filename);
}
if ($rc > 0 && !$donotExit) {
print "Touch of file $filename failed with: $!\n";
return $rc;
}
return 0;
}
#--------------------------------------------------------------------------------
=head3 createRandomName
Create a randome file name.
Arguments:
Prefix of name
Returns:
Prefix with 8 random letters appended
Error:
none
Example:
$file = createRandomName($namePrefix);
Comments:
None
=cut
#--------------------------------------------------------------------------------
sub createRandomName
{
my $name=shift;
my $nI;
for ($nI = 0 ; $nI < 8 ; $nI++)
{
my $char = ('a' .. 'z', 'A' .. 'Z')[int(rand(52)) + 1];
$name .= $char;
}
$name;
}