#!/usr/bin/perl # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # bos720 src/bos/usr/sbin/install/suma/lib/SUMA/SoftwareInventory.pm 1.5 # # Licensed Materials - Property of IBM # # Restricted Materials of IBM # # COPYRIGHT International Business Machines Corp. 2004,2006 # All Rights Reserved # # US Government Users Restricted Rights - Use, duplication or # disclosure restricted by GSA ADP Schedule Contract with IBM Corp. # # IBM_PROLOG_END_TAG package SUMA::SoftwareInventory; # code starts after '=cut' =head1 NAME SUMA::SoftwareInventory - A module to display a system's or nim client's software inventory information in multiple formats. =head1 SYNOPSIS use SUMA::SoftwareInventory qw/get_inv_sys get_inv_repos/; # # Software inventory # $format="lslpp"; $lslpp_flags="Lcq"; @clients=("localhost","alpha","beta"); $path="/usr/sys/inst.images"; ($software_list_fh,$pid)=get_inv_sys($format,$lslpp_flags,"localhost"); # ($software_list_fh,$pid)=get_inv_sys("localhost"); print (<$software_list_fh>); close $software_list_fh; waitpid($pid,0); my $rc=$? >> 8; # exit $rc; # or $software_list_fh=get_inv_sys($format,$lslpp_flags,@clients); # $software_list_fh=get_inv_sys(@clients); print (<$software_list_fh>); close $software_list_fh; # exit 0; # # Software repository # ($software_list_fh,$pid)=get_inv_repos($path); print (<$software_list_fh>); close $software_list_fh; waitpid($pid,0); my $rc=$? >> 8; # exit $rc; # or $software_list_fh=get_inv_repos($path); print (<$software_list_fh>); close $software_list_fh; # exit 0; =cut use strict; use Getopt::Std; use File::Spec; use HTML::Entities qw/encode_entities/; # SUMA modules use lib qw(/usr/suma/lib); use POSIX qw(strftime); use SUMA::GConfig; use SUMA::Util qw(ckPrivate writeXml RE_PATH); use SUMA::Messenger qw( MSG_CANT_FORK MSG_GENERIC MSG_NOT_MASTER MSG_NOT_ROOT MSG_NO_HOSTNAME MSG_USAGE_SUMA_SWINV2 ); require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw( get_inv_sys get_inv_repos ); # Default Values my $user=""; my $nimMaster=0; # Whether this is a nim master my $hostname="localhost"; # Globals my $format; my $lslpp_flags; my @properties; my $xml_arrayRef; my @LSLPP; my @LSLPP_PROD_INFO; my @REPOS; # Error Codes my $ecFailure=1; # General error including usage my $ecPartialFailure=2; # Some clients returned information others did not =head1 METHODS =over 4 =item get_inv_repos PATH_STR Outputs the software inventory of a repository. The PATH_STR can be either relative or absolute. The inventory output is formatted exactly the same as a call to geninstall -Ld PATH_STR. The value returned is either a file handle to the output or an array holding the file handle and then the pid of the process writing the output. The pid is returned so you may get a return code (see synopsis for example). The type of return value is determined by looking at what you are expecting as a return value either a scalar or an array. =cut sub get_inv_repos { my $path=shift; my $writer; my $reader; $path=File::Spec->rel2abs($path); # Get current user $user=`/usr/bin/whoami`; chomp($user); # Pipe the content out. Caller deals with it. pipe($reader, $writer); if(my $pid = fork) { # Parent close $writer; if (wantarray()) { return ($reader,$pid); } else { return $reader; } } else { # Child - write content into the pipe and then exit. unless(defined($pid)) { mesg(LVL_ERROR, MSG_CANT_FORK); mesg(LVL_DEBUG, MSG_GENERIC, "Fork failed piping lslpp content out of " . (caller(0))[3]); return undef; } close $reader; my $rc=_getReposInfo($path); # Output Client Information if ($rc == 0) { print ($writer @REPOS); } # end if $rc == 0 close $writer; exit($rc); } } # end get_inv_repos =item get_inv_sys CLIENT_STR =item get_inv_sys FORMAT_STR, FLAGS_STR, CLIENT_STR =item get_inv_sys FORMAT_STR, FLAGS_STR, CLIENT_STR1, CLIENT_STR2 ... Outputs the software inventory of a system. The CLIENT_STR must be "localhost" if you wish the inventory of the local system. You may also specify a valid nim client as a CLIENT_STR if the local system is the nim master. FORMAT_STR is the format the output should be in; this is either "lslpp" or "xml". FLAGS_STR is the lslpp flags to pass to the lslpp command. The FLAGS_STR's value is ignored if the format is xml, though a value must still be passed in. In the case where only CLIENT_STR is passed in then the output will be the same as if FLAGS_STR="Lcq" and FORMAT_STR="lslpp". The value returned is either a file handle to the output or an array holding the file handle and then the pid of the process writing the output. The pid is returned so you may get a return code (see synopsis for example). The type of return value is determined by looking at what you are expecting as a return value either a scalar or an array. =cut sub get_inv_sys { my @clients; my $client; my $writer; my $reader; if (scalar(@_) == 1) { $format="lslpp"; $lslpp_flags="Lcq"; } else { $format=shift; if (! defined($format)) {$format="lslpp";} $lslpp_flags=shift; if (! defined($lslpp_flags)) {$lslpp_flags="Lcq";} } @clients=@_; if (! defined($clients[0])) {@clients=("localhost")} # Get current user $user=`/usr/bin/whoami`; chomp($user); # Check for nim master system("/usr/bin/grep NIM_CONFIGURATION=master /etc/niminfo > /dev/null 2>&1 "); if ($? == 0) {$nimMaster=1;} # Get hostname $hostname=`/usr/bin/hostname`; if (($? != 0) && ($format eq "xml")) { mesg(LVL_ERROR, MSG_NO_HOSTNAME); exit $ecFailure; } chomp($hostname); my $returnCode=0; # set return code my($wroteXmlHead)=0; my($wroteXmlRCHead)=0; # Pipe the content out. Caller deals with it. pipe($reader, $writer); if(my $pid = fork) { # Parent close $writer; if (wantarray()) { return ($reader,$pid); } else { return $reader; } } else { # Child - write content into the pipe and then exit. unless(defined($pid)) { mesg(LVL_ERROR, MSG_CANT_FORK); mesg(LVL_DEBUG, MSG_GENERIC, "Fork failed piping lslpp content out of " . (caller(0))[3]); return undef; } close $reader; foreach $client (@clients) { $client=_clean($client); my $rc=_getSoftwareInfo($client); if (($rc == 1) && ($returnCode == 0)) {$returnCode=$ecFailure;} if (($rc == 0) && ($returnCode == $ecFailure)) {$returnCode=$ecPartialFailure;} # Output Client Information if ($rc == 0) { GET_CASE1: { ($format eq "lslpp") && do { _writeLslpp($writer); last GET_CASE1; }; ($format eq "xml") && do { if(! $wroteXmlHead) { _writeXmlHead($writer); $wroteXmlHead=1; } my $xml_arrayRef=_createXmlStructure($client); writeXml($writer,$xml_arrayRef, 2); last GET_CASE1; }; ($format eq "xmlrc") && do { if(! $wroteXmlRCHead) { _writeXmlRCHead($writer); $wroteXmlRCHead=1; } my $xml_arrayRef=_createXmlRCStructure($client); writeXml($writer,$xml_arrayRef, 2); last GET_CASE1; }; } # end GET_CASE1 } # end if $rc == 0 } # end foreach $client # Write the end text if the output was in xml. if (($format eq "xml") && ($returnCode != 1)) {_writeXmlTail($writer);} if (($format eq "xmlrc") && ($returnCode != 1)) {_writeXmlRCTail($writer);} close $writer; exit($returnCode); } } # end get_inv_sys # Function: _getSoftwareInfo(client_str) # Purpose: To acquire the lslpp information needed for software inventory. # Side effects: Variables LSLPP and LSLPP_PROD_INFO contain the output from the # lslpp commands. # Returns: 0 success, $ecFailure sub _getSoftwareInfo { ckPrivate(); my $client=shift; if (! defined($client)) {return $ecFailure}; $lslpp_flags=_clean($lslpp_flags); if (! defined($lslpp_flags)) {return $ecFailure}; if (($client eq "localhost") || ($client eq $hostname)) { mesg(LVL_DEBUG, MSG_GENERIC, "Getting lslpp output for the localhost."); if (($format eq "xml") || ($format eq "xmlrc")) { @LSLPP_PROD_INFO=`/usr/bin/lslpp -icq 2>&1 `; if ( $? != 0) {return $ecFailure;} $lslpp_flags="Lcq"; } @LSLPP=`/usr/bin/lslpp -$lslpp_flags 2>&1 `; if ( $? != 0) {return $ecFailure;} } else { mesg(LVL_DEBUG, MSG_GENERIC, "Getting lslpp output for nim client: ",$client,"."); if ($user ne "root") { mesg(LVL_ERROR, MSG_NOT_ROOT); return $ecFailure; } if (! $nimMaster) { mesg(LVL_ERROR, MSG_NOT_MASTER); return $ecFailure; } if (($format eq "xml") || ($format eq "xmlrc")) { @LSLPP_PROD_INFO=`/usr/sbin/nim -o lslpp -a lslpp_flags=-icq $client 2>&1 `; if ( $? != 0) {return $ecFailure;} $lslpp_flags="Lcq"; } @LSLPP=`/usr/sbin/nim -o lslpp -a lslpp_flags=-$lslpp_flags $client 2>&1 `; if ( $? != 0) {return $ecFailure;} } return 0 } # end _getSoftwareInfo # Function: _getReposInfo(path_str) # Purpose: To acquire the geninstall information needed for repository inventory. # Side effects: Variable REPOS contains the output from the geninstall command. # Returns: 0 success, $ecFailure sub _getReposInfo { ckPrivate(); my $path=shift; if (! defined($path)) {return $ecFailure}; ($path) = $path =~ RE_PATH; # Untaint return $ecFailure unless $path; if ($user ne "root") { mesg(LVL_ERROR, MSG_NOT_ROOT); return $ecFailure; } @REPOS=`/usr/sbin/geninstall -Ld $path 2>&1 `; if ( $? != 0) {return $ecFailure;} return 0 } # end _getReposInfo # Function: _writeLslpp(writer_fh) # Purpose: To write the contents of the variable LSLPP to the filehandle passed in. # Side effects: Writes to stream. # Returns: 0 success sub _writeLslpp { ckPrivate(); my $writer=shift; print ($writer @LSLPP); } # end _writeLslpp # Function: _writeXmlHead(writer_fh) # Purpose: To write the xml header and the first two tags to the filehandle passed in. # Side effects: Writes to filehandle. # Returns: 0 success sub _writeXmlHead { ckPrivate(); my $writer=shift; print($writer " \n"); print($writer "\n"); print($writer " \n"); print($writer " \n\n"); } # end _writeXmlHead # Function: _writeXmlRCHead(writer_fh) # Purpose: To write the xmlrc header to the filehandle passed in. # Side effects: Writes to filehandle. # Returns: 0 success sub _writeXmlRCHead { ckPrivate(); my $writer=shift; print($writer " \n"); print($writer " \n"); } # end _writeXmlRCHead # Function: _createXmlStructure(client_str) # Purpose: To create the array reference that will hold the filled in xml structure # for the xml document that is created from reading the LSLPP and LSLPP_PROD_INFO # variables. # Side effects: - # Returns: The tagArrayRef for an xml structure for the client passed in. # See SUMA::Util->writeXml for more details on structure. sub _createXmlStructure { ckPrivate(); my $client=shift; my $clientHostname=$client; my $clientOSLevel; if ($clientHostname eq "localhost") # localhost { $client=$hostname; $clientHostname=$hostname; $clientOSLevel=`/usr/bin/oslevel`; chomp($clientOSLevel); } else # nim client { $clientHostname=(`/usr/sbin/lsnim -Za if1 $client`)[1]; chomp($clientHostname); $clientHostname=(split(":",$clientHostname))[2]; $clientOSLevel=""; } my %productIdHash; foreach my $line (@LSLPP_PROD_INFO) { chomp($line); my($path,$fileset,$vendorCode,$prodId,$featureId,$parent,$extras); my($level); # field:1 2 3 4 5 6 7 ($path,$fileset,$vendorCode,$prodId,$featureId,$parent,$extras)=split(/:/,$line); ($fileset,$level)=split(/ /,$fileset); $productIdHash{$fileset}=$prodId; } my($packageName,$fileset,$level,$state,$ptfId,$fixState,$type,$desc); my($destDir,$uninstaller,$messCat,$messSet,$messNum,$parent,$automatic); my($efixLocked,$extras); my $filesets_array=[]; my ($child_tagArrayRef,$child_array,$property_tagArrayRef); foreach my $line (@LSLPP) { chomp($line); $line=~s/: :/::/g; # Make entries that are a space blank $line=~s/: :/::/g; # Need second run through $line=encode_entities($line); # html encode entries # field: 1 2 3 4 5 6 7 8 ($packageName,$fileset,$level,$state,$ptfId,$fixState,$type,$desc, # field: 9 10 11 12 13 14 15 $destDir,$uninstaller,$messCat,$messSet,$messNum,$parent,$automatic, # field: 16 17 $efixLocked,$extras)=split(/:/,$line); my $property_array=[]; # PCP my $uniqueId='"'.$fileset; $uniqueId.='_'.$destDir if ($destDir ne ""); $uniqueId.='"'; $child_tagArrayRef=['Value',$fileset,"", 'type', '"string"']; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property','PCP',$child_array, 'name', '"PCP"', 'displayName', '"Component"']; push(@{$property_array},$property_tagArrayRef); # DS $child_tagArrayRef=['Value',$desc,"", 'type', '"string"']; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property','DS',$child_array, 'name', '"DS"', 'displayName', '"Description"']; push(@{$property_array},$property_tagArrayRef); # PPF $child_tagArrayRef=['Value',$packageName,"", 'type', '"string"']; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property','PPF',$child_array, 'name', '"PPF"', 'displayName', '"Feature"']; push(@{$property_array},$property_tagArrayRef); # PVK $child_tagArrayRef=['Value',$level,"", 'type', '"string"']; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property','PVK',$child_array, 'name', '"PVK"', 'displayName', '"Version"']; push(@{$property_array},$property_tagArrayRef); # Use the V in VRMF of bos.rte for oslevel if it is a client if (($clientOSLevel eq "") && ($fileset eq "bos.rte")) { $clientOSLevel=substr($level,0,1); $clientOSLevel.=".0.0.0"; } # PIS $child_tagArrayRef=['Value',$destDir,"", 'type', '"string"']; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property','PIS',$child_array, 'name', '"PIS"', 'displayName', '"Instance"']; push(@{$property_array},$property_tagArrayRef); # PUI $child_tagArrayRef=['Value',$uninstaller,"", 'type', '"string"']; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property','PUI',$child_array, 'name', '"PUI"', 'displayName', '"Uninstall Info"']; push(@{$property_array},$property_tagArrayRef); # PFC $type=" " if($type eq ""); # Make this one a space if it is blank $child_tagArrayRef=['Value',$type,"", 'type', '"string"']; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property','PFC',$child_array, 'name', '"PFC"', 'displayName', '"Fix Type Code"']; push(@{$property_array},$property_tagArrayRef); # PSC $child_tagArrayRef=['Value',$fixState,"", 'type', '"string"']; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property','PSC',$child_array, 'name', '"PSC"', 'displayName', '"State Code"']; push(@{$property_array},$property_tagArrayRef); # PST my($fixStateDesc)=$fixState; $fixStateDesc=~s/^A$/APPLIED/; $fixStateDesc=~s/^B$/BROKEN/; $fixStateDesc=~s/^C$/COMMITTED/; $fixStateDesc=~s/^E$/EFIXLOCKED/; $fixStateDesc=~s/^O$/OBSOLETE/; $fixStateDesc=~s/^.$/UNKNOWN/; $child_tagArrayRef=['Value',$fixStateDesc,"", 'type', '"string"']; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property','PST',$child_array, 'name', '"PST"', 'displayName', '"State"']; push(@{$property_array},$property_tagArrayRef); # PAI my($automaticBoolean)=$automatic; $automaticBoolean=~s/^1$/true/; $automaticBoolean=~s/^0$/false/; $child_tagArrayRef=['Value',$automaticBoolean,"", 'type', '"boolean"']; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property','PAI',$child_array, 'name', '"PAI"', 'displayName', '"Automatically Installed"']; push(@{$property_array},$property_tagArrayRef); # PLC my($efixLockedBoolean)=$efixLocked; $efixLockedBoolean=~s/^1$/true/; $efixLockedBoolean=~s/^0$/false/; $child_tagArrayRef=['Value',$efixLockedBoolean,"", 'type', '"boolean"']; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property','PLC',$child_array, 'name', '"PLC"', 'displayName', '"Locked"']; push(@{$property_array},$property_tagArrayRef); # PMF $child_tagArrayRef=['Value',$messCat,"", 'type', '"string"']; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property','PMF',$child_array, 'name', '"PMF"', 'displayName', '"Message File"']; push(@{$property_array},$property_tagArrayRef); # PMT $child_tagArrayRef=['Value',$messSet,"", 'type', '"string"']; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property','PMT',$child_array, 'name', '"PMT"', 'displayName', '"Message Set"']; push(@{$property_array},$property_tagArrayRef); # PMI $child_tagArrayRef=['Value',$messNum,"", 'type', '"string"']; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property','PMI',$child_array, 'name', '"PMI"', 'displayName', '"Message Identifier"']; push(@{$property_array},$property_tagArrayRef); # PPN $child_tagArrayRef=['Value',$productIdHash{$fileset},"", 'type', '"string"']; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property','PPN',$child_array, 'name', '"PPN"', 'displayName', '"Product Name"']; push(@{$property_array},$property_tagArrayRef); my $fileset_tagArrayRef=['Resource',$fileset,$property_array, 'displayName', '"'.$fileset.'"', 'uniqueId', $uniqueId]; push(@{$filesets_array},$fileset_tagArrayRef); } # end foreach $line my $filesets_tagArrayRef=['ResourceList','',$filesets_array, 'displayName', '"Components"']; my $sysProp_array=[]; # HN $child_tagArrayRef=['Value',$clientHostname,"", 'type', '"string"']; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property','HN',$child_array, 'name', '"HN"', 'displayName', '"HostName"']; push(@{$sysProp_array},$property_tagArrayRef); # OS my $OSLevel="AIX ".$clientOSLevel; $child_tagArrayRef=['Value',$OSLevel,"", 'type', '"string"']; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property','OS',$child_array, 'name', '"OS"', 'displayName', '"Operating System"']; push(@{$sysProp_array},$property_tagArrayRef); push(@{$sysProp_array},$filesets_tagArrayRef); my $client_tagArrayRef=['Resource',$client,$sysProp_array, 'displayName', '"'.$client.'"', 'uniqueId', '"'.$client.'"']; my $xml_arrayRef=$client_tagArrayRef; return $xml_arrayRef; } # end _createXmlStructure # Function: _createXmlRCStructure(client_str) # Purpose: To create the array reference that will hold the filled in xml structure # for the xml document that is created from reading the LSLPP and LSLPP_PROD_INFO # variables. # Side effects: - # Returns: The tagArrayRef for an xml structure for the client passed in. # See SUMA::Util->writeXml for more details on structure. sub _createXmlRCStructure { ckPrivate(); my $client=shift; my $clientHostname=$client; my $clientOSLevel; if ($clientHostname eq "localhost") # localhost { $client=$hostname; $clientHostname=$hostname; $clientOSLevel=`/usr/bin/oslevel`; chomp($clientOSLevel); } else # nim client { $clientHostname=(`/usr/sbin/lsnim -Za if1 $client`)[1]; chomp($clientHostname); $clientHostname=(split(":",$clientHostname))[2]; $clientOSLevel=""; } my %productIdHash; foreach my $line (@LSLPP_PROD_INFO) { chomp($line); my($path,$fileset,$vendorCode,$prodId,$featureId,$parent,$extras); my($level); # field:1 2 3 4 5 6 7 ($path,$fileset,$vendorCode,$prodId,$featureId,$parent,$extras)=split(/:/,$line); ($fileset,$level)=split(/ /,$fileset); $productIdHash{$fileset}=$prodId; } my($packageName,$fileset,$level,$state,$ptfId,$fixState,$type,$desc); my($destDir,$uninstaller,$messCat,$messSet,$messNum,$parent,$automatic); my($efixLocked,$extras); my $filesets_array=[]; my ($child_tagArrayRef,$child_array,$property_tagArrayRef); foreach my $line (@LSLPP) { chomp($line); $line=~s/: :/::/g; # Make entries that are a space blank $line=~s/: :/::/g; # Need second run through $line=encode_entities($line); # html encode entries # field: 1 2 3 4 5 6 7 8 ($packageName,$fileset,$level,$state,$ptfId,$fixState,$type,$desc, # field: 9 10 11 12 13 14 15 $destDir,$uninstaller,$messCat,$messSet,$messNum,$parent,$automatic, # field: 16 17 $efixLocked,$extras)=split(/:/,$line); my $property_array=[]; # Description $child_tagArrayRef=['Value',$desc]; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property',"",$child_array, 'name', '"Description"', 'type', '"string"']; push(@{$property_array},$property_tagArrayRef); # Label my $uniqueId='"'.$fileset; $uniqueId.='_'.$destDir if ($destDir ne ""); $uniqueId.='"'; $child_tagArrayRef=['Value',$fileset]; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property',"",$child_array, 'name', '"Label"', 'type', '"string"']; push(@{$property_array},$property_tagArrayRef); # MaintenanceVersion $child_tagArrayRef=['Value',$level]; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property',"",$child_array, 'name', '"MaintenanceVersion"', 'type', '"string"']; push(@{$property_array},$property_tagArrayRef); # Version $child_tagArrayRef=['Value',$level]; $child_array=[$child_tagArrayRef]; $property_tagArrayRef=['Property',"",$child_array, 'name', '"Version"', 'type', '"string"']; push(@{$property_array},$property_tagArrayRef); # Use the V in VRMF of bos.rte for oslevel if it is a client if (($clientOSLevel eq "") && ($fileset eq "bos.rte")) { $clientOSLevel=substr($level,0,1); $clientOSLevel.=".0.0.0"; } my $fileset_tagArrayRef=['ResourceInstance', "", $property_array, 'resourceName', '"'.$fileset.'"', 'resourceId', '""', 'resourceType', '"SoftwareUpdate"']; push(@{$filesets_array},$fileset_tagArrayRef); } # end foreach $line my $filesets_tagArrayRef=['ResourceList','',$filesets_array, 'resourceType', '"SoftwareElement"']; my $sysProp_array=[]; push(@{$sysProp_array},$filesets_tagArrayRef); my $xml_arrayRef=$filesets_tagArrayRef; return $xml_arrayRef; } # end _createXmlRCStructure # Function: _writeXmlTail(writer_fh) # Purpose: To write the last two end tags to the filehandle passed in. # Side effects: Writes to filehandle. # Returns: 0 success sub _writeXmlTail { ckPrivate(); my $writer=shift; print($writer " \n"); print($writer " \n"); } # end _writeXmlTail # Function: _writeXmlRCTail(writer_fh) # Purpose: To write the last tag to the filehandle passed in. # Side effects: Writes to filehandle. # Returns: 0 success sub _writeXmlRCTail { ckPrivate(); my $writer=shift; print($writer " \n"); } # end _writeXmlRCTail # Function: ckPrivate(variable_str) # Purpose: To clean the taint from a variable passed in. # A clean variable in this function will contain only # alphanumerics, underscore, hyphen, at-sign, or a period. # Side effects: - # Returns: The variable passed in untainted if it was clean, or # "" if it was not a valid value. sub _clean { ckPrivate(); my $value=shift; if ($value =~ /^([-\@\w.]+)$/) { $value=$1; } else { mesg(LVL_DEBUG, MSG_GENERIC, "Invalid value: $value"); $value=""; } } # end _clean 1;