#!/usr/local/bin/perl
#####################################################################
# TITRE:	AigProc
#--------------------------------------------------------------------
# CREE LE:	15/11/1999			Par: V.BRION S.GISLAIN
#--------------------------------------------------------------------
#    
# OBJET DU PRESENT TEMPLATE: 
# - Recherche le nombre de process Autosys "interface graphique"
#   consommant plus de $SeuilCpu% de memoire (=> pb si > 0).
# - Envoi de 1 a l'opcmon si process trouve(s).
# - Si reception de 1, l'opcmon re-appelle alors le template avec "" en parametre.
# - Le template renvoie alors le nom des process en cause dans les annotations ITO, 
#   plus le nom du responsable a contacter et l'adresse IP d'ou a ete generee le process.
#			
#====================================================================
# Modifie le: 09/05/00			Par: vb 
#	Motif: Ajout de la recherche de process consommant de la memoire.
# 
#
#####################################################################
# REMARQUES: Les entetes des fonctions ont ete allegees pour plus
#            de lisibilite (fonction de petite taille et presque
#            identiques
#
#####################################################################
# CONVENTION DES CODES DE RETOUR (autres que 0 (Ok) et 1 (erreur))
#
#====================================================================
# ACCES ET DROITS D'APPEL
#	Mode: 0777	Owner: 			Group:
#====================================================================
# PRE-REQUIS EN ENTREE
# Environnement materiel:
#	Machine: 			Constructeur: HP,SUN,IBM,SGI
# Environnement logiciel:
#	OS: hp-ux			Version: 9.05
#	    hp-ux				 10.20
#	    Solaris				 5.3
#	    Solaris				 5.5
#	    SunOs 				 4.1.3
#	    AIX					 3.x
#	    AIX					 4.2
#	    IRIX				 5.3
# Initialisation des variables globales (environnement, reseau...):
#	VARIABLE1	=	
#	VARIABLE2	=
#####################################################################

### Fonctions:
####################
# IdentificationAutosys(<process>):	Verifie si le process contient les chaines de caractere
#					identifiant un process Autosys 'interface graphique'.
# Continuer:				Traitement effectue lors du second appel du template.
# ChercheParPtree(<process>):		Lance /usr/proc/bin/ptree sur un process.
# ChercheParPs(<process>):		Output par ps d'un process recupere auparavant par ptree.
# AnnotationIto:			Affichage des process fautifs dans les annotations ITO.
# ChercheProprio(<process>):		Recherche le proprietaire d'un process selon son champ 'user'.
#					Les proprietaires sont codes en dur dans le template.
# ChercheTerminal(<process>):		Recherche du terminal ayant lance un process, par equivalence
#					entre le champ TTY du process et le DISPLAY correspondant      
# 					retourne par who. Seules les adresses IP sont retenues.

### parametrie
####################
$Chaines = "<defunct> autosc autoc cape";	# Chaines identifiant les process cherches:
						# <defunct>, autosc, autocons, autocal, hostcape, jobscape.
@IdentifieChaine = split(/ /,$Chaines);		# Tableau des chaines precedentes pour traitement en boucle.
$Defunct = "<defunct>";		# <defunct> est recuperee par ps -aef, pas par ps -aef -o ...
$Proprio = "KO";		# Passe a OK si le user est identifiable (liste en dur dans ce fichier)	
$Terminal = "KO";		# passe a OK si le terminal est identifiable (adresse IP => PC)
$SeuilCpu = 15;			# Seuil de % de Cpu consommee a partir duquel declencher une alerte. 
$SeuilMem = 30;			# Seuil de % de memoire (RAM + SWAP) consommee a partir duquel declencher une alerte. 
$Nbr = 0;			# 0 ou 1, renvoye comme argument. Autre utilisation dans &Continuer.
$TotalCpuKo = 0;		# Compteur de process (cpu) fautifs trouves.
$TotalMemKo = 0;		# Compteur de process (memoire) fautifs trouves.
$Cpt = 0;			# Compteur de process fautifs pour l'affichage sous ITO.
$Host = `/usr/bin/hostname`; 
chop $Host;
$Date = `/usr/bin/date`; 
chop $Date;

$NomTemplate = "";
$NomTemplate = $ARGV[0] if(scalar(@ARGV) > 0);

# Recuperation de tous les process dans TabPs_aef (TabPsC_aef = id, avec ligne d'en-tete).
#######################################################

### test ###
#@TabPsC_aef = `/usr/bin/ps -aef -o s,user,pid,ppid,tty,stime,pcpu,pmem,comm | grep a177795`;
@TabPsC_aef = `/usr/bin/ps -aef -o s,user,pid,ppid,tty,stime,pcpu,pmem,comm`;
foreach $TabPsC_aef(@TabPsC_aef)
{
	chop $TabPsC_aef;
	if($TabPsC_aef !~ /PPID/)
	{
		push (@TabPs_aef,$TabPsC_aef);
	}
}


# Sur ces process, recuperation des seuls process Autosys 'interface graphique' consommant plus de $SeuilCpu% de Cpu et plus de $SeuilMem% de memoire (totale).
#######################################################
foreach $TabPs_aef(@TabPs_aef)
{
        ($S,$User,$Pid,$Ppid,$Tty,$Stime,$Pcpu,$Mem,$Com) = split(/\s+/,$TabPs_aef);
	$TabPs_aef = $TabPs_aef . $Defunct if($Com eq "");
        if(($Pcpu >= $SeuilCpu) && (&IdentifieAutosys($Com) == 1))
        {
		if($TotalCpuKo == 0)
		{	
			$TabCpuKo = $TabPs_aef;	
		}
		else
		{
			$TabCpuKo = $TabCpuKo . "#-#-#" . $TabPs_aef;
		}
		$TotalCpuKo++;
        }
        if(($Mem >= $SeuilMem) && (&IdentifieAutosys($Com) == 1))
        {
		if($TotalMemKo == 0)
		{	
			$TabMemKo = $TabPs_aef;	
		}
		else
		{
			$TabMemKo = $TabMemKo . "#-#-#" . $TabPs_aef;
		}
		$TotalMemKo++;
        }
}

# Fonction d'identification des process Autosys 'interface graphique'.
#######################################################
sub IdentifieAutosys 
{
	local ($Com) = @_;
	foreach $IdentifieChaine(@IdentifieChaine)
	{
		if($Com =~ /$IdentifieChaine/)
		{
			return 1;
			last;
		}
	}
### Test: return 1 ###
#	return 1;
	return 0;
}

# Premier appel: envoi de 0 ou 1 a l'opcmon. Second appel: on continue.
#######################################################
if($NomTemplate eq "")
{
	&Continuer($TabCpuKo,"Cpu") if($TotalCpuKo > 0);
	&Continuer($TabMemKo,"Memoire") if($TotalMemKo > 0);
}
else
{
	$Nbr = 1 if(($TotalCpuKo > 0) || ($TotalMemKo > 0));
### Test (appel direct sans parametre possible) ###
### Si appel avec parametre, le script va se rappeler indefiniment car on ne fait pas appel a opcmon ###
#	$Commande = "/users/exploit/a177795/wincenter/AigProc4 $NomTemplate=$Nbr";
	$Commande = "/logiciel/OpC/opcmon $NomTemplate=$Nbr";
	system( $Commande );
}

	

# Second appel
#######################################################
sub Continuer
{
	local($TabKo,$Param) = @_;
	&AnnotationIto($Param);
	@TabCpuKo = split(/#-#-#/,$TabKo);
	# On conserve la notation TabCpuKo par facilite ...
	foreach $TabCpuKo(@TabCpuKo)
        {
		$Cpt++;
		$TotalCpuKo = $TotalMemKo if($Param eq "Memoire");
		if($TotalCpuKo > 0)
		{
			print "Process fautif numero $Cpt:\n";
		}	
		&ChercheParPtree($TabCpuKo);
		print "\nLe ou les process a killer sont:\n\n";
        	print "@TabPsC_aef[0]\n";
		foreach $PidPtree(@PidPtree)
		{
			&ChercheParPs($PidPtree);
		}
                foreach $TabFin(@TabFin)
                {
                        &ChercheProprio($TabFin) if($Proprio ne "OK");
                        &ChercheTerminal($TabFin) if($Terminal ne "OK");
                }
                print "$b\n";
                print "\n" if($Nbr != 0);
		print "Demander a la ou les personnes suivantes l'autorisation de killer ce(s) process:\n";
                print "$Chaine\n";
                $TerminalUser = "inconnu." if($Terminal ne "OK");
                print "Terminal ayant lance le process fautif: $TerminalUser.\n";
                print "----------------------------------------------------------------------------\n";
                $Proprio = "KO";
                $Terminal = "KO";
                print "\n";
        }
}

# Second appel: arborescence d'un process par /usr/proc/bin/ptree. 
#######################################################
sub ChercheParPtree
{
        local($TabCpuKo) = @_;
                @TabFin = ();
		@PidPtree = ();
        	($S,$User,$Pid,$Ppid,$Tty,$Stime,$Pcpu,$Mem,$Com) = split(/\s+/,$TabCpuKo);
		@Ptree = `/usr/proc/bin/ptree $Pid`;
		$NbrPtree = scalar(@Ptree);
		print "\nArborescence du process:\n\n" if($NbrPtree > 1);
		foreach $Ptree(@Ptree)
		{
			print "$Ptree" if($NbrPtree > 1);
			($PidPtree,$Reste1,$Reste2) = split(/\s+/,$Ptree);
			$PidPtree = $Reste1 if($PidPtree eq "");
			push(@PidPtree,$PidPtree);
		}
}

# Second appel: affichage litteral d'un process par ps (Autosys seul). 
#######################################################
sub ChercheParPs
{
        local($PidPtree) = @_;
        		foreach $TabPs_aef(@TabPs_aef)
        		{
				($S,$User,$Pid,$Ppid,$Tty,$Stime,$Pcpu,$Mem,$Com) = split(/\s+/,$TabPs_aef);
				if(($Pid == $PidPtree) && (&IdentifieAutosys($Com) == 1))
				{
					if(($Com eq "") && ($S eq "Z"))
					{
						$NewCom = $Defunct;
						$TabPs_aef = $TabPs_aef . $NewCom;
					}
					push (@TabFin,$TabPs_aef);
					print "$TabPs_aef\n";
					last;
				}
			}
}

# Second appel: affichage dans les annotations ITO.
#######################################################
sub AnnotationIto
{
	local ($Param) = @_;
	if($Param eq "Cpu")
	{
		$Seuil = $SeuilCpu;
	}
	else
	{
		$Seuil = $SeuilMem;
	}
        print "##############################################################################\n";
        print "$Date     Machine: $Host\n";
	print "Liste des process Autosys 'interface graphique' consommant plus de $Seuil% de $Param:\n";	
        print "##############################################################################\n";
}

# Second appel: recherche du user ayant lance le process.
#######################################################
sub ChercheProprio
{
        local($TabFin) = @_;
        ($S,$User,$Pid,$Ppid,$Tty,$Stime,$Pcpu,$Mem,$Com) = split(/\s+/,$TabFin);
        if($User =~ /adminalc/)
        {
                $Chaine = "user ". $User . " => Mostafa Karimi, tel:47611.";
                $Proprio = "OK";
        }
        elsif($User =~ /polalc/)
        {
		$Chaine1 = "user ". $User . " => Nicolas Bachellereau, tel:42672,\n";
		$Chaine2 = "            ou Bernard Becheny,      tel:49302,\n";
		$Chaine3 = "            ou Stephane Laruelle,    tel:49342.";
		$Chaine = $Chaine1 . $Chaine2 . $Chaine3;
                $Proprio = "OK";
        }
        elsif($User =~ /adminphf/)
        {
                $Chaine = "user ". $User . " => Dominique Soyer, tel:42551.";
                $Proprio = "OK";
        }
        elsif($User =~ /adminbpu/)
        {
                $Chaine = "user ". $User . " => Mostafa Karimi, tel:47611.";
                $Proprio = "OK";
        }
        else
        {
                $Chaine = "user ". $User . " inconnu.";
        }
	$ChaineFin = "\nPrevenez egalement V.Brion au 46558, ou par memo.";
	$Chaine = $Chaine . $ChaineFin;
}

# Second appel: recherche de l'adresse IP du terminal ayant lance le process.
#######################################################
sub ChercheTerminal
{
        local($TabFin) = @_;
        ($S,$User,$Pid,$Ppid,$Tty,$Stime,$Pcpu,$Mem,$Com) = split(/\s+/,$TabFin);
        if($Tty =~ /pts/)
        {
                $Term = `/usr/bin/who | grep "$Tty"`;
		chop $Term;
                ($a1,$a2,$a3,$a4,$a5,$TerminalUser) = split(/\s+/,$Term);
#		Seules les adresses IP sont retenues comme adresses interessantes.
#		Le process du pts/xx peut avoir disparu au moment ou est lance &ChercheTerminal, d'ou:
                $Terminal = "OK" if(($TerminalUser ne "") && ($TerminalUser =~ /\./));
        }
}
