package OSF1;

# OSF1.pm - these are operating system specific routines for OSF1
#
# 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...
# 
# Note that there are 2 additional files that go with the OSF1.pm
# module: machmodel.c and machmodel.  The first file is a C source
# file and the second is a pre-compiled binary.  The purpose of the
# program is to return the model of the DEC (Compaq) machine.  Here
# are Wander's comments:
# 
#	That's right, I sent the machmodel.c and the binary to be 
#	integrated into remote files, unless someone have a better 
#	idea. If the OS Version is >= 4.0, the binary file should work.
# 
#	The little C program that I sent called machmodel.c, is the 
#	only way to get the "real" machine model.  This program and 
#	all other stuff for OSF1 works for all Digital Unix V4.0 and 
#	after, i.e., V4.0, V4.0A, V4.0B, V4.0D and V4.0E. I didn't 
#	test with V4.0F, because I don't have it here.
# 
# Another good resource for determining the configuration of a
# DEC UNIX system is a Korn shell script called sys_check which
# should be located in /usr/sbin.  Digital provided this.
# 
# ==============================================================
# 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 Wanderley O. Mendes <wander@cptec.inpe.br>
#       Based upon code by Bruce W. Mohler
# 
# Contributed source:
#	Copyright (c) 1999, 2000 Bill Benedetto
#	Copyright (c) 2000 Frank Crawford
#	Copyright (c) 1999, 2000 Alek O. Komarnitsky
#	Copyright (c) 1999, 2000 Bruce W. Mohler
# 
# ==============================================================
# 
# $Header: /export/home/mohlerb/syssumm/remote/RCS/OSF1.pm,v 1.24 2000/05/08 21:52:58 mohlerb Exp mohlerb $
# 
# $Revision: 1.24 $
#
# $Log: OSF1.pm,v $
# Revision 1.24  2000/05/08 21:52:58  mohlerb
# changes from Bruce Mohler including:
# I had to modify this routine for one more Compaq
# Tru64 anomaly where they use fixed columns in the
# output of netstat.  If the FQDN of the default
# router is too long, it just gets truncated which
# tended to break FQDNtoIP
#
# Revision 1.23  2000/05/04 17:13:50  mohlerb
# changes from Bruce Mohler including:
# changed ReturnEepromOSF1 to return "Unknown" rather than "";
# changed ReturnHostId to add tag "(not set)" if the value of
# the hostid output is 0
#
# Revision 1.22  2000/05/04 17:05:56  mohlerb
# changes from Bruce Mohler including:
# filled in guts of ReturnSwapOSF1 function; output including
# total swap space, percent in-use, and list of swap partitions
#
# Revision 1.21  2000/05/03 23:09:28  mohlerb
# changes from Bruce Mohler including:
# fixed ReturnDefaultRouterOSF1 so that it returns the
# default router IP address properly
#
# Revision 1.20  2000/05/03 22:56:55  mohlerb
# changes from Bruce Mohler including:
# rewrote ReturnNetworkInterfacesOSF1 to conform more to the
# "standard" format used by the SunOS and HPUX modules
#
# Revision 1.19  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.18  2000/02/24 21:37:40  mohlerb
# changes from Wanderley O. Mendes including:
# Fixes to ReturnProcessorsOSF1 and ReturnMemoryOSF1
#
# Revision 1.17  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.16  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.15  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.14  2000/01/12 17:59:22  mohlerb
# changes from Frank Crawford including:
# fix to ReturnNameServer to pattern used parsing /etc/resolv.conf
#
# Revision 1.13  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.12  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.11  2000/01/03 19:35:42  mohlerb
# changes from Bill Benedetto including:
# fixed typo in function ReturnRunningSendmailOSF1 s/YES/Yes/
#
# Revision 1.10  1999/11/03 19:23:32  mohlerb
# changes from Bruce Mohler including:
# fixed typo in RunningLpsched function: s/BSDLp/BSDLpr/
#
# Revision 1.9  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.8  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.7  1999/10/27 20:03:38  mohlerb
# changes from Alek O. Komarnitsky including:
# added ReturnFstab() to common.pm and stubs as appropriate
#
# Revision 1.6  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.5  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.4  1999/10/01 19:50:35  mohlerb
# changes from Wanderley O. Mendes including:
# fixed syntax error in foreach statement on line 630
#
# Revision 1.3  1999/10/01 19:00:53  mohlerb
# changes from Bruce Mohler including:
# fixed the following functions: ReturnSubnetMaskOSF1,
# ReturnDefaultRouterOSF1, ReturnRunningSendmailOSF1,
# ReturnLocalFileSystemsOSF1
#
# Revision 1.2  1999/09/30 21:48:10  mohlerb
# changes from Bruce Mohler including:
# fixed function which determines number, type, and speed
# of processors (OSF1_procspd.pl and OSF1_proctyp.pl);
# aesthetic fix to function reporting on available memory;
# fixed StorageManager function to also support LSM;
# aesthetic fix to function which reports name servers;
# fixed function reporting whether lpsched is reporting to
# reflect DEC UNIX's use of BSD-style printing
#
# Revision 1.1  1999/08/30 14:56:13  mohlerb
# Initial revision
#

use common;

require Exporter;
@ISA = qw(Exporter);
###########################################################################
# the following sub-routines (&) are variables ($) will be 
# visible in a program using this module...
@EXPORT = qw(
	&InitializeOSF1
);
# 
# 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 InitializeOSF1()
$OSVersion = "";
$OSVersionMajor = "";
$OSVersionMinor = "";

# where commands are located			standard args
# CUSTOMIZE
$AwkCommand = "/usr/bin/awk";
$DfCommand = "/usr/bin/df";			$LocalFileSystems = "-t ufs,advfs";
						$NFSFileSystems = "-t nfs";
$FileCommand = "/usr/bin/file";
$GrepCommand = "/usr/bin/grep";
$HostIdCommand = "/usr/sbin/hostid";
$IfconfigCommand = "/usr/sbin/ifconfig";
$IoscanCommand = "/sbin/scu";                   $IoscanArgs = "show edt lun 0";
$LanscanCommand = "/usr/sbin/ifconfig";		$LanscanArgs = "-a";
$LmfCommand = "/usr/sbin/lmf";
$LpdCommand = "/usr/lbin/lpd";
$MemCommand = "./OSF1_physmem";
$NetstatCommand = "/usr/sbin/netstat";
$PlatformCommand = "./machmodel";
$ProcspdCommand = "./OSF1_procspd.pl";
$PsCommand = "/usr/bin/ps";			$PsArgs = "-aef";
$PsrinfoCommand = "/usr/sbin/psrinfo";
$PvcreateCommand = "/usr/sbin/pvcreate";
$SendmailCommand = "/usr/sbin/sendmail";
$SizerCommand = "/usr/sbin/sizer";
$StringsCommand = "/usr/ccs/bin/strings";
$SwapCommand = "/sbin/swapon";			$SwapArgs = "-s";
$SwlistCommand = "/usr/sbin/setld";
$TailCommand = "/usr/bin/tail";
$UnameCommand = "/usr/bin/uname";
$VoldCommand = "/sbin/vold";

# needs to follow $TailCommand...
$DiskinfoCommand = "/sbin/scu";		$DiskinfoArgs = "show dev | $TailCommand -4";

# where files are located
# CUSTOMIZE
$AccountingTag = "ACCOUNTING";
$AutomountTag = "AUTOMOUNT";
$BindConfTag = "BIND_CONF";
$BindTypeTag = "BIND_SERVERTYPE";
$BinLogPath = "/var/adm/binary.errlog";
$ConfPath = "/etc/rc.config";
$DefaultRouterTag = "ROUTED";
$FontServerTag = "";
$GUITag = "XLOGIN";
$IfconfigTag = "IFCONFIG_0";
$IPAddressTag = "IFCONFIG_0";
$LoopbackTag = "LOOPBACK_ADDRESS";
$NFSServerTag = "NFSSERVING";
$NFSClientTag = "NUM_NFSIOD";
$NisConfTag = "NIS_CONF";
$NisTypeTag = "NIS_TYPE";
$PrintcapPath = "/etc/printcap";
$ResolvConfPath = "/etc/resolv.conf";
$SendmailConfPath = '/usr/var/adm/sendmail/sendmail.cf';
$SubnetMaskTag = "IFCONFIG_";
$SyslogConfPath = "/etc/syslog.conf";

$SyslogPath = "";
$SubroutineSuffix = "";

# device path patterns - filled in by InitializeOSF1()
$DiskNamePattern = "/dev/rrz%c";
$TapeNamePattern = "/dev/nrmt%h";

# comments
$RunAsRoot = 0;


###########################################################################
# 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 InitializeOSF1 ()
{
	print "InitializeOSF1()...\n" if $main::Debug;

	# initialize $SubroutineSuffix...
	WhatVersionOfOSF1();

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

	$SyslogPath = LocateTheSyslogPath($SyslogConfPath);
	print "\tSyslogPath is $SyslogPath\n" if $main::Debug;

	# plug in appropriate subroutines
	$main::Routines{General}{NodeName} = \&ReturnNodeNameOSF1;
	$main::Routines{General}{Vendor} = \&ReturnVendorOSF1;
	$main::Routines{General}{Model} = \&ReturnModelOSF1;
	$main::Routines{General}{HostId} = \&ReturnHostIdOSF1;

	$main::Routines{Hardware}{Processors} = \&ReturnProcessorsOSF1;
	$main::Routines{Hardware}{Memory} = \&ReturnMemoryOSF1;
	$main::Routines{Hardware}{Disks} = \&ReturnDisksOSF1;
 	$main::Routines{Hardware}{Tapes} = \&ReturnTapesOSF1;
 	$main::Routines{Hardware}{StorageManager} = \&ReturnStorageManagerOSF1;
 	$main::Routines{Hardware}{Eeprom} = \&ReturnEepromOSF1;

 	$main::Routines{Network}{DomainName} = \&ReturnDomainName;
 	$main::Routines{Network}{DefaultRouter} = \&ReturnDefaultRouterOSF1;
 	$main::Routines{Network}{NameServer} = \&ReturnNameServerOSF1;
        $main::Routines{Network}{IPAddress} = \&ReturnIPAddressOSF1;
        $main::Routines{Network}{SubnetMask} = \&ReturnSubnetMaskOSF1;
 	$main::Routines{Network}{NetworkInterfaces} = \&ReturnNetworkInterfacesOSF1;

 	$main::Routines{Software}{OsName} = \&ReturnOsNameOSF1;
 	$main::Routines{Software}{OsVersion} = \&ReturnOsVersionOSF1;
 	$main::Routines{Software}{NbrOfLicenses} = \&ReturnNbrOfLicensesOSF1;
 	$main::Routines{Software}{Patches} = \&ReturnPatchesOSF1;
 	$main::Routines{Software}{Printers} = \&ReturnPrintersOSF1;
 	$main::Routines{Software}{Services} = \&ReturnServices;
 	$main::Routines{Software}{IPAddressResolution} = \&ReturnIPAddressResolutionOSF1;
 	$main::Routines{Software}{GraphicalUserInterface} = \&ReturnGraphicalUserInterfaceOSF1;
 	$main::Routines{Software}{FontServer} = \&ReturnFontServerOSF1;
	$main::Routines{Software}{Fstab} = \&ReturnFstab;
 	$main::Routines{Software}{LocalFileSystems} = \&ReturnLocalFileSystemsOSF1;
 	$main::Routines{Software}{RemoteFileSystems} = \&ReturnRemoteFileSystemsOSF1;
 	$main::Routines{Software}{ExportedFileSystems} = \&ReturnExportedFileSystemsOSF1;
	$main::Routines{Software}{Swap} = \&ReturnSwapOSF1;

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

	RemoveLocalExclusions();

	return;
}


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


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

	$OSVersion = `$SizerCommand -v`;
	$OSVersion = (split(" ",$OSVersion))[2];
	chomp($OSVersion);
	print "\tRunning version $OSVersion...\n" if $main::Debug;
	( $OSVersionMajor, $OSVersionMinor ) = split(/\./, $OSVersion);
	print "\tMajor OS version is $OSVersionMajor...\n" if $main::Debug;
	print "\tMinor OS version is $OSVersionMinor...\n" if $main::Debug;

	$SubroutineSuffix = $OSVersionMajor;

	return;
}


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

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

	my $NodeName = `$UnameCommand -n`;
	chomp($NodeName);

	# trim off FQDN if returned by uname
	my @NodeNameFields = split(/\./, $NodeName);
	if ( $NodeNameFields[0] ) {
		$NodeName = $NodeNameFields[0];
	}

	return ( $NodeName );
}


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

	# CUSTOMIZE
	return ( "Digital" );
}


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

        my $Model = qx{"$PlatformCommand"};
        $Model = (split('= ',$Model))[1];

	chomp($Model);

	return ( $Model );
}


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

	my $IdNbr = `$HostIdCommand`;
	chomp($IdNbr);

	print "IdNbr is \"$IdNbr\"...\n" if $main::Debug;

	if ( $IdNbr == 0 ) {
		$IdNbr .= " (not set)";
	}

	return ( $IdNbr );
}


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

sub ReturnProcessorsOSF1 ($)
{	my $Subcategory = shift;
	my @Processors = ( );

	# what kind of processor is being used?
	# my $ProcessorType = `$ProctypCommand`;
	my $ProcessorType = `$SizerCommand -implver`;
	chomp($ProcessorType);
	print "\tProcessorType is $ProcessorType\n" if $main::Debug;

	# how many?
	my $NbrOfProcessors = `$SizerCommand -p`; 
	print "\tNbrOfProcessors is $NbrOfProcessors\n" if $main::Debug;

	# how fast?
	my $ProcessorSpeed = `$ProcspdCommand`;
	chomp($ProcessorSpeed);
	$ProcessorSpeed .= "MHz";
	print "\tProcessor speed is $ProcessorSpeed\n" if $main::Debug;

	# iterate over the processors
	foreach $Processor ( 0..($NbrOfProcessors - 1) ) {
		push @Processors, "processor $Processor $ProcessorType $ProcessorSpeed";
	}
	print "\tProcessors is @Processors\n" if $main::Debug;

	my @Response = ForceMultipleResponses(\@Processors);

	return @Response;
}


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

	my $Memory = `$MemCommand`;
	$Memory = (split('= ',$Memory))[1]/8192/1024;
	$Memory = int($Memory + .5 );
	# append units
	$Memory = "$Memory" . " MB";
	chomp($Memory);

	#
	# From Wander:
	#
	# Another way to find out the memory size is through the
	# command "dbx -k /vmunix" and then "print physmem".  If
	# you divide the result by 1024 then by 1024 again, you
	# get the memory size in MB.
	# 

	return ( $Memory );
}


sub ReturnDisksOSF1 ($)
{	my $Subcategory = shift;
	my @Controllers = ( );
	my $ControllerNbr = -1;
	my $CurrentController = -1;
	my @Response = ( );
	my $DeviceNbr = -1;

	my @SyslogText = `$FileCommand /dev/rrz*c`;
	foreach $Line ( @SyslogText ) {

		if ( $Line =~ /SCSI/ ) {
			# map regexp variables to something more mnemonic
			my $Controller = (split(' ',$Line))[5];
			$Controller =~ s/^#//; 
			my $Address = (split(' ',$Line))[11];
			$Address =~ s/^#//;
			$Address =~ s/\)//;
			my $DeviceType = (split(' ',$Line))[6];
			$DeviceNbr = $Controller * 8 + $Address;

			my $Response = AddDeviceinfo("/dev/rrz$DeviceNbr" . "c");
			push @Response, $Response if ( $Response);
		}
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


sub ReturnTapesOSF1 ($)
{	my $Subcategory = shift;
	my @Controllers = ( );
	my $ControllerNbr = -1;
	my $CurrentController = -1;
	my @Response = ( );
	my $DeviceNbr = -1;	

	my @SyslogText = `$FileCommand /dev/nrmt*h`;
	foreach $Line ( @SyslogText ) {

                if ( $Line =~ /SCSI/ ) {
                        # map regexp variables to something more mnemonic
                        my $Controller = (split(' ',$Line))[5];
                        $Controller =~ s/^#//;
                        my $Address = (split(' ',$Line))[11];
                        $Address =~ s/^#//;
                        $Address =~ s/\)//;
                        my $DeviceType = (split(' ',$Line))[6];
			my $DeviceNbr = (split(':',$Line))[0];			

                        my $Response = AddDeviceinfo("$DeviceNbr");
                        push @Response, $Response if ( $Response);
                }
        }

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


# 
# Build the device name, then feed it to the diskinfo
# command to retrieve the vendor and model of the device
# 

sub AddDeviceinfo ($)
{	my $DeviceName = shift;
	my $ValidDevice = 0;

	print "AddDeviceinfo($DeviceName)...\n" if $main::Debug;

	# what does diskinfo say about the device?
	open DISKINFO, "$DiskinfoCommand -f $DeviceName $DiskinfoArgs 2>&1 |" or
		die "Can't read output from diskinfo: $!";
	my @DiskinfoText = <DISKINFO>;
	close(DISKINFO);
	chomp(@DiskinfoText);

	my $Vendor = "";
	my $Model = "";
	my $Firmware = "";
	foreach $Line ( @DiskinfoText ) {
		my $Tag = "";

		if ( $Line =~ /Permission denied/ ) {
			$RunAsRoot = 1;
			return "";
		}
		if ( $Line =~ /No such device/ ) {
			return "";
		}
		$ValidDevice = 1;
		if ( $Line =~ /Vendor/ ) {
			( $Tag, $Vendor ) = split(/:/, $Line);
			# strip off any leading/trailing whitespace
			$Vendor =~ s/^[\s]+//g;
			$Vendor =~ s/[\s]+$//g;
			next;
		}
		if ( $Line =~ /Product/ ) {
			( $Tag, $Model ) = split(/:/, $Line);
			# strip off any leading/trailing whitespace
			$Model =~ s/^[\s]+//g;
			$Model =~ s/[\s]+$//g;
			next;
		}
		if ( $Line =~ /Firmware/ ) {
			( $Tag, $Firmware ) = split(/:/, $Line);
			# strip off any leading/trailing whitespace
			$Firmware =~ s/^[\s]+//g;
                        $Firmware =~ s/[\s]+$//g;
			next;
		}		
	}
	print "\tVendor is $Vendor...\n" if $main::Debug;
	print "\tModel is $Model...\n" if $main::Debug;
	print "\tFirmware is $Firmware...\n" if $main::Debug;

	my $Description = "unknown";
	if ( $Vendor and $Model and $Firmware ) {
		$Description = $Vendor . " " . $Model . " " . $Firmware;
	}

	return ( $ValidDevice 
		? "$DeviceName model=\"$Description\"" 
		: "" );
}


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

	if ( -x $VoldCommand ) {
		push @Response, "Logical Storage Manager (LSM))";
	}
	elsif ( -x $PvcreateCommand ) {
		push @Response, "Logical Volume Manager (LVM)";
	}
	else {
		return ( "None" );
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


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

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

	return ( ReturnUnknownField($Subcategory) );
}


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

#
# Even though Compaq Tru64 UNIX 4.X provides the /etc/routes file
# for specifying a default route, you can specify other fixed
# routes in that file as well.  So, rather than parsing, /etc/routes
# we'll just get the information straight from netstat -r.
# 

sub ReturnDefaultRouterOSF1 ($)
{	my $Subcategory = shift;
	my $DefaultRouter = "unknown";

	my @NetstatText = ReturnArrayExec("$NetstatCommand -r");
	foreach $Line (@NetstatText) {
		if ( $Line =~ /^default/ ) {
			$Line =~ /^default\s+([\w\d.-]+)\s+/;
			$DefaultRouter = $1;
			if ( $DefaultRouter =~ /\d+\.\d+\.\d+\.\d+/ ) {
				$DefaultRouter = IPtoFQDN($DefaultRouter);
			}
			else {
				my $IPAddress = FQDNtoIP($DefaultRouter);
				$DefaultRouter = "$DefaultRouter ($IPAddress)";
			}
		}
	}

	return ( $DefaultRouter );
}


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

	my @ResolvConfText = ReturnArrayFile($ResolvConfPath);
	if ( scalar(@ResolvConfText) < 1 ) {
		push @Response, "None";
	}
	else {
		foreach $Line (@ResolvConfText) {
			my $NameServerText = "";
	
			# ignore lines that might be comments
                        next if $Line =~ /^[\s]*#.*/;
			next if $Line =~ /^[\s]*;.*/;

			# find the first line with "nameserver" in it?
			if ( $Line =~ /^nameserver\s+([\d]+\.[\d]+\.[\d]+\.[\d]+)/ ) {
				my $NameServerIP = (split(' ',$Line))[1];
				# do we recognize this nameserver?
				my $NameServerFQDN = IPtoFQDN($NameServerIP);
				push @Response, $NameServerFQDN;
				next;
			}
		}
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


# 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

sub ReturnIPAddressOSF1
{	my $Subcategory = shift;

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

        return ( $IPAddress );
}


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

sub ReturnSubnetMaskOSF1
{	my $Subcategory = shift;
	my $SubnetMask = "";
        my $IPAddress = ReturnIPAddressOSF1();
        my @Interfaces = ReturnNetworkInterfacesOSF1();

        # find interface corresponding to "default" IP
        # and get netmask from it

        my $ched = SearchFileForTagValue($ConfPath, $IfconfigTag);
        if ( $ched eq $NotFound or $ched eq "" ) {
                $ched = "Unknown";
        }
        else {
		$ched = (split(' ',$ched))[2];
        }

        return ($ched);
}


# 
# This function now conforms to the output format of the
# SunOS and HPUX modules except that it's missing the 
# following types of information:
# 
# 	linkspeed
# 	device type
# 

sub ReturnNetworkInterfacesOSF1 ($)
{	my $Subcategory = shift;
	my $Interface = "";
	my @Response = ( );

	# 
	# We're looking for lines like:
	# 
	# 	tu0: flags=c63<UP,BROADCAST,NOTRAILERS,RUNNING,...
	# 	     inet 10.11.25.20 netmask ffff0000 broadcast 10.11.255.255 ...
	# 
	my @IfconfigText = ReturnArrayExec("$IfconfigCommand -a");
	foreach $Line ( @IfconfigText ) {
		# we don't care out local loopback or pointotpoint interfaces
		next if $Line =~ /^#|^lo0|^sl|^ppp/o;

		if ( $Line =~ /^(\w+\w+\d+):/o ) {
			$Interface = $1;
		}
		# if this is the "second" line of ifconfig output...
		elsif ( $Line =~ /inet/ and $Interface ) {
			# ...get the rest of the information from ifconfig
			$Line =~ /inet (\d+.\d+.\d+.\d)/;
			my $IpAddress = $1;
			$Line =~ /netmask ([0-9a-f]{8})/;
			my $Netmask = $1;
			$Line =~ /broadcast (\d+.\d+.\d+.\d)/;
			my $Broadcast = $1;

			# get the MAC address from the netstat command
			my @NetstatText = ReturnArrayExec("$NetstatCommand -I $Interface -irn");
			my $MacAddress = "";
			foreach $Line (@NetstatText) {
				if ( $Line =~ /([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2})/ ) {
					$MacAddress = $1;
					last;
				}
			}

			# now push into the Response array
			my $Response = "$Interface macaddr=$MacAddress ip=$IpAddress netmask=$Netmask broadcast=$Broadcast";
			push @Response, $Response;
		}
		else {
			$Interface = "";
		}
        }

        @Response = ForceMultipleResponses(\@Response);

        return @Response;
}


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

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

	return ( "OSF1" );
}


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

	return ( "$OSVersion" );
}


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

	my $NbrOfLicenses = `$LmfCommand list for OSF-BASE | $TailCommand -1`;
	$NbrOfLicenses = (split(" ", $NbrOfLicenses))[2];
	chomp($NbrOfLicenses);

	return ( $NbrOfLicenses );
}


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

	# what patches are installed?
	open SWLIST, "$SwlistCommand -i | $GrepCommand Patch: | $GrepCommand installed 2>&1 |" or
		die "Can't read output from swlist: $!";
	my @SwlistText = <SWLIST>;
	close(SWLIST);
	chomp(@SwlistText);
	foreach $Line ( @SwlistText ) {
		$Line =~ s/^[\s]*//;		# no leading spaces
		$Line =~ s/[\s]+/ /g;		# single spaces separating fields
		$Line =~ s/[\s]*$//;		# no trailing spaces
		if ( $Line =~ /^OSF/ ) {
			my ( $PatchVersion, $PatchInstalled, $PatchDescription ) =
				split(/ /, $Line, 3);
			$PatchDescription =~ s/^Patch: //; # redundant
			push @Response, "$PatchVersion = \"$PatchDescription\"";
		}
	}
	
	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


sub ReturnRunningLpschedOSF1 ($)
{	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 ReturnPrintersOSF1 ($)
{	my $Subcategory = shift;
	my @Response = ( );

        foreach $Line ( `$LpstatCommand $LpstatArgs` ) {
		my $LocalPrinters = (split(" ",$Line))[3]; 
		push @Response, "$LocalPrinters";
	}

	@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 ReturnRunningSendmailOSF1 ($)
{	my $Subcategory = shift;

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

	# okay, it's on the system.  Is it running?
	if ($Sendmail eq "Yes") {
		my @RunningProcs = ReturnArrayExec("$PsCommand $PsArgs");
		my @SendmailFields = split('/', $SendmailCommand);
		my $SendmailExecutable = $SendmailFields[($#SendmailFields)];
		if (!(grep {m,$SendmailExecutable,} @RunningProcs)) {
			$Sendmail = "No";
		}
	}

	# what version of sendmail are we running?
	if ( ( $Sendmail eq 'Yes' ) and ( -r $SendmailConfPath ) ) {
		@SendmailConfig = ReturnArrayFile("$SendmailConfPath");
		foreach $Line (@SendmailConfig) {
			# again Compaq Tru64 shows itself to be different
			if ( $Line =~ /^DV(\d+\.\d+\.\d+\.\d+)/ ) {
				$Sendmail .= " (version $1)";
				last;
			}
		}
	}

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

	return ( $Sendmail );
}


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

	my $NFSState = "";
	my $NFSServer = SearchFileForTagValue($ConfPath, $NFSServerTag);
	print "\tNFSServer is $NFSServer\n" if $main::Debug;
	my $NFSClient = SearchFileForTagValue($ConfPath, $NFSClientTag);
	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 ReturnRunningAutomountOSF1 ($)
{	my $Subcategory = shift;

	my $Automount = SearchFileForTagValue($ConfPath, $AutomountTag);
	$Automount = ( $Automount ? "Yes" : "No" );

	return ( $Automount );
}


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

	my $NISState = "";
	my $NISconf = SearchFileForTagValue($ConfPath, $NisConfTag);
	my $NIStype = SearchFileForTagValue($ConfPath, $NisTypeTag);
	if ( $NISconf or $NIStype ) {
		$NISconf = 1;
	}
	if ( $NISconf and $NIStype eq "MASTER" ) {
		$NISState = "Yes, both server and client";
	}
	elsif ( $NISconf and $NIStype eq "CLIENT" ) {
		$NISState = "Yes, client only";
	}
	else {
		$NISState = "No";
	}

	return ( $NISState );
}


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

	my $Nameserver = SearchFileForTagValue($ConfPath, $BindConfTag);
	if ( $Nameserver eq $NotFound or $Nameserver eq "" ) {
		$Nameserver = "Unknown";
	}
	else {
		$Nameserver = ( $Nameserver ? "YES" : "NO" );
	}

	return ( $Nameserver );
}


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

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

print "ipaddressresolution = $IPAddressResolution";

	return ( $IPAddressResolution );
}


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

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


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

	my $GUI = SearchFileForTagValue($ConfPath, $GUITag);
	if ( $GUI eq $NotFound or $GUI eq "" ) {
		$GUI = "Unknown";
	}

	return ( $GUI );
}


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

	my $FontServer = SearchFileForTagValue($ConfPath, $FontServerTag);
	if ( $FontServer eq $NotFound or $FontServer eq "" ) {
		$FontServer = "Unknown";
	}
	else {
		$FontServer = ( $FontServer ? "Yes" : "No" );
	}

	return ( $FontServer );
}


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

	my @DfText = ReturnArrayExec("$DfCommand $LocalFileSystems");

	my $PreviousLine = "";
	$Suffix = 0;
	foreach $Line (@DfText) {

		# bypass the header line
		next if $Line =~ /^Filesystem/;
		# bypass any cdrom drives or remote file systems
		next if $Line =~ /cdrom/;

		# 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;
			# go get the rest of it
			next;
		}

		# calc size in MB
		my $Size = sprintf("%.1f", ( $DfFields[1] / 1000 ) );

		push @Response, "$DfFields[5] mount=$DfFields[0] size=$Size sat=$DfFields[4]";
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


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

	my @DfText = ReturnArrayExec("$DfCommand $NFSFileSystems");

	my $PreviousLine = "";
	$Suffix = 0;
	foreach $Line (@DfText) {

		# bypass the header line
		next if $Line =~ /^Filesystem/;
		# bypass any cdrom drives or local file systems
		next if $Line =~ /cdrom/;
		next if $Line =~ /^\//;

		# 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;
			# go get the rest of it
			next;
		}

		# calc size in MB
		my $Size = sprintf("%.1f", ( $DfFields[1] / 1000 ) );

		my ( $RemoteSystem, $RemoteFileSystem ) = split(':', $DfFields[0]);
		push @Response, "$DfFields[5] remote=$RemoteSystem mount=$RemoteFileSystem size=$Size sat=$DfFields[4]";
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


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

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

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


# 
# Note that this ReturnSwap function should actually
# call the ReturnSwap function in common.pm, but like
# so many other things, Compaq Tru64 UNIX chooses to
# follow its own relative path in things...
# 

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

	my $SwapSpace = "";
	my $SwapUsed = "";
	my $SwapPartitions = "";
	my $StartChecking = 0;
	my @SwapText = ReturnArrayExec("$SwapCommand $SwapArgs");
	foreach $Line (@SwapText) {
		last if ( $SwapSpace and $SwapUsed );
		if ( $Line =~ /Total swap allocation/ ) {
			$StartChecking = 1;
		}
		if ( $Line =~ /^Swap partition/ ) {
			$Line =~ /partition ([\w\/]+)[ :]/;
			if ( $SwapPartitions ) {
				$SwapPartitions .= ", $1";
			}
			else {
				$SwapPartitions = $1;
			}
		}
		if ( $StartChecking and $Line =~ /Allocated space/ ) {
			$Line =~ /\((\w+)\)/;
			$SwapSpace = $1;
			next;
		}
		if ( $StartChecking and $Line =~ /In-use space/ ) {
			$Line =~ /\(([ \w]+%)\)/;
			$SwapUsed = $1;
			$SwapUsed =~ s/^[\s]+//;
			next;
		}
	}

	return "$SwapSpace ($SwapUsed used) $SwapPartitions";
}


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

	my $Accounting = SearchFileForTagValue($ConfPath, $AccountingTag);
	if ( $Accounting == $NotFound or $Accounting eq "" ) {
		$Accounting = "Unknown";
	}
	else {
		$Accounting = ( $Accounting ? "Yes" : "No" );
	}

	return ( $Accounting );
}


###########################################################################
# End of OSF1.pm
###########################################################################

1;
