package HPUX;

# HPUX.pm - these are operating system specific routines for HPUX
#
# 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 SAIC (Bruce W. Mohler)
# 
# Contributed source:
#	Copyright (c) 2000 Martin Andrews
#	Copyright (c) 2000 Gustavo Chaves
#	Copyright (c) 1999, 2000 Jeffrey W. Collyer
#	Copyright (c) 1999, 2000 Frank Crawford
#	Copyright (c) 1999, 2000 Paul Farrall
#	Copyright (c) 2000 Jim Holthaus
#	Copyright (c) 1999, 2000 Alek O. Komarnitsky
#	Copyright (c) 1999, 2000 Keong Lim
#	Copyright (c) 2000 Paul Thomson
#	Copyright (c) 1999, 2000 Uwe Willenbacher
# 
# ==============================================================
# 
# $Header: /export/home/mohlerb/syssumm/remote/RCS/HPUX.pm,v 1.55 2000/05/21 22:50:29 mohlerb Exp mohlerb $
# 
# $Revision: 1.55 $
#
# $Log: HPUX.pm,v $
# Revision 1.55  2000/05/21 22:50:29  mohlerb
# changes from Gustavo Chaves including:
# corrected a number of problems where strings were compared
# using integer operators; checked for undefined $SwapCommand
#
# Revision 1.54  2000/05/03 22:25:22  mohlerb
# changes from Bruce Mohler including:
# fixed a problem in AddDiskinfo where 1003MB hard drives
# were being returned with a size of 0GB (a problem between
# a comparison of 1000 and division by 1024)
#
# Revision 1.53  2000/05/03 22:16:26  mohlerb
# changes from Bruce Mohler including:
# fixed problem in ReturnPrintersHPUX where it wasn't returning
# any local printers
#
# Revision 1.52  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.51  2000/03/08 00:03:27  mohlerb
# changes from Bruce Mohler including:
# re-added call to AddDiskinfo10 to ReturnDisksHPUX10 (and 11)
# so that we get disk sizes again
#
# Revision 1.50  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.49  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.48  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.47  2000/01/24 18:26:04  mohlerb
# changes from Paul Thomson including:
# changed ReturnModel function to use "model" command rather than
# uname -m (more information!)
#
# Revision 1.46  2000/01/12 17:59:22  mohlerb
# changes from Frank Crawford including:
# fix to ReturnNameServer to pattern used parsing /etc/resolv.conf
#
# Revision 1.45  2000/01/11 18:03:54  mohlerb
# changes from Jim Holthaus including:
# fixed a subtle bug in AddNetInfo where Perl var $IPAddress was
# sometimes called $IpAddress (note that Bruce changed all references
# in *ALL* OS modules to $IPAddress); also added a default definition
# for $BroadcastMask; fixed problem in ReturnRunningNFSHPUX and
# ReturnRunningAutomountHPUX where -1 return value from
# SearchFileForTagValue was interpreted as server(s) running
# (this was caused by 744 permissions on nfsconf file in
# /etc/rc.config.d (therefore the file was "executed" rather
# than being read in)
#
# Revision 1.44  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.43  2000/01/06 21:57:36  mohlerb
# changes from Jim Holthaus including:
# the ReturnTapesHPUX function wasn't working for HP-UX 11.X because
# the arguments to ioscan were incorrect (they changed between 10.X
# and 11.X); added IoscanArgs for each OS version; split ReturnTapes
# into OS version specific functions; fixed regex pattern for -f
# output; this also occassionned fixing ioscan parsing for the
# number of processors and disks
#
# Revision 1.42  2000/01/06 19:47:25  mohlerb
# changes from Jim Holthaus including:
# support for cip and atm interfaces in ReturnNetworkInterfacesHPUX
# function; (I also added $BroadcastMask to output)
#
# Revision 1.41  2000/01/05 21:11:20  mohlerb
# change from Jim Holthaus including:
# Jim noticed that the new changes to the Memory routines did
# not work for HP-UX 11.X since while HP-UX 10.X returns the
# size of memory in bytes, 11.X returns it in Kbytes.  This
# makes HP-UX 11.X boxes report their physical memory as 0MB.
# Jim supplied Perl code to pull the memory size out of the
# currently running kernel with adb
#
# Revision 1.40  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.39  2000/01/03 19:24:02  mohlerb
# changes from Bruce Mohler including:
# changed determination of processors, memory, disks, tapes,
# and network interfaces to NOT rely on the syslog as this
# file may be filled (and rotated) because of local messages
# or it may be automatically rotated by local scripts and
# unreliable; these changes are from Paul Thomson
#
# Revision 1.38  1999/11/04 01:12:16  mohlerb
# changes from Alek O. Komarnitsky including:
# filled in code for ReturnExportedFileSystemsHPUX function
#
# Revision 1.37  1999/11/04 00:56:55  mohlerb
# changes from Alek O. Komarnitsky including:
# reworked ReturnDisksHPUX10 function per changes made to the
# equivalent function in the SunOS module to not depend on dmesg
# but to iterate across /dev/rdsk/c*t*d* devices and return
# the disk label information; also fixed a problem with the
# "type=" field in the AddDiskinfo function
#
# Revision 1.36  1999/11/03 19:23:32  mohlerb
# changes from Bruce Mohler including:
# fixed typo in RunningLpsched function: s/BSDLp/BSDLpr/
#
# Revision 1.35  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.34  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.33  1999/10/30 02:29:23  mohlerb
# changes from Bruce Mohler including:
# added clockspeed to ReturnProcessors and fixed 2 typos
#
# Revision 1.32  1999/10/27 20:03:38  mohlerb
# changes from Alek O. Komarnitsky including:
# added ReturnFstab() to common.pm and stubs as appropriate
#
# Revision 1.31  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.30  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.29  1999/10/12 18:38:06  mohlerb
# changes from Bruce Mohler including:
# fixed test for FontServer to all look for a running xfs process
# (Paul Thompson pointed this out)
#
# Revision 1.28  1999/09/30 21:45:26  mohlerb
# changes from Bruce Mohler including:
# fixed problem in determining the number of processors where
# we were referencing $IoscanArgs rather than $IoscanArgs10;
# this problem was discovered by PAUL.A.THOMSON@flemings.com
#
# Revision 1.27  1999/09/29 22:08:17  mohlerb
# changes from Uwe Willenbacher including:
# support for multiple StorageManagers; support for
# Veritas storage manager under SunOS
#
# Revision 1.26  1999/08/13 16:27:31  mohlerb
# changes from Paul Farrall including:
# I rewrote ReturnProcessorsHPUX10() to
# Returns multiple responses
# Uses "ioscan -fnC processor" to search for processors
#
# Revision 1.25  1999/08/05 21:33:05  mohlerb
# changes from Bruce Mohler including:
# fed $DefaultRouter to IPtoFQDN before returning
#
# Revision 1.24  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.23  1999/08/03 23:22:45  mohlerb
# changes from Paul Farrell including:
# fix to ReturnDisksHPUX10 for disk controller addresses that
# weren't 2 digit numbers like "10/4/4.3.0"
#
# Revision 1.22  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.21  1999/07/02 16:22:36  mohlerb
# changes from Frank Crawford including:
# Added "MB" to end of disk size field.
#
# Revision 1.20  1999/06/19 00:31:40  mohlerb
# changes from Bruce Mohler including:
# fixed some inconsistencies in arguments to some network functions
#
# Revision 1.19  1999/06/17 17:30:54  mohlerb
# changes from Frank Crawford including:
# Moved ReturnDomainNameSunOS to common.pm.
#
# Revision 1.18  1999/06/15 14:04:42  mohlerb
# changes from Frank Crawford including:
# fix for ReturnRunningSamba function: added $InetdConfPath
#
# Revision 1.17  1999/06/12 02:33:00  mohlerb
# changes from Bruce Mohler including:
# cleaned up AddDiskinfo routine; fixed problem where it was
# returning "unknown" for all devices even as run as root;
# split vendor/model into separate fields
#
# Revision 1.16  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.15  1999/06/11 18:08:02  mohlerb
# changes from Bruce Mohler including:
# when syssumm detects that NIS is running, add the domain
# name to the output
#
# Revision 1.14  1999/06/11 17:47:21  mohlerb
# changes from Bruce Mohler including:
# factored ReturnRunningSamba routine into common.pm
#
# Revision 1.13  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.12  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.11  1999/06/10 21:47:13  mohlerb
# changes from Bruce Mohler including:
# standardized reference to $MailCommand in initialization function
#
# Revision 1.10  1999/06/07 19:02:11  mohlerb
# changes from Bruce Mohler including:
# changed "Permission denied" RE to case insensitive as some
# messages are capitalized and others aren't
#
# Revision 1.9  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.8  1999/06/07 16:24:51  mohlerb
# changes from Keong Lim including:
# fix little bugs in IPAddressResolution and RunAsRoot
#
# Revision 1.7  1999/06/04 18:51:51  mohlerb
# changes from Bruce Mohler including:
# Added code for "RunAsRoot" functionality.
#
# Revision 1.6  1999/06/03 20:52:55  mohlerb
# changes from Paul Farrall including:
# Added ReturnIPAddressHPUX and ReturnSubnetMaskHPUX functions.
#
# Revision 1.5  1999/06/02 21:18:06  mohlerb
# changes from Keong Lim including:
# added support for HPUX11
# changed "/ 1000" to "/1024" when calculating MB from KB
# uncommented lots of functions that return useful info
#
# Revision 1.4  1999/05/30 19:44:11  mohlerb
# changes from Jeffrey W. Collyer including:
# Support for vxfs local files systems.
#
# Revision 1.3  1999/05/27 14:09:57  mohlerb
# changes from Keong Lim including:
# added Header RCS tag above Revision tag
#
# Revision 1.2  1999/05/25 19:39:57  mohlerb
# changes from Bruce Mohler including:
# Diked out "FauxNameServer" routine in common which was cute
# but silly and non-portable and replaced it with call to
# gethostbyaddr via IPtoFQDN routine in common.pm
#
# Revision 1.1  1999/05/14 22:58:05  mohlerb
# Initial revision
#

use Sys::Hostname;
use common;

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

# where commands are located			standard args
# CUSTOMIZE
$BdfCommand = "/usr/bin/bdf";			$LocalFileSystems = "-t hfs";
						$LocalvxfsFileSystems = "-t vxfs";
						$NFSFileSystems = "-t nfs";
$DiskinfoCommand = "";				# filled in below
$DomainnameCommand = "/usr/bin/domainname";
$IfconfigCommand = "/usr/sbin/ifconfig";
$IoscanCommand = "/etc/ioscan";			$IoscanArgs9 = "-fn";
						$IoscanArgs10 = "-fC";
						$IoscanArgs11 = "-fuC";
						$IoscanArgs12 = "-fnC";
$LanscanCommand = "/usr/sbin/lanscan";
$LpstatCommand = "/usr/bin/lpstat";		$LpstatArgs = "-p";
$ModelCommand = "/usr/bin/model";
$PsCommand = "/usr/bin/ps";			$PsArgs = "-aef";
$PvcreateCommand = "/usr/sbin/pvcreate";
$SwapCommand = "";
$SwlistCommand = "/usr/sbin/swlist";
$UnameCommand = "/bin/uname";
$WcCommand = "/usr/bin/wc";			$WcArgs = "-c";

# where files are located
# CUSTOMIZE
$AccountingConfPath = "/etc/rc.config.d/acct";	$AccountingTag = "START_ACCT";
$ExportsPath = "/etc/exports";
$FontServerConfPath = "/etc/rc.config.d/xfs";	$FontServerTag = "RUN_X_FONT_SERVER";
$GUIConfPath = "/etc/rc.config.d/desktop";	$GUITag = "DESKTOP";
$InetdConfPath = "/etc/inetd.conf";
$LpschedConfPath = "/etc/rc.config.d/lp";	$LpschedTag = "LP";
$MailservsConfPath = "/etc/rc.config.d/mailservs"; $MailservsTag = "SENDMAIL_SERVER";
$MemoryPath = "/dev/mem";
$NameserverConfPath = "/etc/rc.config.d/namesvrs"; $NameserverTag = "NAMED";
						$NISmasterTag = "NIS_MASTER_SERVER";
						$NISslaveTag = "NIS_SLAVE_SERVER";
						$NISclientTag = "NIS_CLIENT";
$NetConfPath = "/etc/rc.config.d/netconf";	$IPAddressTag = "IP_ADDRESS";
						$LoopbackTag = "LOOPBACK_ADDRESS";
						$SubnetMaskTag = "SUBNET_MASK";
						$DefaultRouterTag = "ROUTE_GATEWAY";
$NfsConfPath = "/etc/rc.config.d/nfsconf";	$NFSServerTag = "NFS_SERVER";
						$NFSClientTag = "NFS_CLIENT";
						$AutomountTag = "AUTOMOUNT";
$ResolvConfPath = "/etc/resolv.conf";
$SendmailConfPath = '/etc/mail/sendmail.cf';
$SyslogConfPath = "/etc/syslog.conf";

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

# device path patterns - filled in by InitializeHPUX()
$DiskNamePattern = "";
$TapeNamePattern = "";


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

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

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

	# initialize $SubroutineSuffix...
	WhatVersionOfHPUX();

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

	# this is only used for the HP-UX 9.X memory function
	$SyslogPath = LocateTheSyslogPath($SyslogConfPath);
	print "\tSyslogPath is $SyslogPath\n" if $main::Debug;

	# initialize variables tied to OS level
	if ( $OSVersionMajor == 9 ) {
		$DiskinfoCommand = "/etc/diskinfo";
	}
	elsif ( $OSVersionMajor == 10 or $OSVersionMajor == 11 ) {
		$DiskinfoCommand = "/usr/sbin/diskinfo";
	}
	else {
		die "syssumm doesn't support HP-UX version $OSVersionMajor (yet)";
	}

	# fill in device path patterns
	if ( $OSVersionMajor == 10 or $OSVersionMajor == 11 ) {
		$DiskNamePattern = "/dev/rdsk/c%st%sd0";	# cont, addr
		$TapeNamePattern = "/dev/rmt/%sm";		# addr
	}

	# plug in appropriate subroutines
	$main::Routines{General}{Vendor} = \&ReturnVendorHPUX;
	$main::Routines{General}{Model} = \&ReturnModelHPUX;
	$main::Routines{General}{HostId} = \&ReturnHostIdHPUX;

	my $ReturnProcessorsHPUX = "ReturnProcessorsHPUX$OSVersionMajor";
	$main::Routines{Hardware}{Processors} = \&$ReturnProcessorsHPUX;
	my $ReturnMemoryHPUX = "ReturnMemoryHPUX$OSVersionMajor";
	$main::Routines{Hardware}{Memory} = \&$ReturnMemoryHPUX;
	my $ReturnDisksHPUX = "ReturnDisksHPUX$OSVersionMajor";
	$main::Routines{Hardware}{Disks} = \&$ReturnDisksHPUX;
	my $ReturnTapesHPUX = "ReturnTapesHPUX$OSVersionMajor";
	$main::Routines{Hardware}{Tapes} = \&$ReturnTapesHPUX;
	$main::Routines{Hardware}{StorageManager} = \&ReturnStorageManagerHPUX;
	$main::Routines{Hardware}{Eeprom} = \&ReturnEepromHPUX;

	$main::Routines{Network}{DomainName} = \&ReturnDomainNameHPUX;
	$main::Routines{Network}{DefaultRouter} = \&ReturnDefaultRouterHPUX;
	$main::Routines{Network}{NameServer} = \&ReturnNameServerHPUX;
	$main::Routines{Network}{IPAddress} = \&ReturnIPAddressHPUX;
	$main::Routines{Network}{SubnetMask} = \&ReturnSubnetMaskHPUX;
	$main::Routines{Network}{NetworkInterfaces} = \&ReturnNetworkInterfacesHPUX;

	$main::Routines{Software}{OsName} = \&ReturnOsNameHPUX;
	$main::Routines{Software}{OsVersion} = \&ReturnOsVersionHPUX;
	$main::Routines{Software}{NbrOfLicenses} = \&ReturnNbrOfLicensesHPUX;
	$main::Routines{Software}{Patches} = \&ReturnPatchesHPUX;
	$main::Routines{Software}{Printers} = \&ReturnPrintersHPUX;
	$main::Routines{Software}{Services} = \&ReturnServices;
	$main::Routines{Software}{IPAddressResolution} = \&ReturnIPAddressResolutionHPUX;
	$main::Routines{Software}{GraphicalUserInterface} = \&ReturnGraphicalUserInterfaceHPUX;
	$main::Routines{Software}{FontServer} = \&ReturnFontServerHPUX;
	$main::Routines{Software}{Fstab} = \&ReturnFstab;
	$main::Routines{Software}{LocalFileSystems} = \&ReturnLocalFileSystemsHPUX;
	$main::Routines{Software}{RemoteFileSystems} = \&ReturnRemoteFileSystemsHPUX;
	$main::Routines{Software}{ExportedFileSystems} = \&ReturnExportedFileSystemsHPUX;
	$main::Routines{Software}{Swap} = \&ReturnSwapHPUX;

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

	RemoveLocalExclusions();

	return;
}


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


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

	$OSVersion = `$UnameCommand -r`;
	chomp($OSVersion);

	# adjust the OS version
	# 
	# This will change "B.10.20" to "10.20" or
	#                  "A.09.04" to "09.04"
	# 
	$OSVersion =~ s/[AB]\.//;
	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 ReturnVendorHPUX ($)
{	my $Subcategory = shift;

	# CUSTOMIZE
	return ( "HP" );
}


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

	my $Model = `$ModelCommand`;
	chomp($Model);

	return ( $Model );
}


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

	my $IdNbr = `$UnameCommand -i`;
	chomp($IdNbr);

	return ( $IdNbr );
}


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

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

	print("In ReturnProcessorsHPUX9\n") if $main::Debug;

	# determine clock speed in MHz
	# from Matt Alderson <matt@barry.gf.state.az.us>
	# in comp.sys.hp.hpux
	my $ClockSpeed = 0;
	my $VariableName = "itick_per_tick";
	my @AdbOutput = `echo $VariableName/D | adb /hp-ux /dev/kmem`;
	chomp(@AdbOutput);
	for $Line (@AdbOutput) {
		if ( $Line =~ /(\d+)$/ ) {
			$ClockSpeed = $1;
			last;
		}
	}
	$ClockSpeed = ( $ClockSpeed / 10000 );

	# 
	# Note that HP Technical Tips Bulletin A5440339 provided
	# a way of calling ioscan to return a single line for
	# each processor:
	# 
	#	ioscan -fnC processor
	# 
	# with output like this:
	#	Class       I  H/W Path  Driver    S/W State H/W Type  Description
	#	===================================================================
	#	processor   0  32        processor CLAIMED   PROCESSOR Processor
	#	processor   1  34        processor CLAIMED   PROCESSOR Processor

	# 

	my @IoscanText = ReturnArrayExec("$IoscanCommand $IoscanArgs9");
	foreach $Line ( @IoscanText ) {
		#
		# ioscan, like diskinfo, likes to be run
		# by root...
		# 
		if ( $Line =~ /permission denied/i ) {
			$main::RunAsRoot = 1;
			last;
		}
		if ( $Line =~ /^processor/ ) {
			# get the hardware address
			$Line =~ /[\s]([\d]{2})[\s]/;
			push @Processors, "processor $1";
			next;
		}
	}

	my $NbrOfProcessors = scalar(@Processors);
	my $ProcessorString = $NbrOfProcessors . " processor" . 
		( ( $NbrOfProcessors != 1 ) ? "s" : "" ) . " ($ClockSpeed MHz)";

	# 
	# This routine needs to be modified to support
	# multiple processors...
	# 

	return ( $ProcessorString );
}


# This subroutine uses essentially the same method as described above
# in ReturnProcessorsHPUX09() to find processors.  It uses the output
# of "ioscan -fnC processor".
# This subroutine returns multiple instances of processors.
# Need to implement search for processor speed and type.
# HP doc #A5030766 (How to determine CPU speed and model number) gives 
# a procedure.  I didn't really understand it though, so I left it out 
# of subroutine.

sub ReturnProcessorsHPUX10 ($)
{	my $Subcategory = shift;
	my @Processors = ( );
	my $Nbr = 0;

	print("In ReturnProcessorsHPUX10\n") if $main::Debug;

	# determine clock speed in MHz
	# from Matt Alderson <matt@barry.gf.state.az.us>
	# in comp.sys.hp.hpux
	my $ClockSpeed = 0;
	my $VariableName = "itick_per_tick";
	my @AdbOutput = `echo $VariableName/D | adb /stand/vmunix /dev/kmem`;
	chomp(@AdbOutput);
	for $Line (@AdbOutput) {
		if ( $Line =~ /(\d+)$/ ) {
			$ClockSpeed = $1;
			last;
		}
	}
	$ClockSpeed = ( $ClockSpeed / 10000 );

	my @IoscanText = ReturnArrayExec("$IoscanCommand $IoscanArgs10 processor");
	foreach $Line ( @IoscanText ) {

		next unless ( $Line =~ /^processor\s+(\d+)\s+(\d+)/ );

		# map regexp variables to something more mnemonic
		my $Instance = $1;
		my $HwPath = $2;

		print "\tfound processor instance $Instance\n" if $main::Debug;
		push (@Processors, "processor $Instance ($ClockSpeed MHz)");
	}

	my @Response = ForceMultipleResponses(\@Processors);

	return @Response;
}


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

	# 
	# processing is the same as for HPUX10...
	# 
	# XXX note that the ioscan args are different for 10 and 11...
	# 

	return ReturnProcessorsHPUX10($Subcategory);
}


# 
# We've changed the ReturnMemory function for HP-UX 10.X and 11.X
# to no longer use the syslog as its source of information.  do we
# need to do the same for HP-UX 9.X?  [I no longer have any HP-UX
# 9.X systems to test on - Bruce]
# 

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

	# how much memory?
	my $Memory = SearchFileForPattern($SyslogPath, "real mem", 3);
	$Memory = int ( $Memory / 1024 );
	$Memory = "$Memory" . "MB";

	return ( $Memory );
}


# 
# There are a couple of ways to answer this question.
# 
#	Look for "Physical:" in the syslog.
#	Run "wc -c /dev/mem" as root.
#	/usr/sam/lbin/getmem.
#	Pull it from the currently running kernel with adb (as we do below)
# 
# Because of problems with retrieving information from the syslog,
# we're opting to use option 4 because it is so much faster than 
# option 2!
# 

sub ReturnMemoryHPUX10 ($)
{	my $Subcategory = shift;
	my $Memory = 0;
 
	open (MEM_SIZE, "echo physmem/D | adb /stand/vmunix /dev/mem |");
	while (<MEM_SIZE>) {
		if (/^\S+:\s+(\d+)/) {
			$Memory = $1;
			last;
		}
	}
	close MEM_SIZE;
	$Memory = int ( $Memory / 256);
	$Memory = "$Memory" . "MB";

	return ( $Memory );
}


sub ReturnMemoryHPUX11 ($)
{	my $Subcategory = shift;
	my $Memory = 0;
 
	open (MEM_SIZE, "echo phys_mem_pages/D | adb /stand/vmunix /dev/mem |");
	while (<MEM_SIZE>) {
		if (/^\S+:\s+(\d+)/) {
			$Memory = $1;
			last;
		}
	}
	close MEM_SIZE;
	$Memory = int ( $Memory / 256);
	$Memory = "$Memory" . "MB";
 
	return ( $Memory );
}


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

	my @IoscanText = ReturnArrayExec("$IoscanCommand $IoscanArgs9");
	foreach $Line ( @IoscanText ) {
		#
		# ioscan, like diskinfo, likes to be run
		# by root...
		# 
		if ( $Line =~ /permission denied/i ) {
			$main::RunAsRoot = 1;
			last;
		}
		# SCSI controller
		if ( $Line =~ /^scsi/ ) {
			$Line =~ /[\s][\d]{2}\/([\d]{2})[\s]/;
			push @Controllers, "controller $1";
			$CurrentController = $1;
			next;
		}
		# disk drive
		if ( $Line =~ /^disk/ ) {
			# get the hardware address
			$Line =~ /[\s][\d]{2}\/([\d]{2}\.[\d]{1}\.[\d]{1})[\s]/;
			my $HardwareAddress = $1;
			# now rescan the IoscanText and find the /dev name
			my $FindHardwareAddress = 1;
			my $DeviceAddress = "";
			INNER: foreach $Line ( @IoscanText ) {
				if ( $FindHardwareAddress ) {
					next if ! $Line =~ /^disk/;
					if ( $Line =~ /$HardwareAddress/ ) {
						$FindHardwareAddress = 0;
						next INNER;
					}
				}
				else { # find /dev/name
					$Line =~ /(\/dev\/rdsk\/c[\d]+d0s2)/;
					if ( $1 ) {
						$DeviceAddress = $1;
						last INNER;
					}
				}
			}
			print "\tfound disk $CurrentController $DeviceAddress\n" if $main::Debug;
			my $Response = AddDiskinfo09("disk $CurrentController $DeviceAddress");
			push @Response, $Response if ( $Response );
			next;
		}
	}

	@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 AddDiskinfo09 ($)
{	my $DeviceInfo = shift;
	my $ValidDevice = 0;

	print "AddDiskinfo09($DeviceInfo)...\n" if $main::Debug;

	my ( $DeviceType, $Controller, $DeviceName ) = split(/ /, $DeviceInfo);
	print "\tDeviceName is $DeviceName...\n" if $main::Debug;

	return AddDiskinfo($DeviceName);
}


sub ReturnDisksHPUX10 ($)
{	my $Subcategory = shift;
	my $ControllerNbr = 0;
	my $CurrentController = -1;
	my $DeviceName = "";
	my $Response = "";
	my @Response = ( );

	my @IoscanText = ReturnArrayExec("$IoscanCommand $IoscanArgs10 disk");
	foreach $Line ( @IoscanText ) {
		my $CdromDrive = 0;

		# 
		# If it's a CD-ROM drive, save information for later
		# 
		if ( $Line =~ /CD-ROM/ ) {
			$CdromDrive = 1;
			# drop the field from the line...
			$Line =~ s/CD-ROM //;
		}

		# we're looking for patterns like
		# 
		#	"disk      0  56/52.1.0  disc3  CLAIMED   DEVICE    SEAGATE ST12400N"
		#	"disk      1  56/52.2.0  disc3  CLAIMED   DEVICE    TOSHIBA CD-ROM XM-3401TA"
		#	"disk      4  56/52.5.0  disc3  CLAIMED   DEVICE    HP      C2247M1"
		# 
		if ( $Line =~ /^(disk)\s+(\d+)\s+(\S+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)/) {

			# map regexp variables to something more mnemonic
			# not all of these will be used...
			my $Class = $1;
			my $Instance = $2;
			my $HwPath = $3;
			my $Driver = $4;
			my $SwState = $5;
			my $HwType = $6;
			my $Vendor = $7;
			my $Model = $8;

			print "\tfound disk instance $Instance:$HwPath\n" if $main::Debug;

			# split out controller and SCSI address
			$HwPath =~ /\d+\/(\d+)\.(\d+)\.\d+/;
			my $Controller = $1;
			my $Address = $2;

			# 
			# XXX Is this accurate?
			# 
			if ( $CurrentController == -1 ) {
				$CurrentController = $Controller;
			}
			elsif ( $CurrentController != $Controller ) {
				$ControllerNbr += 1;
				$CurrentController = $Controller;
			}

			$DeviceName = sprintf($DiskNamePattern, $ControllerNbr, $Address);

			if ( $CdromDrive ) {
				$Model="CD-ROM ($Model)";
			}

			my $Response = AddDiskinfo10("disk $CurrentController $DeviceName");
			# $Response = "$DeviceName vendor=$Vendor model=$Model";

			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 AddDiskinfo10 ($)
{	my $DeviceInfo = shift;
	my $ValidDevice = 0;

	print "AddDiskinfo10($DeviceInfo)...\n" if $main::Debug;

	# build the name of the drive from controller/address info
# 	my $DeviceName = "";
	my ( $DeviceType, $Controller, $DeviceName ) = split(/ /, $DeviceInfo);
# 	if ( $DeviceType eq "disk" ) {
# 		$DeviceName = sprintf($DiskNamePattern, $Controller, $Address);
# 	}
# 	elsif ( $DeviceType eq "tape" ) {
# 		$DeviceName = sprintf($TapeNamePattern, $Controller, $Address);
# 	}
# 	return "" if ! $DeviceName;
	print "\tDeviceName is $DeviceName...\n" if $main::Debug;

	return AddDiskinfo($DeviceName);
}


sub AddDiskinfo ($)
{	my $DeviceName = shift;
	my $ValidDevice = 0;
	my $UnknownDevice = "model=unknown";

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

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

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

		if ( $Vendor and $Model and $Type ) {
			return ("$DeviceName vendor=$Vendor type=$Type model=$Model");
		}

		print "\t$Line\n" if $main::Debug;
		if ( $Line =~ /permission denied/i ) {
			$main::RunAsRoot = 1;
			return "$DeviceName $UnknownDevice";
		}
		if ( $Line =~ /no such device/i ) {
			return "$DeviceName $UnknownDevice";
		}
		if ( $Line =~ /vendor/ ) {
			( $Tag, $Vendor ) = split(/:/, $Line);
			# strip off any leading/trailing whitespace
			$Vendor =~ s/^[\s]+//g;
			$Vendor =~ s/[\s]+$//g;
			print "\tVendor is $Vendor...\n" if $main::Debug;
			next;
		}
		if ( $Line =~ /product id/ ) {
			( $Tag, $Model ) = split(/:/, $Line);
			# strip off any leading/trailing whitespace
			$Model =~ s/^[\s]+//g;
			$Model =~ s/[\s]+$//g;
			# if it's a cd-rom, split that out as the type
			if ( $Model =~ /^(CD-ROM) (.*)$/ ) {
				$Type = $1;
				$Model = $2;
				print "\tType is $Type...\n" if $main::Debug;
			}
			print "\tModel is $Model...\n" if $main::Debug;
			next;
		}
		if ( $Line =~ /size/ ) {
			$Line =~ /size: (\d+) Kbytes/;
			$Size = int( $1 / 1024 );
			if ( $Size > 1024 ) {
				$Size = int( $Size / 1024 );
				$Size .= "GB";
			}
			else {
				$Size .= "MB";
			}
		}
	}

	# return what we have
	my $Description = "";

	if ( $Vendor ) {
		$Description .= "vendor=$Vendor";
	}
	if ( $Model ) {
		if ( $Description ) {
			$Description = "$Description model=$Model";
		}
		else {
			$Description .= "model=$Model";
		}
	}
	if ( $Type ) {
		if ( $Description ) {
			$Description = "$Description type=$Type";
		}
		else {
			$Description .= "type=$Type";
		}
	}
	if ( $Size ) {
		if ( $Description ) {
			$Description = "$Description size=$Size";
		}
		else {
			$Description .= "size=$Size";
		}
	}

	return "$DeviceName $Description";
}


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

	# 
	# processing is the same as for HPUX10...
	# 
	# XXX note that the ioscan args are different for 10 and 11...
	# 

	return ReturnDisksHPUX10($Subcategory);
}


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

	return ReturnTapesHPUX($IoscanArgs09);
}


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

	return ReturnTapesHPUX($IoscanArgs10);
}


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

	return ReturnTapesHPUX($IoscanArgs11);
}


sub ReturnTapesHPUX ($)
{	my $IoscanArgs = shift;
	my $DeviceName = "";
	my $Response = "";
	my @Response = ( );

	my @IoscanText = ReturnArrayExec("$IoscanCommand $IoscanArgs tape");
	foreach $Line ( @IoscanText ) {

		# we're looking for patterns like
		# 
		# "tape      0  4.1.0     tape2  CLAIMED   DEVICE    HP      HP35480A"
		# 
		if ( $Line =~ /^(tape)\s+(\d+)\s+(\S+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)/) {

			# map regexp variables to something more mnemonic
			# not all of these will be used...
			my $Class = $1;
			my $Instance = $2;
			my $HwPath = $3;
			my $Driver = $4;
			my $SwState = $5;
			my $HwType = $6;
			my $Vendor = $7;
			my $Model = $8;

			print "\tfound tape instance $Instance:$HwPath\n" if $main::Debug;

			$DeviceName = sprintf($TapeNamePattern, $Instance);

			$Response = "$DeviceName hwpath=$HwPath vendor=$Vendor model=$Model";

			push @Response, $Response;
		}
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


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

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

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


sub ReturnEepromHPUX ($)
{	my $Subcategory = shift;
	my $Eeprom = "Not applicable";

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

	return ( $Eeprom );
}


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

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

	return ReturnDomainName($Subcategory, $ResolvConfPath);
}


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

	my $DefaultRouter = SearchFileForTagValue($NetConfPath, $DefaultRouterTag);
	$DefaultRouter = IPtoFQDN($DefaultRouter);

	return ( $DefaultRouter );
}


sub ReturnNameServerHPUX ($)
{	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);
				if ( ! $NameServerFQDN ) {
					$HPUX::NonStandardNameServer = 1;
				}
				push @Response, $NameServerFQDN;
				next;
			}
		}
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


sub ReturnIPAddressHPUX
{	my $Subcategory = shift;

	# Returns the IP address associated with "$main::nodename"
	my @Addresses = (gethostbyname $main::NodeName)[4];         
	my ($a, $b, $c, $d) = unpack('C4', $Addresses[0]);
	$IPAddress = "$a." . "$b." . "$c." . "$d" ;

	return ( $IPAddress );
}


sub ReturnSubnetMaskHPUX
{	my $Subcategory = shift;
	my $SubnetMask = "";       

	print "Deriving the default netmask...\n" if $main::Debug;

	# Returns netmask associated with the "default" IP address
	my $IPAddress = ReturnIPAddressHPUX($Subcategory);
	my @Interfaces = ReturnNetworkInterfacesHPUX($Subcategory);

	# 
	# XXX - there is a problem with this function
	#	If I read it correctly, it will return
	#	the netmask on the *last* interface returned
	#	from the ReturnNetworkInterfacesHPUX function.
	#	I don't think that this is what we want.
	# 	We should return the netmask on the "default"
	# 	network interface (INTERFACE_NAME[0] in the
	#	/etc/rc.config.d/netconf file).
	# 

	# find interface corresponding to "default" IP
	# and get netmask from it
	foreach $Line (@Interfaces) {
		next unless ( $Line =~ /$IPAddress/ ); 
		if ( $Line =~ /netmask=(\w+)/ ) {      
			# ReturnNetworkInterfacesHPUX() returns netmask in hex.
			# convert back to decimal
			my $a=substr($1,0,2); 
			my $b=substr($1,2,2); 
			my $c=substr($1,4,2); 
			my $d=substr($1,6,2);
			$SubnetMask = hex($a) . "." . hex($b) . "." . hex($c) . "." . hex($d);
		}
	}

	return ($SubnetMask);
}     


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

	my @LanscanText = ReturnArrayExec("$LanscanCommand");
	foreach $Line ( @LanscanText ) {
		# we're looking for patterns like
		# 
		#	"60/6     0x080009797BDB 0   UP       lan0..."
		# 
		# Below is a regex (provided by Jim Holthaus) that will 
		# properly parse the output from lanscan that works on
		# both 11.X and 10.X, though be warned about the 
		# following difference: $6 = PPA or blank (for atm) on 
		# 11.X; $6 = Interface State on 10.X.  Since we are not 
		# using $6 for anything, there is no problem -- yet.
		# 
		# this will also handle cip and atm interfaces
		if ( $Line =~ /^(\S+)\s+(0x[0-9A-Fa-f]+)\s+(\d+)\s+(\w+)\s+(\w+)\s+(.+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)$/) {
			# map regexp variables to something more mnemonic
			my $MacAddress = $2;
			my $NICName = $5;
			my $State = $4;
			my $Type = $8;

			print "\tfound NIC instance $NICName\n" if $main::Debug;

			my ( $IPAddress, $Netmask, $BroadcastMask ) = AddNetInfo($NICName);

			$Response = "$NICName type=$Type macaddr=$MacAddress ip=$IPAddress netmask=$Netmask state=$State broadcast=$BroadcastMask";

			push @Response, $Response if ( $Response);
		}
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


# 
# Obtain the IP address and netmask of the supplied 
# network interface
# 

sub AddNetInfo ($)
{	my $NICName = shift;
	my $IPAddress = "n/a";
	my $Netmask = "n/a";
	my $BroadcastMask = "n/a";

	print "AddNetInfo($NICName)...\n" if $main::Debug;

	my @IfconfigText = ReturnArrayExec("$IfconfigCommand $NICName");

	foreach $Line (@IfconfigText) {
		if ( $Line =~ /inet\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}).*netmask\s+([0-9a-f]{8}).*broadcast\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/ ) {
			$IPAddress = $1;
			$Netmask = $2;
			$BroadcastMask = $3;
			last;
		}
	}

	return ( $IPAddress, $Netmask, $BroadcastMask );
}


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

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

	return ( "HP-UX" );
}


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

	return ( "$OSVersion" );
}


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

	my $NbrOfLicenses = `$UnameCommand -l`;
	chomp($NbrOfLicenses);

	return ( $NbrOfLicenses );
}


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

	# what patches are installed?
	open SWLIST, "$SwlistCommand -l product 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 =~ /^PH/ ) {
			my ( $PatchName, $PatchVersion, $PatchDescription ) =
				split(/ /, $Line, 3);
			push @Response, "$PatchName desc=\"$PatchDescription\"";
		}
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


sub ReturnRunningLpschedHPUX ($)
{	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 ReturnPrintersHPUX ($)
{	my $Subcategory = shift;
	my $IsDefault = "";
	my @Response = ( );

	# what is the default printer queue?
	my @DefaultPrinter = ReturnArrayExec("$LpstatCommand -d");
	$DefaultPrinter[0] =~ /system default destination: (.*)$/;
	my $DefaultPrinter = $1;

	# get a list of all configured printers
	my @LocalPrinters = ReturnArrayExec("$LpstatCommand $LpstatArgs");
	foreach $Line (@LocalPrinters) {
		if ( $Line =~ /^printer/ ) {
			$Line =~ /^printer ([\w_]+) is/;
			my $PrinterName = $1;
			$IsDefault = "";
			if ( $PrinterName eq $DefaultPrinter ) {
				$IsDefault = " (default)";
			}
			push @Response, "$PrinterName$IsDefault";
		}
	}

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

	my $Sendmail = SearchFileForTagValue($MailservsConfPath, $MailservsTag);

	if ( $Sendmail eq $NotFound ) {
		$Sendmail = SearchFileForPattern("$PsCommand $PsArgs", "sendmail", -1);
		# if we still didn't find anything...
		if ( $Sendmail eq $NotFound ) {
			$Sendmail = "";
		}
	}
	$Sendmail = ( $Sendmail ? "Yes" : "No" );

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

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

	return ( $Sendmail );
}


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

	my $NFSState = "";
	my $NFSServer = SearchFileForTagValue($NfsConfPath, $NFSServerTag);
	print "\tNFSServer is $NFSServer\n" if $main::Debug;
	my $NFSClient = SearchFileForTagValue($NfsConfPath, $NFSClientTag);
	print "\tNFSClient is $NFSClient\n" if $main::Debug;
	if ( $NFSServer eq "1" and $NFSClient eq "1" ) {
		$NFSState = "Yes, both server and client";
	}
	elsif ( $NFSServer eq "1" ) {
		$NFSState = "Yes, server only";
	}
	elsif ( $NFSClient eq "1" ) {
		$NFSState = "Yes, client only";
	}
	else {
		$NFSState = "No";
	}

	return ( $NFSState );
}


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

	my $Automount = SearchFileForTagValue($NfsConfPath, $AutomountTag);
	$Automount = ( $Automount eq "1" ? "Yes" : "No" );

	return ( $Automount );
}


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

	my $NISState = "";
	my $NISmaster = SearchFileForTagValue($NameserverConfPath, $NISmasterTag);
	my $NISslave = SearchFileForTagValue($NameserverConfPath, $NISslaveTag);
	my $NISclient = SearchFileForTagValue($NameserverConfPath, $NISclientTag);
	if ( $NISmaster or $NISslave ) {
		$NISmaster = 1;
	}
	if ( $NISmaster and $NISclient ) {
		$NISState = "Yes, both server and client";
	}
	elsif ( $NISmaster ) {
		$NISState = "Yes, server only";
	}
	elsif ( $NISclient ) {
		$NISState = "Yes, client only";
	}
	else {
		$NISState = "No";
	}

	# if we're running NIS, document the domain name
	if ( $NISState =~ /^yes/oi ) {
		my $Domainname = `$DomainnameCommand`;
		chomp($Domainname);
		$NISState .= ", domain is $Domainname";
	}

	return ( $NISState );
}


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

	my $Nameserver = SearchFileForTagValue($NameserverConfPath, $NameserverTag);
	if ( $Nameserver eq $NotFound ) {
		$Nameserver = "Unknown";
	}
	else {
		$Nameserver = ( $Nameserver ? "Yes" : "No" );
	}

	return ( $Nameserver );
}


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

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

	return ( $IPAddressResolution );
}


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

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


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

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

	return ( $GUI );
}


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

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

	# just in case someone configured it manually... (thanks to Paul Thompson)
	if ( $FontServer eq "No" ) {
		my $PsOutput = SearchFileForPattern("$PsCommand $PsArgs", "xfs", -1);
		if ( $PsOutput == $NotFound or $PsOutput eq "" ) {
			$FontServer = "No";
		}
		else {
			$FontServer = "Yes";
		}      
	}

	return ( $FontServer );
}


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

	my @BdfText = ReturnArrayExec("$BdfCommand $LocalFileSystems");
	my @BdfvxfsText = ReturnArrayExec("$BdfCommand $LocalvxfsFileSystems");
	push @BdfText, @BdfvxfsText;

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

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

		# partial line?
		if ( $PreviousLine ) {
			$Line = $PreviousLine . $Line;
			$PreviousLine = "";
		}

		# clean and split line
		$Line =~ s/[\s]+/ /g;
		my @BdfFields = split(/ /, $Line);

		# partial line?
		if ( scalar(@BdfFields) < 2 ) {
			$PreviousLine = $Line;
			# go get the rest of it
			next;
		}

		# calc size in MB
		my $Size = sprintf("%.1fMB", ( $BdfFields[1] / 1024 ) );

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

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


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

	my @BdfText = ReturnArrayExec("$BdfCommand $NFSFileSystems");

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

		# 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 @BdfFields = split(/ /, $Line);

		# partial line?
		if ( scalar(@BdfFields) < 2 ) {
			$PreviousLine = $Line;
			# go get the rest of it
			next;
		}

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

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

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


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

	if ( -r $ExportsPath) {
		my @Exportslist = ReturnArrayFile("$ExportsPath");
		foreach $Line (@Exportslist) {
			next if ($Line =~ /^\s*$/);
			next if ($Line =~ /^#/);
			push @Response, $Line;
		}
	} else {
		@Response = "No exports - not an NFS Server";
	}

	@Response = ForceMultipleResponses(\@Response);

	return @Response;
}


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

	#
	# XXX - This is a dummy routine
	# 
	# The value of $SwapCommand needs to be initialized above.
	# 

	if ( $SwapCommand ) {
		return ReturnSwap($Subcategory, "$SwapCommand");
	} else {
		return '(unknown)';
	}
}


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

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

	return ( $Accounting );
}


###########################################################################
# End of HPUX.pm
###########################################################################

1;
