#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2004,2008 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# @(#)33   1.12   src/csm/core/cmds/monerrorlog.perl, csmcore, csm_rgar2h, rgar2hs001a 11/29/07 03:04:57

#When first run (by the sensor) this script adds an entry to the AIX ODM
#or Linux syslog.conf file so that it will be notified when an error is
#logged (through a message queue on AIX and a named pipe on Linux). Then
#it checks for any logged errors. On all subsequent runs this script just
#checks for errors.

use strict;
use locale;

BEGIN
{

	# this enables us to redirect where it looks for other CSM files during development
	$::csmroot = $ENV{'CSM_ROOT'} ? $ENV{'CSM_ROOT'} : '/opt/csm';
	$::csmpm   = "$::csmroot/pm";
	$::csmbin  = "$::csmroot/bin";
}
use lib $::csmpm;
use Getopt::Long;
use NodeUtils;
use ServerUtils;
require NetworkUtils;
use IPC::SysV qw(IPC_STAT S_IRWXU IPC_PRIVATE IPC_CREAT S_IRUSR S_IWUSR );
use IPC::Msg;

$::MSGCAT     = 'nodecmds.cat';
$::MSGMAPPATH = "$::csmroot/msgmaps";
if (defined $ENV{'CSM_VERBOSE'}) { $::VERBOSE = 1; }

#Variable definitions
%::msOSDefs = ServerUtils->get_OSDefs();    #load global definitions
my $distroname = NodeUtils->get_DistributionName();
my $distroversion = NodeUtils->get_DistributionVersion();

my $dirname = "csm_err_mon";
my $vardir = "/var/opt/$dirname";    #don't want it in /var/optcsm because it shouldn't be failed over

my $default_runfile = "$vardir/.monerrorlog_run";
my $default_fifo = "$vardir/syslog_fifo";
my $default_pri = "*.warn";
$::MAX_SENSOR_STRING = 10240;

my ($facility_priority, $fifo, $runfile) = &getArgs();

my ($syslogconf, $embedinfo);
if (($distroname eq "SLES") && ($distroversion eq "10")) 
{
	$syslogconf = "/etc/syslog-ng/syslog-ng.conf";
    if (($facility_priority eq $default_pri) && ($fifo eq $default_fifo))
    {
    	$embedinfo = "destination warn_fifo { pipe(\\\"$fifo\\\" group(root) perm(0644)); };\nlog { source(src); filter(f_warn); destination(warn_fifo); };";
    }
    else
    {
        my $tmp_dest = ServerUtils->CreateRandomName("fifo");
    	$embedinfo = "destination $tmp_dest { pipe(\\\"$fifo\\\" group(root) perm(0644)); };\nlog { source(src); filter($facility_priority); destination($tmp_dest); };";
    }
}
else
{
	$syslogconf = "/etc/syslog.conf";
    $embedinfo = "$facility_priority   |$fifo";
}
my $odmstanza  = "$vardir/odmstanza";

if (!-d $vardir) { mkdir($vardir); }

#--------------------------------------------------------------------------------

=head3   first_time_run 

        Notes: check whether this is the first time that monerrlog is run
	       on Linux, check the marker file /var/opt/csm_err_mon/.monerrorlog_run
	       on AIX, check the errnotify odm entry itself

Arguments:
	N/A

Returns:
       0 - This is NOT the first time that monerrlog is run
       1 - This is the first time that monerrlog is run 
=cut

#--------------------------------------------------------------------------------
sub first_time_run()
{
	if(NodeUtils->isAIX())
	{
		my $output  = NodeUtils->runcmd("/bin/odmget -q \"en_name=csm_errlog_sens\" errnotify", -1);
		if (!$output)
		{
			return 1;
		}
		return 0;
	}
	else
	{
		if (!-e $runfile)
		{
			return 1;
		}
		return 0;
	}

}

#check to see if this is the first time this script has been run
if (&first_time_run)
{      #first time
	if (NodeUtils->isLinux())
	{
		NodeUtils->runcmd("$::GREP \"$embedinfo\" $syslogconf", -1);
		if ($::RUNCMD_RC == 1)
		{    #grep did not find dirname
			    #update syslog.conf
			if (!-d $vardir) { mkdir($vardir); }
                        if (!-e $fifo)
                        {
  			    NodeUtils->runcmd("/usr/bin/mkfifo $fifo");
                        }
			NodeUtils->runcmd("echo \"$embedinfo\" >> $syslogconf");
			my $cmd = NetworkUtils->service("syslog", "restart");
			NodeUtils->runcmd($cmd);
		}
		NodeUtils->touchFile($runfile);
	}
	elsif (NodeUtils->isAIX())
	{
		open(ODM, ">$odmstanza") or die $!;
		print ODM '
errnotify:
      en_pid = 0
      en_name = "csm_errlog_sensor"
      en_persistenceflg = 1
      en_method = "/opt/csm/csmbin/errmsgque sequence = $1 error_id = $2 class = $3 type = $4 alert_flags = $5 res_name = $6 res_type = $7 res_class = $8 label = $9"
';
		close ODM or die $!;
		NodeUtils->runcmd("/usr/bin/odmadd $odmstanza");
	}
	else
	{
		print "unknown platform\n";
		exit 1;
	}
}

#Check for errors

if (NodeUtils->isLinux())
{
	local $SIG{ALRM} = sub { die "alarm\n" };
	eval {
		alarm 4;
		open(PIPE, $fifo) or die 
        MessageUtils->messageFromCat('csmInstall.cat', $::MSGMAPPATH, 
                                     'csminstall',     'E1', 
                                     'EMsgCANT_OPEN', $fifo
                                     ); 
		alarm 0;
	};
	if ($@ =~ /alarm/) { close PIPE; exit 0; }

	my $allinfo = "";
	while (1)
	{
		my $line;
		eval {
			alarm 2;
			$line = <PIPE>;
			alarm 0;
		};
		if ($@ =~ /alarm/) { 
				close PIPE; 
                # send the messages to sensor
				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/csm_err_mon/tmplogmsg  
					if ($strlen > $::MAX_SENSOR_STRING)
					{
						srand(time | $$); 
						my $filename = "$vardir/tmplogmsg_$$";
						while (-e $filename)
						{
							$filename = ServerUtils->CreateRandomName($filename);
						}
						if (open(TMPLOG, ">$filename"))
						{
							print TMPLOG $allinfo;
							close TMPLOG;
							print "CSM_MONERRORLOG_FILE:$filename";
						}
						else
						{
							#open failed, why?
							print "OPEN_FILE_FAILED: $filename";
						}
					}
					else
					{
						print $allinfo;
					}
				}

				exit 0; 
		}
		$allinfo .= $line;
	}
	close PIPE;
}
elsif (NodeUtils->isAIX())
{
	# the monitoring is stopped
	if ($ENV{'SENSOR_MonitorStatus'} eq '2')
	{
		# stopsrc -s IBM.SensorRM will also 
		# set $ENV{'SENSOR_MonitorStatus'} to 2
		# should not do clean up when IBM.SensorRM is stopped
		if (NodeUtils->isRMrunning("IBM.SensorRM"))
		{
			NodeUtils->runcmd("/bin/odmdelete -o errnotify -q \" en_name=csm_errlog_sens\"", -1);
			if (-e $runfile)
			{
				unlink($runfile);
			}
		}
		exit 0;
	}

	my $m = ord('csm');
	my $key = IPC::SysV::ftok("/var/adm/ras/errlog", $m);
	my $buf;
	my $msg = new IPC::Msg($key, IPC_CREAT | S_IRUSR | S_IWUSR);
	local $SIG{ALRM} = sub { die "alarm\n" };
	while (1)
	{
		eval {
			alarm 2;
			my $rectype = $msg->rcv($buf, 256);
			alarm 0;
		};
		if ($@ =~ /alarm/) { close PIPE; exit 0; }
		NodeUtils->runcmd(
			"echo \"/usr/bin/refsensor ErrorLogSensor String=\'$buf\' 1>/dev/null 2>/dev/null\" | at now",
			0
		);
	}

	exit 0;
}

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/csm_err_mon/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, $fifo, $runfile);

    if (
        !GetOptions(
                    'p=s'      => \$facility_priority,
                    'f=s'      => \$fifo,
        )
      )
    {
        print "LEAVING: $routine\n" if $::DEBUG;
        exit 1;
    }

    # Set runfile mark file
    if ($facility_priority || $fifo)
    {
        my @para = split '/', $fifo;
        my $newpara = join '-', @para;
        $runfile = "$vardir/.monerrorlog_run" . "-$facility_priority". "-$newpara";
    }
    else
    {
        $runfile = $default_runfile;
    }

    if (!$fifo)
    {
        $fifo = $default_fifo; 
    }

    if (!$facility_priority)
    {
        $facility_priority = $default_pri;
    }
    
    return ($facility_priority, $fifo, $runfile);
}


