package IRIX;

# IRIX.pm - these are operating system specific routines for IRIX
#
# Rules for these subroutines:
# 
#	1.  These subroutines can be called in any order except
#	    for Initialize${OSName}.  That will always be called
#	    before any others.
#	2.  These subroutines can be called in any order...
# 
# ==============================================================
# 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 
# 2 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.
# 
# Original source:
#	Copyright (c) 1999, 2000 Frank Crawford <frank@ansto.gov.au>
#	Based upon code by Bruce W. Mohler
# 
# Contributed source:
#	Copyright (c) 1999, 2000 Martin Andrews
#	Copyright (c) 1999, 2000 Alek O. Komarnitsky
#	Copyright (c) 1999, 2000 Bruce W. Mohler
#	Copyright (c) 2000 Ken Monville
# 
# ==============================================================
# 
# $Header: /export/home/mohlerb/syssumm/remote/RCS/IRIX.pm,v 1.34 2000/04/27 17:46:30 mohlerb Exp mohlerb $
# 
# $Revision: 1.34 $
# 
# $Log: IRIX.pm,v $
# Revision 1.34  2000/04/27 17:46:30  mohlerb
# changes from Ken Monville including:
# Fix a typo ReturnArray -> ReturnArrayExec
#
# Revision 1.33  2000/04/22 22:59:05  mohlerb
# changes from Ken Monville including:
# patched to detect if you're using the XLV Volume Manager
# in addition to RAID and it also reads the Eeprom and prints
# that information just like the SunOS.pm module
#
# Revision 1.32  2000/04/22 22:32:24  mohlerb
# changes from Ken Monville including:
# added support for Fore ForeRunnerHE ATM nic's under IRIX;
# changed sub ReturnNetworkInterfacesIRIX () to use both hinv
# and ifconfig -a output to find interfaces; modeled the IRIX
# routine after the SunOS one
#
# Revision 1.31  2000/04/10 17:27:14  mohlerb
# changes from Bruce Mohler including:
# replaced calls to ReturnArray with either ReturnArrayFile or
# ReturnArrayExec; also removed references to ReturnArrayGlob
#
# Revision 1.30  2000/02/09 23:44:18  mohlerb
# changes from Bruce Mohler including:
# cleaned up ReturnServices by moving function to common.pm
# and having it be driven by a @Services array in syssumm.pl;
# note also the option at the end of the Initialize<OS> function
# where you can add OS-specific services that you wish to have
# monitored
#
# Revision 1.29  2000/02/04 00:14:32  mohlerb
# changes from Bruce Mohler including:
# implemented ReturnServices to return all of the Running*
# functions as a multiple value field
#
# Revision 1.28  2000/02/03 23:22:02  mohlerb
# changes from Martin Andrews including:
# IRIX, Linux, and SunOS now report swap file sizes, stubs added
# to other OS modules
#
# Revision 1.27  2000/01/07 01:20:51  mohlerb
# changes from Bruce Mohler including:
# added code to ReturnRunningSendmail* to determine what version
# of sendmail is running from the sendmail.cf file
#
# Revision 1.26  2000/01/06 18:20:56  mohlerb
# changes from Bruce Mohler including:
# final (?) changes for e-mail delivery
#
# Revision 1.25  2000/01/06 16:56:04  mohlerb
# changes from Frank Crawford including:
# Taken $EmailAvailable out of common.pm, syssumm.pl and
# IRIX.pm; Made Sendmail.pm a package of its own; Added a
# Response variable in Sendmail.pm; Reworked error messages,
# etc, in common.pm; Fixed up the end of line in the messages;
# Reworked $Username as discussed
#
# Revision 1.24  2000/01/03 20:18:18  mohlerb
# changes from Bruce Mohler including:
# cleaned out references to $MailCommand to complete changes
# that Frank Crawford made to syssumm.pl and common.pm in
# order to use the Sendmail.pm module
#
# Revision 1.23  2000/01/03 19:49:58  mohlerb
# changes from Frank Crawford including:
# Removes the error messages from the IRIX.pm module reported
# by Richard Crane (not a true fix, Frank is continuing to work
# with Richard to really fix this problem)
#
# Revision 1.22  1999/11/03 19:23:32  mohlerb
# changes from Bruce Mohler including:
# fixed typo in RunningLpsched function: s/BSDLp/BSDLpr/
#
# Revision 1.21  1999/11/02 23:29:29  mohlerb
# changes from Bruce Mohler including:
# abstracted Lpsched routines into 3 routines moved to common.pm
# including ReturnRunningSysvLp, ReturnRunningBSDLpr, and
# ReturnRunningLPRng, then inserted code in each of the OS
# modules (except AIX.pm) to call the appropriate routines
# and concatenate the results into a single coherent response
#
# Revision 1.20  1999/11/02 22:15:20  mohlerb
# changes from Alek O. Komarnitsky including:
# support for local exclusions file to prevent one or more
# categories/sub-categories from processing without having
# to specify command line options or change Perl code
#
# Revision 1.19  1999/10/27 20:03:38  mohlerb
# changes from Alek O. Komarnitsky including:
# added ReturnFstab() to common.pm and stubs as appropriate
#
# Revision 1.18  1999/10/26 22:11:53  mohlerb
# Changes from Alek O. Komarnitsky including:
# added a stub routine for listing the file systems exported from
# the local machine
#
# Revision 1.17  1999/10/26 14:19:15  mohlerb
# Changes from Alek O. Komarnitsky including:
# added a stub routine for dumping the EEPROM for disaster
# recovery purposes
#
# Revision 1.16  1999/08/05 21:33:05  mohlerb
# changes from Bruce Mohler including:
# fed $DefaultRouter to IPtoFQDN before returning
#
# Revision 1.15  1999/08/05 21:23:14  mohlerb
# changes from Bruce Mohler including:
# folded post processing after IPtoFQDN call into common.pm into
# actual IPtoFQDN call to expand IP address to fully qualified
# domain name (plus IP address) if possible
#
# Revision 1.14  1999/07/02 21:21:15  mohlerb
# changes from Bruce Mohler including:
# Perl complained about the UnameCommand in syssumm.pl not being
# used because it couldn't see (yet) the references down in the
# OS modules.  Since AIX doesn't have the uname command in the
# same place as the other OSs (so far), I moved the UnameCommand
# local to each OS module.
#
# Revision 1.13  1999/07/02 16:19:38  mohlerb
# changes from Frank Crawford including:
# Removed incorrect comment.
#
# Revision 1.12  1999/06/17 17:30:54  mohlerb
# changes from Frank Crawford including:
# Moved ReturnDomainNameSunOS to common.pm.
#
# Revision 1.11  1999/06/15 14:04:42  mohlerb
# changes from Frank Crawford including:
# fix for ReturnRunningSamba function: added $InetdConfPath
#
# Revision 1.10  1999/06/11 18:33:14  mohlerb
# changes from Bruce Mohler including:
# put in "stub" for adding domainname to NIS field if NIS running
#
# Revision 1.9  1999/06/11 17:47:21  mohlerb
# changes from Bruce Mohler including:
# factored ReturnRunningSamba routine into common.pm
#
# Revision 1.8  1999/06/11 16:06:46  mohlerb
# changes from Frank Crawford including:
# small changes to global variables for Samba and Netstat
#
# Revision 1.7  1999/06/10 22:50:38  mohlerb
# changes from Bruce Mohler including:
# modified unified call to Net::Domain::Hostname to determine
# hostname of local system as it calls a CPAN module and we
# want to avoid this for purposes of portability; instead we
# call Sys::Hostname which is part of the core Perl 5 distribution
#
# Revision 1.6  1999/06/10 21:58:01  mohlerb
# changes from Bruce Mohler including:
# standardized derivation of NodeName across OS modules:
# it is defined near the beginning of the Initialize${OSName}
# and stored in $main::NodeName.  The ReturnNodeNameField
# merely returns $main::NodeName.
#
# Revision 1.5  1999/06/10 21:13:35  mohlerb
# changes from Frank Crawford including:
# small change to ReturnRunningNFSIRIX function to initialize variable
#
# Revision 1.4  1999/06/08 18:42:48  mohlerb
# change from Frank Crawford including:
# Now using netstat to obtain MAC address.
# Addition of default IPAddress and Netmask routines.
# Specification of SGI Mailcommand (for common.pm use).
# Added call to scsicontrol to probe for disk info (requires root access).
# Made OSRelease include the release details for IRIX 6.5 and later.
# Reorganised Disk and Tape lookups.
# Added table to map Network device to a "description".
# Added new samba code (from AIX module).
# General code reformatting.
#
# Revision 1.3  1999/06/07 18:56:13  mohlerb
# change from Bruce Mohler including:
# common ReturnRunAsRoot relocated from individual OS modules
# to common.pm; RunAsRoot variable relocated to syssumm.pl
# (referenced as $main::RunAsRoot); this suggestion was really
# Frank Crawford's...
#
# Revision 1.2  1999/06/04 18:51:51  mohlerb
# changes from Bruce Mohler including:
# Added code for "RunAsRoot" functionality.
#
# Revision 1.1  1999/06/02 21:35:52  mohlerb
# Initial revision
#

use Sys::Hostname;
use Time::Local;
use common;

require Exporter;
@ISA = qw(Exporter);
###########################################################################
# the following sub-routines (&) are variables ($) will be 
# visible in a program using this module...
@EXPORT = qw(
	&InitializeIRIX
);
# 
# Note that you do not need to export the Return* subroutine
# names since they are being called by reference.
# 
###########################################################################

###########################################################################
# Public Global Variables (must be declared above)
###########################################################################


###########################################################################
# Private Global Variables
###########################################################################

# parts of OS version - filled in by InitializeIRIX()
$OSVersion = "";
$OSVersionMajor = "";
$OSVersionMinor = "";

# where commands are located			standard args
# CUSTOMIZE
$AutomountCommand = "/usr/etc/automount";
$AutomountPattern = "(\/automount|\/autofsd)";
$ChkconfigCommand = "/sbin/chkconfig";		$ChkconfigArgs = "-s";
$DfCommand = "/bin/df";				$LocalFileSystems = "-kl";
						$NFSFileSystems = "-k -F nfs";
$EepromCommand = "/sbin/nvram";
$HinvCommand = "/sbin/hinv";			$HinvArgs = "-v";
$IfconfigCommand = "/usr/etc/ifconfig";
$LpstatCommand = "/usr/bin/lpstat";		$LpstatArgs = "-p";
$LpcCommand = "/usr/etc/lpc";			$LpcArgs = "status";
$MountdCommand = "/usr/etc/rpc.mountd";
$NetstatCommand = "/usr/etc/netstat";		$NetstatRouteArgs = "-rn";
						$NetstatMacArgs = "-ianI";
$NfsdCommand = "/usr/etc/nfsd";
$NISServerCommand = "/usr/etc/yp/ypserv"; 
$NISClientCommand = "/usr/etc/yp/ypbind";
$NsdCommand = "/usr/etc/nsd";
$PsCommand = "/usr/bin/ps";			$PsArgs = "-aef";
# Apparently only in 6.X and up.  For IRIX 5.3 you need to compile the
# code supplied in the demos directory.
$ScsiControlCommand = "/usr/sbin/scsicontrol";	$ScsiControlArgs = "-i /dev/scsi/* 2>&1";
$SendmailCommand = "/usr/lib/sendmail";
$SwapCommand = "/sbin/swap -l";
$SysinfoCommand = "/sbin/sysinfo";		$SysinfoArgs = "-s";
$UnameCommand = "/bin/uname";
$VersionsCommand = "/usr/sbin/versions";	$VersionsArgs = "-b";
$XlvmgrCommand = "/sbin/xlv_mgr";       $XlvmgrArgs = "-c \"show kernel\"";

# Search Patterns
$LpDaemonPattern = "(\/lpsched|\/lpd)";
$NameServerPattern = "/usr/sbin/(in\.)?named";

# where files are located
# CUSTOMIZE
$ExportsPath = "/etc/exports";
$EtcFstabPath = "/etc/fstab";
$InetdConfPath = "/etc/inetd.conf";
$NISServConfPath = "/var/ns/domains/*/nsswitch.conf";	# For glob match
$NsSwitchConfPath = "/etc/nsswitch.conf";
$ResolvConfPath = "/etc/resolv.conf";
$SendmailConfPath = '/etc/sendmail.cf';
$SyslogConfPath = "/etc/syslog.conf";

# The following list was found by examining the config files for IRIX 6.5
# Moved here to be consistant with the SunOS.pm module
%IfList = (
	'ci'  =>	'Fore ForeRunnerHE 155/622 ATM, Classical IP',
	'cl'  =>	'CrayLink',
	'ec'  =>	'SGI (Eclipse) Indigo/Indy/Indigo2 Ethernet',
	'ecf' =>	'SGI fast Ethernet',
	'ee'  =>	'Everest IO4 EPC SEEQ/EDLC Ethernet',
	'ef'  =>	'SGI IOC3 10/100Mbps Fast Ethernet',
	'eg'  =>	'Tigon Gigabit Ethernet',
	'el'  =>	'Fore ForeRunnerHE 155/622 ATM, Emulated LAN',
	'ep'  =>	'E-Plex 8-port mez. Ethernet board',
	'et'  =>	'Integral Ethernet controller on IO2 boards',
	'fa'  =>	'Fore ForeRunnerHE 155/622 ATM, FORE IP',
	'fxp' =>	'CMC c130 FXP Ethernet board',
	'gfe' =>	'ThunderLAN Ethernet',
	'hy'  =>	'NSC HYPERchannel with IKON interface',
	'ipg' =>	'FDDIXPress, 6U FDDI board',
	'ls'  =>	'Load sharing network pseudo-device',
	'lsp' =>	'Load sharing network pseudo-device for point-to-point',
	'me'  =>	'IP32 motherboard fast Ethernet',
	'ppp' =>	'STREAMS Point-to-Point-Protocol',
	'ptr' =>	'Madge tokenring adapter',
	'rns' =>	'RNS PCI FDDI board',
	'sl'  =>	'STREAMS Serial Line Internet Protocol',
	'sw'  =>	'swIPe',
	'tr'  =>	'Fore ForeRunnerHE 155/622 ATM, Token Ring',
	'vfe' =>	'VME Fast Ethernet',
	'xpi' =>	'GIO bus and mez. FDDI board',
);


###########################################################################
# Subroutines
###########################################################################

# 
# This subroutine is called before any others.  It's
# reason for existence is to plug in the references to
# subrotines below to actually generate the information.
# 

sub InitializeIRIX ()
{
	print "InitializeIRIX()...\n" if $main::Debug;

	WhatVersionOfIRIX();

	# we need the nodename for later on...
	$main::NodeName = hostname();
	print "\tNodeName is $main::NodeName\n" if $main::Debug;

	# plug in appropriate subroutines
	$main::Routines{General}{Vendor} = \&ReturnVendorIRIX;
	$main::Routines{General}{Model} = \&ReturnModelIRIX;
	$main::Routines{General}{HostId} = \&ReturnHostIdIRIX;

	$main::Routines{Hardware}{Processors} = \&ReturnProcessorsIRIX;
	$main::Routines{Hardware}{Memory} = \&ReturnMemoryIRIX;
	$main::Routines{Hardware}{Disks} = \&ReturnDisksIRIX;
	$main::Routines{Hardware}{Tapes} = \&ReturnTapesIRIX;
	$main::Routines{Hardware}{StorageManager} = \&ReturnStorageManagerIRIX;
	$main::Routines{Hardware}{Eeprom} = \&ReturnEepromIRIX;

	$main::Routines{Network}{DomainName} = \&ReturnDomainNameIRIX;
 	$main::Routines{Network}{DefaultRouter} = \&ReturnDefaultRouterIRIX;
 	$main::Routines{Network}{NameServer} = \&ReturnNameServerIRIX;
	$main::Routines{Network}{IPAddress} = \&ReturnIPAddressIRIX;
	$main::Routines{Network}{SubnetMask} = \&ReturnSubnetMaskIRIX;
 	$main::Routines{Network}{NetworkInterfaces} = \&ReturnNetworkInterfacesIRIX;
 
	$main::Routines{Software}{OsName} = \&ReturnOsNameIRIX;
	$main::Routines{Software}{OsVersion} = \&ReturnOsVersionIRIX;
	$main::Routines{Software}{NbrOfLicenses} = \&ReturnNotApplicableField;
	$main::Routines{Software}{Patches} = \&ReturnPatchesIRIX;
	$main::Routines{Software}{Printers} = \&ReturnPrintersIRIX;
	$main::Routines{Software}{Services} = \&ReturnServices;
	$main::Routines{Software}{IPAddressResolution} = \&ReturnIPAddressResolutionIRIX;
	$main::Routines{Software}{GraphicalUserInterface} = \&ReturnGraphicalUserInterfaceIRIX;
	$main::Routines{Software}{FontServer} = \&ReturnFontServerIRIX;
	$main::Routines{Software}{Fstab} = \&ReturnFstab;
	$main::Routines{Software}{LocalFileSystems} = \&ReturnLocalFileSystemsIRIX;
	$main::Routines{Software}{RemoteFileSystems} = \&ReturnRemoteFileSystemsIRIX;
	$main::Routines{Software}{ExportedFileSystems} = \&ReturnExportedFileSystemsIRIX;
	$main::Routines{Software}{Swap} = \&ReturnSwapIRIX;

	# if you have OS-specific services, add them here
	# push @main::Services, "Local-Service";

	RemoveLocalExclusions();

	return;
}


###########################################################################
# Global
###########################################################################


sub WhatVersionOfIRIX
{
	print "WhatVersionOfIRIX()...\n" if $main::Debug;

	$OSVersion = `$UnameCommand -r`;
	chomp($OSVersion);
	print "\tRunning version $OSVersion...\n" if $main::Debug;

	$OSVersion =~ /(\d+\.\d+)/;
	$OSVersionMajor = $1;
	$OSVersionMinor = "";
	if ($OSVersionMajor >= 6.5) {
		my $OSRelease = `$UnameCommand -R`;
		chomp($OSRelease);
		if ($OSRelease =~ /\d+\.\d+\s*((\d+\.\d+)\.(\d+[mf]?))?/) {
			$OSVersion = $1;
			$OSVersionMajor = $2;
			$OSVersionMinor = $3;
		}
	}
	print "\tMajor OS version is $OSVersionMajor...\n" if $main::Debug;
	print "\tMinor OS version is $OSVersionMinor...\n" if $main::Debug;

	return;
}


###########################################################################
# General
###########################################################################


sub ReturnVendorIRIX ($)
{	my $Subcategory = shift;
	
	# CUSTOMIZE
	return ('SGI');
}


sub ReturnModelIRIX ($)
{	my $Subcategory = shift;

	my $Model = `$UnameCommand -m`;
	chomp($Model);

	return ( $Model );
}


sub ReturnHostIdIRIX ($)
{	my $Subcategory = shift;

	my $IdNbr = `$SysinfoCommand $SysinfoArgs`;
	chomp($IdNbr);
	# I don't know why SGI don't report it as a hex as that is what they want.
	$IdNbr = sprintf("%#x", $IdNbr) if $IdNbr != 0;

	return ( $IdNbr );
}


###########################################################################
# Hardware
###########################################################################


sub ReturnProcessorsIRIX ($)
{	my $Subcategory = shift;
	my $NumProcessors = 0;
	my $ProcessorSpeed = "";
	my $ProcessorType = "";
	my @Processors = ( );
	my @Hinv = ReturnArrayExec("$HinvCommand $HinvArgs");

	foreach $Line (@Hinv) {
		if ($Line =~ /^\s+Processor (\d+).*:\s+(\d+ \whz)\s+(\w+)/) {
			push @Processors, "processor $1 MIPS $3 $2";
		} elsif ($Line =~ /^(\d+) (\d+ \wHZ) (\w+) Processors?/i) {
			$NumProcessors = $1;
			$ProcessorSpeed = $2;
			$ProcessorType = $3 unless $ProcessorType;
		} elsif ($Line =~ /^CPU: MIPS (\w+)/) {
			$ProcessorType = $1;
		}
	}

	if ( ! @Processors ) {
		for $cnt (0 .. ($NumProcessors - 1)) {
			push @Processors, "processor $cnt MIPS $ProcessorType $ProcessorSpeed";
		}
	}

	my @Response = ForceMultipleResponses(\@Processors);

	return @Response;
}


sub ReturnMemoryIRIX ($)
{	my $Subcategory = shift;
	my $Memory = "";
	my @Hinv;

	@Hinv = ReturnArrayExec("$HinvCommand $HinvArgs");

	foreach (@Hinv) {
		if (/^Main memory size:\s+(\d+) (.)bytes/) {
			$Memory = $1 . $2 . 'B';
			last;
		}
	}

	if ( $Memory ) {
		return ( $Memory );
	}
	else {
		return ( ReturnUnknownField($Subcategory) );
	}
}


sub ReturnDisksIRIX ($)
{	my $Subcategory = shift;
	my @Response = ( );
	
	my @Hinv = ReturnArrayExec("$HinvCommand $HinvArgs");

	foreach $Line ( @Hinv ) {

		next if $Line =~ /controller:/i;

		if ($Line =~ /^\s*(RAID|Disk|CDROM)[^:]*: unit (\d+)(, lun (\d+))? on SCSI controller (\d+)/) {
			my $Response;

			if (defined($3)) {
				$Response = GetHardware($Subcategory,
					$1, "/dev/rdsk/dks%dd%dl%dvol", $5, $2, $4);
			} else {
				$Response = GetHardware($Subcategory,
					$1, "/dev/rdsk/dks%dd%dvol", $5, $2, 0);
			}

			push @Response, $Response;
		}
	}
	
	@Response = ForceMultipleResponses(\@Response);
	
	return @Response;
}


sub ReturnTapesIRIX ($)
{	my $Subcategory = shift;
	my @Response = ( );

	my @Hinv = ReturnArrayExec("$HinvCommand $HinvArgs");

	foreach $Line ( @Hinv ) {

		if ($Line =~ /^\s*Tape drive: unit (\d+)(, lun (\d+))? on SCSI controller (\d+):\s*(.*)/) {
			my $Response;

			if (defined($3)) {
				$Response = GetHardware($Subcategory,
					$5, "/dev/rmt/tps%dd%dl%d", $4, $1, $3);
			} else {
				$Response = GetHardware($Subcategory,
					$5, "/dev/rmt/tps%dd%d", $4, $1, 0);
			}

			push @Response, $Response;
		}
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


sub GetHardware($$$$$$)
{	my $Subcategory = shift;
	my $DeviceType = shift;
	my $DevPattern = shift;
	my $ScsiController = shift;
	my $ScsiID = shift;
	my $ScsiLUN = shift;

	my $DeviceAddress = "";
	my $DeviceModel = "";
	my $ScsiAddress = "";
	my $ScsiPattern = "/dev/scsi/sc%dd%dl%d";

	if (defined($ScsiLUN)) {
		$DeviceAddress = sprintf($DevPattern,
			$ScsiController, $ScsiID, $ScsiLUN);
		$ScsiAddress = sprintf($ScsiPattern,
			$ScsiController, $ScsiID, $ScsiLUN);
	} else {
		$DeviceAddress = sprintf($DevPattern,
			$ScsiController, $ScsiID);
		$ScsiAddress = sprintf($ScsiPattern,
			$ScsiController, $ScsiID, 0);
	}
	$DeviceModel = AddDeviceModel($ScsiAddress);
	$DeviceType = "\"$DeviceType\"" if $DeviceType =~ /\W/;

	print "\tfound $Subcategory $DeviceAddress $DeviceType $DeviceModel\n" if $main::Debug;

	return("dev=$DeviceAddress type=$DeviceType model=\"$DeviceModel\"");
}


sub AddDeviceModel ($)
{	my $ScsiAddress = shift;
	my $Response = "unknown";

	my @ScsiText = ReturnArrayExec("$ScsiControlCommand $ScsiControlArgs");
	foreach $Line (@ScsiText) {
		if ( $Line =~ /permission denied/i ) {
			$main::RunAsRoot = 1;
			last;
		} elsif ( $Line =~ /no such file/i ) {
			last;
		} elsif ($Line =~ /^${ScsiAddress}:\s+\S+\s+(.*)/) {
			($Response = $1) =~ tr/ / /s;
			last;
		}
	}

	return($Response);
}


sub ReturnStorageManagerIRIX ($)
{	my $Subcategory = shift;

	my @Hinv = ReturnArrayExec("$HinvCommand $HinvArgs");
	my @Packages = ReturnArrayExec("$VersionsCommand");

	my $RAID = grep(/RAID lun/, @Hinv);

	PACKAGE:foreach $Line (@Packages) {
		if ( $RAID ) {
			$Line =~ /^I\s+raid\s+\S+\s+(.*)$/ && push @Response, $1;
		}
		if ( $Line =~ /^I\s+eoe\.sw\.xlv\s+\S+\s+(.*)$/ ) {
			my $XlvResponse = $1;

			# make sure we're actually using it and not just have it installed
			my @Xlvmgr = ReturnArrayExec("$XlvmgrCommand $XlvmgrArgs");
			# start at the end, that's where the line should be
			for ($c = $#Xlvmgr; $Xlvmgr[$c] =~ /^There\s+\S+\s+(\d+)\s+\S+\.$/; $c--) {
				my $NumberVolumes = $1;

				if ($NumberVolumes =~ /^\d+$/ && $NumberVolumes > 0) {
					push @Response, $XlvResponse;
					next PACKAGE;  # found it, we're done looking
				}
			}
		}
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


sub ReturnEepromIRIX ($)
{	my $Subcategory = shift;
	my $Eeprom = "";

	# Taken from SunOS.pm
	my @EepromList = ReturnArrayExec("$EepromCommand");
	foreach $Line (@EepromList) {
		# it's a single value return, but let the embedded breaks
		# format it onto multiple lines
		$Eeprom = $Eeprom . "$Line<br> ";
	}

	return ( $Eeprom );
}


###########################################################################
# Network
###########################################################################

sub ReturnDomainNameIRIX ($)
{	my $Subcategory = shift;

	return ReturnDomainName($Subcategory, $ResolvConfPath);
}


sub ReturnDefaultRouterIRIX ($)
{	my $Subcategory = shift;

	$DefaultRouter = "UNKNOWN";

	my @routes = ReturnArrayExec("$NetstatCommand $NetstatRouteArgs");
	my @defrouters = grep /^(default|0.0.0.0)/, @routes;

# This needs to be checked out. Probably need to be smarter with more than one
# default router.

	if ( @defrouters ) {
		$DefaultRouter = (split(" ", $defrouters[0]))[1];
	}
	$DefaultRouter = IPtoFQDN($DefaultRouter);

	return ( $DefaultRouter );
}


sub ReturnNameServerIRIX ($)
{	my $Subcategory = shift;
	my @Response = ( );

	my @ResolvConfText = ReturnArrayFile($ResolvConfPath);
	if ( scalar(@ResolvConfText) < 1 ) {
		push @Response, "None";
	}
	else {
		foreach $Line (@ResolvConfText) {
			# find the first line with "nameserver" in it?
			if ( $Line =~ /^nameserver\s+(\d+\.\d+\.\d+\.\d+)/ ) {
				my $NameServerIP = $1;
				# do we recognize this nameserver?
				my $NameServerFQDN = IPtoFQDN($NameServerIP);
				push @Response, $NameServerFQDN;
				next;
			}
		}
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


sub ReturnIPAddressIRIX ($)
{
	# Returns the IP address associated with "$main::nodename"
	# The "default" IP address. This subroutine will be used
	# if Bruce decides to implement this function in syssumm.pl

	my @Addresses = (gethostbyname $main::NodeName)[4];
	my ($a, $b, $c, $d) = unpack('C4', $Addresses[0]);
	$IPAddress = "$a." . "$b." . "$c." . "$d" ;

	return ( $IPAddress );
}


sub ReturnSubnetMaskIRIX ($)
{	my $SubnetMask = "";
	my $IPAddress = ReturnIPAddressIRIX(@_);
	my @Interfaces = ReturnNetworkInterfacesIRIX(@_);

	# Returns netmask associated with the "default" IP address
	# This subroutine will be used if Bruce decides to implement
	# this function in syssumm.pl

	# find interface corresponding to "default" IP
	# and get netmask from it
	foreach $Line (@Interfaces) {
		next unless ( $Line =~ /$IPAddress/ );
		if ( $Line =~ /netmask=(\d+\.\d+\.\d+\.\d+)/ ) {
			$SubnetMask = $1;
		}
	}

	return ($SubnetMask);
}


sub ReturnNetworkInterfacesIRIX ($)
{	my $Subcategory = shift;
	my %Interfaces;
	my $Interface;
	my @Response = ( );
	my @Hinv;

	#
	# We need to get the interfaces from hinv and ifconfig now...
	# This is based on the SunOS.pm module
	#

	if ( -x $HinvCommand ) {
		my @Hinv = ReturnArrayExec("$HinvCommand $HinvArgs");

		foreach $Line ( @Hinv ) {
			if ( $Line =~ /(Ethernet|FDDI)( controller)?:\s+(\w+\d+)\b/i ) {
				print "\tLine is $Line...\n" if $main::Debug;
				$Interfaces{$3}{Iface} = $3 unless defined $Interfaces{$3}{Iface};
				$Interfaces{$3}{Type} = $1 unless defined $Interfaces{$3}{Type};
			}
		}
	}
 
	if ( -x $IfconfigCommand ) {
		my @Ifconfig = ReturnArrayExec("$IfconfigCommand -a");
 
		foreach $Line (@Ifconfig) {
			next unless ( $Line =~ /^((\w+)\d+(:\d+)?)/ ) and defined($IfList{$2});

			my $FoundInterface = $1;
			my $FoundIfName = $2;

			if ( $IfList{$FoundIfName} =~ /ATM/ ) {
				$Interfaces{$FoundInterface}{Name} = $FoundInterface unless defined $Interfaces{$FoundInterface}{Name};
				$Interfaces{$FoundInterface}{Type} = "ATM" unless defined $Interfaces{$FoundInterface}{Type};
			} else {
				$Interfaces{$FoundInterface}{Name} = $FoundInterface 
					unless defined $Interfaces{$FoundInterface}{Name};
				$Interfaces{$FoundInterface}{Type} = "Ethernet"
  					unless defined $Interfaces{$FoundInterface}{Type};
			}
		}
	}

	foreach $Interface ( keys %Interfaces ) {
		my $Response = AddNetInfo($Interfaces{$Interface}{Name}, $Interfaces{$Interface}{Type});
		push @Response, $Response if ($Response);
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


sub AddNetInfo ($$)
{	my $NetworkInterfaceName = shift;
	my $NICType = shift;

	print "AddNetInfo($NetworkInterfaceName, $NICType)...\n" if $main::Debug;

	# use ifconfig to get the rest of the information
	my @IfconfigText = ReturnArrayExec("$IfconfigCommand $NetworkInterfaceName");
	# use netstat to get the MAC info.
	my @NetstatText = ReturnArrayExec("$NetstatCommand $NetstatMacArgs $NetworkInterfaceName");

	my $NICDevice = $NetworkInterfaceName;
	$NICDevice =~ s/\d+$//;
	$NICDevice = $IfList{$NICDevice} if defined($IfList{$NICDevice});

	# Get MAC address

	my $MACAddress = "";
	foreach $Line (@NetstatText) {
		if ($Line =~ /\b(\w+:\w+:\w+:\w+:\w+:\w+)\b/) {
			$MACAddress = $1;
			last;
		}
	}
	$MACAddress =~ s/\b(\d)\b/0$1/g;

	# assume that there could be multiple fields on each line...

	my $IPAddress = "";
	my $BroadcastMask = "";
	my $NetMask = "";

	foreach $Line (@IfconfigText) {
		if ( $Line =~ /flags=/ ) {
			return("$NetworkInterfaceName " .
				"type=$NICType device=\"$NICDevice\" " .
				"macaddr=$MACAddress UNCONFIGURED")
					unless $Line =~ /UP/;
		}
		# grab the IP address
		if ( $Line =~ /inet\s+(\d+\.\d+\.\d+\.\d+)/ ) {
			$IPAddress = $1;
		}
		# grab the broadcast mask
		if ( $Line =~ /broadcast\s+(\d+\.\d+\.\d+\.\d+)/ ) {
			$BroadcastMask = $1;
		}
		# grab the netmask
		if ( $Line =~ /netmask\s+(0x)?([a-f0-9]{8})/ ) {
		  my $netmask = $2;
		  $NetMask = "";
		  for ($i = 0; $i < 8; $i = $i + 2) {
		    $NetMask = $NetMask . hex(substr($netmask,$i,2));
		    if ($i < 6) { $NetMask = "$NetMask."; }
		  }
		}
	}

	my $NICDescription = 
		"$NetworkInterfaceName " .
		"type=$NICType device=\"$NICDevice\" " .
		"macaddr=$MACAddress " .
		"ip=$IPAddress netmask=$NetMask broadcast=$BroadcastMask";

	return $NICDescription;
}


###########################################################################
# Software
###########################################################################

# 
# We're using alot of the same tests for existance
# that are used by the /etc/rc.d/init.d scripts
# 

sub ReturnOsNameIRIX ($)
{	my $Subcategory = shift;

	# This might be IRIX or IRIX64
	my $OSSystem = `$UnameCommand -s`;
	chomp($OSSystem);

	return ( $OSSystem );
}


sub ReturnOsVersionIRIX ($)
{	my $Subcategory = shift;

	return ( "$OSVersion" );
}


sub ReturnPatchesIRIX ($)
{	my $Subcategory = shift;
	my %Patches;
	my @Response = ( );

	my @Patchlist = ReturnArrayExec("$VersionsCommand $VersionsArgs");

	foreach $Line (@Patchlist) {
		$Line =~ /^I\s+patchSG\d+\s+\S+\s+(.*)$/ && push @Response, $1;
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


sub ReturnRunningLpschedIRIX ($)
{	my $Subcategory = shift;
	my @Responses = ( );

	my $Response = ReturnRunningSysvLp($Subcategory, $PsCommand, $PsArgs);
	push @Responses, $Response if $Response =~ /Yes/;
	$Response = ReturnRunningBSDLpr($Subcategory, $PsCommand, $PsArgs);
	push @Responses, $Response if $Response =~ /Yes/;
	$Response = ReturnRunningLPRng($Subcategory);
	push @Responses, $Response if $Response =~ /Yes/;

	# concatenate the final responses as necessary
	my $FinalResponse = "";
	foreach $Response (@Responses) {
		if ( $FinalResponse eq "" ) {
			$FinalResponse = $Response;
		}
		else {
			$FinalResponse = "$FinalResponse, $Response";
		}
	}

	return ($FinalResponse);
}


sub ReturnPrintersIRIX ($)
{	my $Subcategory = shift;
	my @Response = ( );

	# Note: it is most likely that only one or the other package
	# is installed, but we don't really know which.
	# Look through AT&T printers first
	my $LocalPrinters = SearchFileForPattern("$LpstatCommand $LpstatArgs", "^printer", 1);
	@Response = split(/ /, $LocalPrinters) if $LocalPrinters ne $NotFound;

	# Now look through BSD printers
	my @LocalPrinters = ReturnArrayExec("$LpcCommand $LpcArgs");
	foreach $Line (@LocalPrinters) {
		if ( $Line =~ /(\w+):/ ) {
			push @Response, $1;
		}
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


# 
# Note that this subroutine has a side-effect of setting
# a global variable in main:: called EmailAvailable if
# sendmail is running...
# 

sub ReturnRunningSendmailIRIX ($)
{	my $Subcategory = shift;

	my $Sendmail = ( ( -f "$SendmailCommand" ) ? "Yes" : "No" );

	# if sendmail is available, check to see if it is running, or
        # runnable vi /etc/inetd.conf...

	my @RunningProcs = ReturnArrayExec("$PsCommand $PsArgs");
	my @InetdConf = ReturnArrayFile("$InetdConfPath");

	if ($Sendmail eq "Yes") {
		if (!(grep {m,$SendmailCommand,} @RunningProcs) &&
			!(grep {m,$SendmailCommand,} @InetdConf)) {
				$Sendmail = "No";
		}
	}

	# what version of sendmail are we running?
	if ( ( $Sendmail eq 'Yes' ) and ( -r $SendmailConfPath ) ) {
		@SendmailConfig = ReturnArrayFile("$SendmailConfPath");
		foreach $Line (@SendmailConfig) {
			# IRIX needs alphanumeric rather than numeric
			# per Frank Crawford's example
			if ( $Line =~ /^DZ(\w+\.\w+\.\w+)/ ) {
				$Sendmail .= " (version $1)";
				last;
			}
		}
	}

	# side-effect
	$main::EmailAvailable = ( $Sendmail eq "Yes" );

	return ( $Sendmail );
}


sub ReturnRunningNFSIRIX ($)
{	my $Subcategory = shift;

	my $NFSState = "";
	my $NFSServer = "";
	if ( -f $NfsdCommand and -f $ExportsPath ) {
		my @Exports = ReturnArrayFile("$ExportsPath");
		$NFSServer = grep(m:^/:, @Exports);
	}
	print "\tNFSServer is $NFSServer\n" if $main::Debug;
	my $NFSClient = ( -f $MountdCommand );
	print "\tNFSClient is $NFSClient\n" if $main::Debug;
	if ( $NFSServer and $NFSClient) {
		$NFSState = "Yes, both server and client";
	}
	elsif ( $NFSServer ) {
		$NFSState = "Yes, server only";
	}
	elsif ( $NFSClient ) {
		$NFSState = "Yes, client only";
	}
	else {
		$NFSState = "No";
	}

	return ( $NFSState );
}


sub ReturnRunningAutomountIRIX ($)
{	my $Subcategory = shift;
	
	my $Automount = ( ( -f "$AutomountCommand" ) ? "Yes" : "No" );
	my @RunningProcs = ReturnArrayExec("$PsCommand $PsArgs");

	$Automount = ( $Automount eq "Yes"
		&& ( grep {m,$AutomountPattern,} @RunningProcs))
			? "Yes" : "No";

	return ( $Automount );
}


sub ReturnRunningNISIRIX ($)
{	my $Subcategory = shift;
	my $NISState = "";
	my $NISServer = "";
	my $NISClient = "";

	my @RunningProcs = ReturnArrayExec("$PsCommand $PsArgs");

	my $NSDaemon = SearchFileForPattern("$ChkconfigCommand $ChkconfigArgs", "nsd", 1);

	if ($NSDaemon eq "on") {
		# Running the nsd daemon - probably IRIX 6.5 or later
		my @NsSwitch = ReturnArrayFile("$NsSwitchConfPath");

		if (grep {m,$NsdCommand,} @RunningProcs) {
			$NISClient = (SearchFileForPattern("$ChkconfigCommand $ChkconfigArgs", 
				'yp\b', 1) eq "on") && 
				grep(/^[^#]+\snis[^s]/, @NsSwitch);

			$NISServer = (SearchFileForPattern("$ChkconfigCommand $ChkconfigArgs", 
				"ypserv", 1) eq "on") && 
				glob($NISServConfPath);
		}
	} else {
		# No nsd (or nsd off) - probably IRIX 6.2 or earlier
		$NISServer = ( -f $NISServerCommand ) && 
			grep {m,$NISServerCommand,} @RunningProcs;
		$NISClient = ( -f $NISClientCommand ) && 
			grep {m,$NISClientCommand,} @RunningProcs;
	}

	if ( $NISServer and $NISClient ) {
		$NISState = "Yes, NIS (YP), server and client";
	} elsif ( $NISServer ) {
		$NISState = "Yes, NIS (YP), server only";
	} elsif ( $NISClient ) {
		$NISState = "Yes, NIS (YP), client only";
	} else {
		$NISState = "No";
	}

	# XXX add NIS domainname to $NisState if NIS is running...

	return ( $NISState );
}


sub ReturnRunningNameserverIRIX ($)
{	my $Subcategory = shift;

	my @RunningProcs = ReturnArrayExec("$PsCommand $PsArgs");

	my $Nameserver = (grep {m,$NameServerPattern,} @RunningProcs)
		? "Yes" : "No";

	return ( $Nameserver );
}


sub ReturnIPAddressResolutionIRIX ($)
{	my $Subcategory = shift;
	my $IPAddressResolution = "Unknown";

	if ( -f $ResolvConfPath ) {
		$IPAddressResolution = "DNS";
	}
	else {
		$IPAddressResolution = "/etc/hosts";
	}

	return ( $IPAddressResolution );
}


sub ReturnRunningSambaIRIX ($)
{      my $Subcategory = shift;

	return ReturnRunningSamba($Subcategory, $PsCommand, $PsArgs, $InetdConfPath);
}


sub ReturnGraphicalUserInterfaceIRIX ($)
{	my $Subcategory = shift;

	# XXX Let's defer this for now

	return ( "X11R6" );
}


sub ReturnFontServerIRIX ($)
{	my $Subcategory = shift;

	my $FontServer = SearchFileForPattern("$ChkconfigCommand $ChkconfigArgs", "fontserver", 1);

	$FontServer = ($FontServer eq "on") ? "Yes" : "No";

	return ( $FontServer );
}


sub ReturnLocalFileSystemsIRIX ($)
{	my $Subcategory = shift;
	my @Response = ( );

	my @DfText = ReturnArrayExec("$DfCommand $LocalFileSystems");
	my $PreviousLine = "";
	foreach $Line (@DfText) {
		# bypass the header line
		next if $Line =~ /^Filesystem/;
		# partial line?
		if ( $PreviousLine ) {
			$Line = $PreviousLine . $Line;
			$PreviousLine = "";
		}
		# clean and split line
		$Line =~ s/[\s]+/ /g;
		my @DfFields = split(/ /, $Line);
		# partial line?
		if ( scalar(@DfFields) < 2 ) {
			$PreviousLine = $Line;
			next;
		}
		# bypass any cdrom drives or remote file systems
		next if $Line =~ /cdrom/i;
		next if $Line =~ /^[\w]/;
		# calc size in MB
		my $Size = sprintf("%.1fMB", ( $DfFields[2] / 1024 ) );
		$DfFields[5] .= '%' unless $DfFields[5] =~ /%$/;
		push @Response, "$DfFields[6] mount=$DfFields[0] size=$Size sat=$DfFields[5]";
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


sub ReturnRemoteFileSystemsIRIX ($)
{      my $Subcategory = shift;
	my @Response = ( );
	my @Filesystems = ( );

	#
	# I really don't want to see automounted NFS file systems. What gets
	# found depends on when this is run. So, read fstab file, the run df
	# on the nfs file systems found there.
	#

	my @FstabText = grep /^[^#]+\snfs\d?\s/, ReturnArrayFile("$EtcFstabPath");

	foreach $Line (@FstabText) {
		push @Filesystems, (split " ", $Line)[1];
	}

	# If nothing there, then skip.
	if ( @Filesystems ) {

		my $dfComm = "$DfCommand $NFSFileSystems " . join " ", @Filesystems;

		my @DfText = `$dfComm`;
		my $PreviousLine = "";
		foreach $Line (@DfText) {
			# bypass the header line
			next if $Line =~ /^Filesystem/;
			# partial line?
			if ( $PreviousLine ) {
				$Line = $PreviousLine . $Line;
				$PreviousLine = "";
			}
			# clean and split line
			$Line =~ s/[\s]+/ /g;
			my @DfFields = split(/ /, $Line);
			# partial line?
			if ( scalar(@DfFields) < 2 ) {
				$PreviousLine = $Line;
				next;
			}
			# bypass any cdrom drives or remote file systems
			next if $Line =~ /cdrom/i;
			next if $Line =~ /^\//;
			print "\t$Line\n" if $main::Debug;
			# calc size in MB
			my $Size = sprintf("%.1fMB", ( $DfFields[2] / 1024 ) );
			my ( $RemoteSystem, $RemoteFileSystem ) = split(':', $DfFields[0]);
			$DfFields[5] .= '%' unless $DfFields[5] =~ /%$/;
			push @Response, "$DfFields[6] remote=$RemoteSystem mount=$RemoteFileSystem size=$Size sat=$DfFields[5]";
		}
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


sub ReturnExportedFileSystemsIRIX ($)
{	my $Subcategory = shift;
	my @Response = ( );

	# XXX - this is a stub routine to be filled in later...

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


sub ReturnSwapIRIX ($)
{	my $Subcategory = shift;

	ReturnSwap($Subcategory, "$SwapCommand");
}


sub ReturnRunningAccountingIRIX ($)
{	my $Subcategory = shift;

	my $Accounting = SearchFileForPattern("$ChkconfigCommand $ChkconfigArgs", "acct", 1);

	$Accounting = ($Accounting eq "on") ? "Yes" : "No";

	return ( $Accounting );
}


###########################################################################
# End of IRIX.pm
###########################################################################

1;
