#!/usr/bin/perl
# ============================================================================
# ============================== INFO ========================================
# ============================================================================
# Version	: 0.3.1
# Date		: january 15 2021
# Author	: Justin Bouchard
# Licence 	: GPL - summary below
#
# ============================================================================
# ============================== SUMMARY =====================================
# ============================================================================
#
# Check the state of the redudant stack ring, switches in the stack ring and 
# stackport status
# Check the http://exchange.nagios.org website for new versions.
# V0.3 : Justin Bouchard
#		add support stack virtual in distributed mode
#		check compatibility STACK switch for this script
# compatibility vendor id: see hash variable %cisco_VendorIDModel below  
# 
# V0.2 : Michiel Timmers ( michiel.timmers AT gmx.net)
# ============================================================================
# ============================== LICENCE =====================================
# ============================================================================
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>
#
# ============================================================================
# ============================== HELP ========================================
# ============================================================================
# Help : ./check_snmp_cisco_stack_dist.pl --help
#
# ============================================================================
use strict;
use warnings;
use Net::SNMP;
use Getopt::Long;
# ============================================================================
# ============================== NAGIOS VARIABLES ============================
# ============================================================================
my $TIMEOUT 			= 15;	# This is the global script timeout, not the SNMP timeout
my %ERRORS				= ('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4);
my @Nagios_state 		= ("UNKNOWN","OK","WARNING","CRITICAL"); # Nagios states coding
# ==============================================================
# = Cisco Vendor id compatible with this script generate from  =
# = ftp://ftp.cisco.com/pub/mibs/v2/CISCO-PRODUCTS-MIB.my      =
# = if new mmodel is not in this list you need add it          =
# ==============================================================
my %cisco_VendorIDModel = (
	'ciscoWsC2960XR48FpsI' => '1802', 'ciscoWsC2960XR24PsI' => '1805', 
	'catWsC2960s48fpdL' => '1258', 'catalyst37xxStack' => '516',
	'ciscoWsC2960XR48TsI' => '1804', 'catalyst3750G24TS1U' => '624',  
	'ciscoWsC2960XR48LpsI' => '1803', 'catWsC2960s24tdL' => '1262',    
	'catalyst3750G48TS' => '604', 'catalyst375024TS' => '513',     
	'ciscoC385012S' => '1880', 'catalyst3750v248ts' => '1026',
	'ciscoWsC2960XR24PdI' => '1800', 'catalyst3750E24PD' => '792',    
	'catalyst3750E48TD' => '790', 'catWsC2960s48tsS' => '1256',    
	'catalyst3750G24PS' => '602', 'ciscoWsC2960XR48TdI' => '1799', 
	'catalyst3750G24WS25' => '778', 'catalyst3750v224ts' => '1022',  
	'cat385024' => '1644', 'ciscoC385024XS' => '2163',
	'catWsC2960s48lpsL' => '1264', 'ciscoWsC2960XR24TdI' => '1801',
	'ciscoC385012X48U' => '2165', 'catalyst375048' => '512',
	'cat385024P' => '1642', 'catalyst375024FS' => '656',
	'ciscoC385024XU' => '2166', 'catalyst3750E24TD' => '789',
	'catWsC2960s48fpsL' => '1263', 'catalyst3750G16TD' => '591',
	'cat385048U' => '1768', 'catWsC2960s24tsL' => '1267',
	'catalyst3750G48PS' => '603', 'ciscoWsC2960XR24TsI' => '1806',
	'cat29xxStack' => '1208', 'catalyst375024PS' => '536',
	'catalyst3750E48PD' => '791', 'catalyst3750v248ps' => '1027',
	'ciscoC385048XS' => '2164', 'catWsC2960s24pdL' => '1261',
	'ciscoWsC2960XR48LpdI' => '1798', 'cat385024U' => '1767',
	'ciscoWsC2960XR48FpdI' => '1797', 'ciscoC385024S' => '1879',
	'catalyst3750G24WS50' => '779', 'catalyst375024T' => '514',
	'catWsC2960s48tdL' => '1260', 'cat385048' => '1643',
	'catalyst3750Ge12Sfp' => '530', 'catWsC2960s48ldpL' => '1259',
	'catWsC2960s24tsS' => '1257', 'cat385048P' => '1641',
	'catWsC2960s24psL' => '1265', 'catalyst375048PS' => '535',
	'catWsC2960s48tsL' => '1266', 'catalyst375024' => '511',
	'catalyst3750Ge12SfpDc' => '688', 'catalyst3750v224ps' => '1023',
	'ciscoC385012XS' => '2162', 'cat38xxstack' => '1745',
	'catWsC2960x48fpdL' => '1690', 'cat2960xs24tdL' => '1185',
	'cat2960xs48fpsL' => '1186', 'cat2960xs24psL' => '1188',
	'catWsC2960x48fpsL' => '1695', 'catWsC2960x48tsL' => '1698',
	'catWsC2960x48lpsS' => '1701', 'catWsC2960x48tdL' => '1692',
	'cat2960xs48lpsL' => '1187', 'cat2960xs48lpdL' => '1182',
	'cat2960xs24pdL' => '1184', 'catWsC2960x24psS' => '1702',
	'catWsC2960x48lpdL' => '1691', 'cat2960xs48fpdL' => '1181',
	'cat2960xs24tsL' => '1190', 'catWsC2960x24pdL' => '1693',
	'catWsC2960x24psL' => '1697', 'cat2960xs48ltdL' => '1183',
	'catWsC2960x48lpsL' => '1696', 'cat2960xs48tsL' => '1189',
	'catWsC2960x24tdL' => '1694', 'catWsC2960x24tsL' => '1699'
);
# ============================================================================
# ============================== OID VARIABLES ===============================
# ============================================================================
#SNMPv2-MIB:
my $sysObjectID_oid = "1.3.6.1.2.1.1.2"; # sysObjectID
#SNMPv2-SMI::enterprises.9.1 ->
#.9-CISCO-SMI:
my $ciscoProducts_oid = "1.3.6.1.4.1.9.1";# ciscoProducts
#.9.1-CISCO-STACKWISE-MIB:
my $cisco_StackWiseMIBObjects_oid    = "1.3.6.1.4.1.9.9.500.1"; #:ciscoStackWiseMIBObjects
my $cisco_cswRingRedundant_oid     	 = "1.3.6.1.4.1.9.9.500.1.1.3.0"; 	# cswRingRedundant
my $cisco_cswSwitchInfoEntry_oid	 = "1.3.6.1.4.1.9.9.500.1.2.1.1";	# cswSwitchInfoEntry 
my $cisco_cswSwitchNumCurrent_oid	 = "1.3.6.1.4.1.9.9.500.1.2.1.1.1";	# cswSwitchNumCurrent
my $cisco_cswSwitchState_oid     	 = "1.3.6.1.4.1.9.9.500.1.2.1.1.6"; # cswSwitchState
my $cisco_cswStackPortOperStatus_oid = "1.3.6.1.4.1.9.9.500.1.2.2.1.1";	# cswStackPortOperStatus
#OID for switch with stack virtual distributed domain
my $cisco_cswStackType_oid                   = "1.3.6.1.4.1.9.9.500.1.1.7.0"; # distribued if = 1
my $cisco_cswDistrStackPhyPort_oid           = "1.3.6.1.4.1.9.9.500.1.2.4.1.1"; #cswDistrStackPhyPort port number stackvirtual
my $cisco_cswDistrStackPhyPortOperStatus_oid = "1.3.6.1.4.1.9.9.500.1.2.4.1.2"; #cswDistrStackPhyPortOperStatus port status stackvirtual
#ENTITY-MIB:
my $cisco_entPhysicalSerialNum_oid   = "1.3.6.1.2.1.47.1.1.1.1.11"; 		# entPhysicalSerialNum
# ============================================================================
# ============================== GLOBAL VARIABLES ============================
# ============================================================================
my $Version			= '0.3';	# Version number of this script
my $o_host			= undef; 	# Hostname
my $o_community 		= undef; 	# Community
my $o_port	 		= 161; 		# Port
my $o_help			= undef; 	# Want some help ?
my $o_verb			= undef;	# Verbose mode
my $o_version			= undef;	# Print version
my $o_timeout			= undef; 	# Timeout (Default 5)
my $o_version1			= undef;	# Use SNMPv1
my $o_version2			= undef;	# Use SNMPv2c
my $o_domain			= undef;	# Use IPv6
my $o_login			= undef;	# Login for SNMPv3
my $o_passwd			= undef;	# Pass for SNMPv3
my $v3protocols			= undef;	# V3 protocol list.
my $o_authproto			= 'sha';	# Auth protocol
my $o_privproto			= 'aes';	# Priv protocol
my $o_privpass			= undef;	# priv password
# ============================================================================
# ============================== SUBROUTINES (FUNCTIONS) =====================
# ============================================================================
# Subroutine: Print version
sub p_version { 
	print "check_snmp_cisco_stack version : $Version\n"; 
}
# Subroutine: Print Usage
sub print_usage {
    print "Usage: $0 [-v] -H <host> [-6] -C <snmp_community> [-2] | (-l login -x passwd [-X pass -L <authp>,<privp>])  [-p <port>] [-t <timeout>] [-V]\n";
}
# Subroutine: Check number
sub isnnum { # Return true if arg is not a number
	my $num = shift;
	if ( $num =~ /^(\d+\.?\d*)|(^\.\d+)$/ ) { return 0 ;}
	return 1;
}
# Subroutine: Set final status
sub set_status { # Return worst status with this order : OK, unknown, warning, critical 
	my $new_status = shift;
	my $cur_status = shift;
	if ($new_status == 1 && $cur_status != 2) {$cur_status = $new_status;}
	if ($new_status == 2) {$cur_status = $new_status;}
	if ($new_status == 3 && $cur_status == 0) {$cur_status = $new_status;}
	return $cur_status;
}
# Subroutine: Check if SNMP table could be retrieved, otherwise give error
sub check_snmp_result {
	my $snmp_table		= shift;
	my $snmp_error_mesg	= shift;
	# Check if table is defined and does not contain specified error message.
	# Had to do string compare it will not work with a status code
	if (!defined($snmp_table) && $snmp_error_mesg !~ /table is empty or does not exist/) {
		printf("ERROR: ". $snmp_error_mesg . " : UNKNOWN\n");
		exit $ERRORS{"UNKNOWN"};
	}
}
# Subroutine: Print complete help
sub help {
	print "\nCisco Stack check plugin for Nagios\nVersion: ",$Version,"\n\n";
	print_usage();
	print <<EOT;

Options:
-v, --verbose
   Print extra debugging information 
-h, --help
   Print this help message
-H, --hostname=HOST
   Hostname or IPv4/IPv6 address of host to check
-6, --use-ipv6
   Use IPv6 connection
-C, --community=COMMUNITY NAME
   Community name for the host's SNMP agent
-1, --v1
   Use SNMPv1
-2, --v2c
   Use SNMPv2c (default)
-l, --login=LOGIN ; -x, --passwd=PASSWD
   Login and auth password for SNMPv3 authentication 
   If no priv password exists, implies AuthNoPriv 
-X, --privpass=PASSWD
   Priv password for SNMPv3 (AuthPriv protocol)
-L, --protocols=<authproto>,<privproto>
   <authproto> : Authentication protocol (md5|sha : default sha)
   <privproto> : Priv protocole (des|aes : default aes) 
-P, --port=PORT
   SNMP port (Default 161)
-t, --timeout=INTEGER
   Timeout for SNMP in seconds (Default: 15)
-V, --version
   Prints version number

Notes:
- Check the http://exchange.nagios.org website for new versions.
- For questions, problems and patches send me an e-mail (michiel.timmmers AT gmx.net).

EOT
}

# Subroutine: Verbose output
sub verb { 
	my $t=shift; 
	print $t,"\n" if defined($o_verb); 
}

# Subroutine: Verbose output
sub check_options {
	Getopt::Long::Configure ("bundling");
	GetOptions(
		'v'	=> \$o_verb,		    'verbose'	    => \$o_verb,
        'h'     => \$o_help,    	'help'        	=> \$o_help,
        'H:s'   => \$o_host,		'hostname:s'	=> \$o_host,
        'p:i'   => \$o_port,   		'port:i'	    => \$o_port,
        'C:s'   => \$o_community,	'community:s'	=> \$o_community,
		'l:s'	=> \$o_login,		'login:s'	    => \$o_login,
		'x:s'	=> \$o_passwd,		'passwd:s'	    => \$o_passwd,
		'X:s'	=> \$o_privpass,	'privpass:s'	=> \$o_privpass,
		'L:s'	=> \$v3protocols,	'protocols:s'	=> \$v3protocols,   
        't:i'   => \$o_timeout,     'timeout:i'     => \$o_timeout,
		'V'     => \$o_version,		'version'	    => \$o_version,
		'6'     => \$o_domain,      'use-ipv6'      => \$o_domain,
		'1'     => \$o_version1,    'v1'            => \$o_version1,
		'2'     => \$o_version2,     'v2c'          => \$o_version2
	);
	# Basic checks
	if (defined($o_timeout) && (isnnum($o_timeout) || ($o_timeout < 2) || ($o_timeout > 60))) { 
		print "Timeout must be >1 and <60 !\n";
		print_usage();
		exit $ERRORS{"UNKNOWN"};
	}
	if (!defined($o_timeout)) {
		$o_timeout=15;
	}
	if (defined ($o_help) ) {
		help();
		exit $ERRORS{"UNKNOWN"};
	}
	if (defined($o_version)) { 
		p_version(); 
		exit $ERRORS{"UNKNOWN"};
	}
	# check host and filter 
	if ( ! defined($o_host) ) {
		print_usage();
		exit $ERRORS{"UNKNOWN"};
	}
	# Check IPv6 
	if (defined ($o_domain)) {
		$o_domain="udp/ipv6";
	} else {
		$o_domain="udp/ipv4";
	}
	# Check SNMP information
	if ( !defined($o_community) && (!defined($o_login) || !defined($o_passwd)) ){ 
		print "Put SNMP login info!\n"; 
		print_usage(); 
		exit $ERRORS{"UNKNOWN"};
	}
	if ((defined($o_login) || defined($o_passwd)) && (defined($o_community) || defined($o_version2)) ){ 
		print "Can't mix SNMP v1,v2c,v3 protocols!\n"; 
		print_usage(); 
		exit $ERRORS{"UNKNOWN"};
	}

	# Check SNMPv3 information
	if (defined ($v3protocols)) {
		if (!defined($o_login)) { 
			print "Put SNMP V3 login info with protocols!\n"; 
			print_usage(); 
			exit $ERRORS{"UNKNOWN"};
		}
		my @v3proto=split(/,/,$v3protocols);
		if ((defined ($v3proto[0])) && ($v3proto[0] ne "")) {
			$o_authproto=$v3proto[0];
		}
		if (defined ($v3proto[1])) {
			$o_privproto=$v3proto[1];
		}
		if ((defined ($v3proto[1])) && (!defined($o_privpass))) {
			print "Put SNMP v3 priv login info with priv protocols!\n";
			print_usage(); 
			exit $ERRORS{"UNKNOWN"};
		}
	}
}
#***************************
#************Main***********
#***************************
check_options();
# Connect to host
my ($session,$error);
if (defined($o_login) && defined($o_passwd)) {
	# SNMPv3 login
	verb("SNMPv3 login");
	if (!defined ($o_privpass)) {
		# SNMPv3 login (Without encryption)
		verb("SNMPv3 AuthNoPriv login : $o_login, $o_authproto");
		($session, $error) = Net::SNMP->session(
		-domain		=> $o_domain,
		-hostname	=> $o_host,
		-version	=> 3,
		-username	=> $o_login,
		-authpassword	=> $o_passwd,
		-authprotocol	=> $o_authproto,
		-timeout	=> $o_timeout
	);  
	} else {
		# SNMPv3 login (With encryption)
		verb("SNMPv3 AuthPriv login : $o_login, $o_authproto, $o_privproto");
		($session, $error) = Net::SNMP->session(
		-domain		=> $o_domain,
		-hostname	=> $o_host,
		-version	=> 3,
		-username	=> $o_login,
		-authpassword	=> $o_passwd,
		-authprotocol	=> $o_authproto,
		-privpassword	=> $o_privpass,
		-privprotocol	=> $o_privproto,
		-timeout	=> $o_timeout
		);
	}
} else {
	if ((defined ($o_version2)) || (!defined ($o_version1))) {
		# SNMPv2 login
		verb("SNMP v2c login");
		($session, $error) = Net::SNMP->session(
		-domain		=> $o_domain,
		-hostname	=> $o_host,
		-version	=> 2,
		-community	=> $o_community,
		-port		=> $o_port,
		-timeout	=> $o_timeout
		);
	} else {
		# SNMPv1 login
		verb("SNMP v1 login");
		($session, $error) = Net::SNMP->session(
		-domain		=> $o_domain,
		-hostname	=> $o_host,
		-version	=> 1,
		-community	=> $o_community,
		-port		=> $o_port,
		-timeout	=> $o_timeout
		);
	}
}
# Check gobal timeout if SNMP screws up
if (defined($TIMEOUT)) {
	verb("Alarm at ".$TIMEOUT." + ".$o_timeout);
	alarm($TIMEOUT+$o_timeout);
} else {
	verb("no global timeout defined : ".$o_timeout." + 15");
	alarm ($o_timeout+15);
}
# Report when the script gets "stuck" in a loop or takes to long
$SIG{'ALRM'} = sub {
	print "UNKNOWN: Script timed out\n";
	exit $ERRORS{"UNKNOWN"};
};
#--- Check if there are any problems with the session ---
if (!defined($session)) {
	printf("ERROR opening session: %s.\n", $error);
	exit $ERRORS{"UNKNOWN"};
}
#--- variables for CISCO STACK-----
my $output = "";	
my $final_status = 0;
my $stackport_up = 0;
my $stackport_down = 0;
my $stackport_forcedDown = 0;
my $number_of_switches = 0;
my ($cswSwitchState,$cswSwitchNumCurrent,$entPhysicalSerialNum,$cswStackPortOperStatus)=(undef,undef,undef,undef);
my $cisco_cswDistrStackPhyPort = undef;
my $cisco_cswDistrStackPhyPortOperStatus = undef;
my $cisco_cswRingRedundant = undef;
my $cisco_StackWiseMIBObjects = undef;
my $cisco_entPhysicalSerialNum = undef;
my %statusport = (1 => "up",2 => "down",3 => "forced down");
my %switchState =(
	1 => "WAITING", 2 => "PROGRESSING", 3 => "ADDES!",
	4 => "Ready", 5 => "SDM-MISMATCH", 6 => "VER-MISMATCH",
	7 => "FEATURE-MISMATCH", 8 => "NEW-MASTER-INIT", 9 => "PROVISIONED",
	10 => "INVALID", 11 =>"REMOVED"
);
my $cisco_cswStackType = undef;
my $ciscoModel = "false";
my @check_Model = undef;
my $sysObjectID = undef;
#************************************************************************
# Get SNMP Tables Check result caution $cisco_StackWiseMIBObjects
# and $cisco_entPhysicalSerialNum is a pointer after snmp table query
#*************************************************************************
$sysObjectID = $session->get_request(-varbindlist => [$sysObjectID_oid.".0"]);
&check_snmp_result($sysObjectID,$session->error);
#-- Check Model compatibility for this script --
@check_Model = values %$sysObjectID;
$check_Model[0]=~ s/$ciscoProducts_oid\.//;
foreach (values %cisco_VendorIDModel){
	if ($check_Model[0] == $_){
		$ciscoModel = "true";
		last;
	} 
}
if ($ciscoModel eq "false"){
	$output = "This Cisco switch is not in list for this script check cisco vendor ID : UNKNOWN";
	print $output;
	exit $ERRORS{'UNKNOWN'};
}
$cisco_StackWiseMIBObjects = $session->get_table(-baseoid => $cisco_StackWiseMIBObjects_oid);
&check_snmp_result($cisco_StackWiseMIBObjects,$session->error);
$cisco_entPhysicalSerialNum = $session->get_table(-baseoid => $cisco_entPhysicalSerialNum_oid);
&check_snmp_result($cisco_entPhysicalSerialNum,$session->error);
$session->close;#end get SNMP and close session
#-- Check switch is stackable ---
if (!defined($cisco_StackWiseMIBObjects)) {
	$output = "Switch is non-stackable : UNKNOWN";
	exit $ERRORS{'UNKNOWN'};
}
#---check switch states
$output.= "Switch States: ";
foreach my $key (sort keys %$cisco_StackWiseMIBObjects) {
	if ($key =~ /$cisco_cswSwitchState_oid/) {
		$key =~ s/$cisco_cswSwitchState_oid//;
		$number_of_switches++;
		$cswSwitchState	= $$cisco_StackWiseMIBObjects{$cisco_cswSwitchState_oid.$key};
		$cswSwitchNumCurrent = $$cisco_StackWiseMIBObjects{$cisco_cswSwitchNumCurrent_oid.$key};
		$entPhysicalSerialNum = $$cisco_entPhysicalSerialNum{$cisco_entPhysicalSerialNum_oid.$key};
		$output.= "sw".$cswSwitchNumCurrent."(sn:".$entPhysicalSerialNum.")=".$switchState{$cswSwitchState}.", ";
		if ($cswSwitchState != 4){
			$final_status = &set_status(2,$final_status);
		}
	}
}
#**********************************************
# ---- check port states------
#**********************************************
$output.= ": Port States: ";
#---check StackType
if (defined $$cisco_StackWiseMIBObjects{$cisco_cswStackType_oid}){
	$cisco_cswStackType = ($$cisco_StackWiseMIBObjects{$cisco_cswStackType_oid});
}
#******************************************
# case switch virtual is ditributed stack
#******************************************
if (defined $cisco_cswStackType && $cisco_cswStackType == 1){
	foreach my $key (sort keys %$cisco_StackWiseMIBObjects){
		if ($key =~ /$cisco_cswDistrStackPhyPort_oid/){
			$key =~ s/$cisco_cswDistrStackPhyPort_oid//;
			$cisco_cswDistrStackPhyPortOperStatus = $$cisco_StackWiseMIBObjects{$cisco_cswDistrStackPhyPortOperStatus_oid.$key};            
			$output.= $$cisco_StackWiseMIBObjects{$cisco_cswDistrStackPhyPort_oid.$key}.": ".$statusport{$cisco_cswDistrStackPhyPortOperStatus}.", ";            
			if ($cisco_cswDistrStackPhyPortOperStatus == 2){
				$final_status = &set_status(2,$final_status);
			}
		}
	}
}
#**************************************************
#----case switch virtual is conventional stack ----
#**************************************************
if (!defined $cisco_cswStackType || $cisco_cswStackType == 0){
	foreach my $key (sort keys %$cisco_StackWiseMIBObjects) {
		if ($key =~ /$cisco_cswStackPortOperStatus_oid/) {
			$key =~ s/$cisco_cswStackPortOperStatus_oid//;
			$cswStackPortOperStatus	= $$cisco_StackWiseMIBObjects{$cisco_cswStackPortOperStatus_oid.$key};
			if ($cswStackPortOperStatus == 1){$stackport_up++}
			if ($cswStackPortOperStatus == 2){$stackport_down++}
			if ($cswStackPortOperStatus == 3){$stackport_forcedDown++}
		}
	}
	$output.= "up(".$stackport_up."), ";
	if ($stackport_down == 0){
		$output.= "down(0), ";
	}else{
		if ($number_of_switches == 1){
			$output.= "down(".$stackport_down."), ";
		}else{
			$output.= "DOWN(".$stackport_down."!), ";
			$final_status = &set_status(2,$final_status);
		}
	}
	if ($stackport_forcedDown == 0){
		$output.= "forcedDown(0) ";
	}else{
		$output.= "FORCED-DOWN(".$stackport_forcedDown."!) ";
		$final_status = &set_status(2,$final_status);
	}
	#--- check ring status---
	$cisco_cswRingRedundant = $$cisco_StackWiseMIBObjects{$cisco_cswRingRedundant_oid};
	if($cisco_cswRingRedundant == 1){
		$output = "Ring Redundant: yes : ".$output;
	}else{
		if ($number_of_switches == 1){
			$output = "Ring Redundant: no (single switch in stack) : ".$output;
		}else{
			$output = "Ring Redundant: NO! : ".$output;
			$final_status = &set_status(2,$final_status);
		}
	}
}
#**********************************************
# check final status, add it to output then exit
#**********************************************
foreach my $key (keys %ERRORS){
    if ($final_status == $ERRORS{$key}){
            $output.=": Satus: ".$key;
    }
}
print $output;
exit ($final_status);