#!/bin/sh -- # Really perl
eval 'exec perl $0 ${1+"$@"}'
if 0;
#########################################################################
# Name: Patch Check Tool
#
# Version #: 1.1
#
# Description
# ===========
# 
# The Sun Patch Check tool is a diagnostic tool that enables system administrators
# to examine a profile of the patches installed on their Solaris system against
# the most current profiles available from Sun Microsystems with respect to:
# 
#  - latest revisions
#  - recommended patches
#  - security patches
#  - year 2000 patches
#  - other patches relevant to the software environment
# 
# The results of Patch Check can help a system administrator quickly
# determine and analyze the need for applying additional patches or newer 
# revisions of existing patches. The results will also allow the
# system administrator to select desired patches and receive them from Sun.
# 
# For installation and other notes, please read the userguide file that comes with
# the Sun Patch Check tool.
#
#########################################################################
#
#    This program is distributed WITHOUT ANY WARRANTY; without even the 
#    implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
#    PURPOSE.  
#
#########################################################################
#
#       Copyright 1996 Sun Microsystems, Inc. All Rights Reserved.
#             Manufactured in the United States of America.
# 2550 Garcia Avenue, Mountain View, California, 94043-1100 U.S.A.
# 
# This product and related documentation is protected by copyright and
# distributed under licenses restricting its use, copying, distribution
# and decompilation.  No part of this product or related documentation
# may be reproduced in any form by any means without prior written
# authorization of Sun and its licensors, if any.
# 
# Portions of this product may be derived from the UNIX(R) and Berkeley
# 4.3 BSD systems, licensed from UNIX Systems Laboratories, Inc. a wholly
# owned subsidiary of Novell, Inc. and the University of California,
# respectively.  Third party software, including font technology, in this
# product is protected by copyright and licensed from Sun's suppliers.
# 
# RESTRICTED RIGHTS LEGEND:  Use, duplication, or disclosure by the
# government is subject to restrictions as set forth in subparagraph
# (c)(1)(ii) of the Rights in Technical Data and Computer Software clause
# at DFARS 252.227-7013 and FAR 52.227-19.
# 
# Sun, Sun Microsystems, the Sun Logo, Solaris, SunOS, SunSoft, the
# SunSoft Logo, ONC, NFS, OpenWindows, DeskSet, AnswerBook, SunLink,
# SunView, SunDiag, NeWS, OpenBoot, OpenFonts, SunInstall, SunNet,
# ToolTalk, X11/NeWS and XView are trademarks or registered trademarks of
# Sun Microsystems, Inc in the U.S.  and certain other countries.  OPEN
# LOOK is a registered trademark of Novell, Inc.  UNIX is a registered
# trademark in the U.S. and other countries, exclusively licensed through
# X/Open, Ltd.  PostScript is a registered trademark of Adobe Systems,
# Inc.  All other product names mentioned herein are the trademarks of
# their respective owners.
# 
# All SPARC trademarks, including the SCD Compliant Logo, are trademarks
# or registered trademarks of SPARC International, Inc.  SPARCstation,
# SPARCserver, SPARCengine, SPARCworks and SPARCompiler are licensed
# exclusively to Sun Microsystems, Inc.  Products bearing SPARC
# trademarks are based upon an architecture developed by Sun
# Microsystems, Inc.
# 
# The OPEN LOOK(R) and Sun(TM) Graphical User Interfaces were developed
# by Sun Microsystems, Inc. for its users and licensees.  Sun
# acknowledges the pioneering efforts of Xerox in researching and
# developing the concept of visual or graphical user interfaces for the
# computer industry.  Sun holds a non-exclusive license from Xerox to the
# Xerox Graphical User Interface, which license also covers Sun's
# licensees who implement OPEN LOOK GUIs and otherwise comply with Sun's
# written license agreements.
# 
# The X Window System is a product of the Massachusetts Institute of
# Technology.
# 
#########################################################################
#
$usage = <<"THEEND";

Usage:  perl patchk 	[ -b ]
			[ -l ]
                 	[ -s <sfile> <os_ver arch> [<remotename>] ]
                 	[ -p <pfile> <sfile> <os_ver> <arch> [<remotename>] ]
                 	[ -x <xref> ]
                 	[ -h | -? ]

        where:
       
        <arch>   is the architecture of the system where the data was obtained. 
        	        Valid settings for <arch> are: 					
       
        	        - sparc
        	        - i386
        
        	        If the architecture of the system is not specified, the system
        	        assumes 'sparc'.
       
        <sfile>  is a file containing showrev -p output.
       
        <pfile>  is a file containing pkginfo -l output.
       
        <os_ver> is the OS version; this must be a SunOS number, not Solaris. 
        	        Use "5.5", not "2.5" for "Solaris 2.5".

        <remotename> is remote host name other than that is on the same host
                     machine.

	<xref>	 is a file containing the patch cross-reference data; the default 
		 name for this is "patchdiag.xref". 

        With no flags, the Patch Check tool will invoke a showrev -p on the
        system where it is running and print out the standard audit report
        which contains the installed, uninstalled recommended and uninstalled
        security patches.
		
	-b	places the output of this program in a formatted HTML file
		which includes a form, allowing the user to select patches,
		submit a request and receive the patches via the Internet
	
        -l	prints out a long audit report which includes other patches
		pertinent to packages that have been already installed.

	-s <sfile> <os_ver> <arch>
		prints out the standard audit report using file containing
		the output from showrev -p.

	-p <pfile> <sfile> <os_ver> <arch>
		prints out the long audit report using files containing
		the outputs from showrev -p and pkginfo -l.

	-x <xref>
		uses a different cross reference file than that
		is in the same directory as the patchk script.
		
	-h | -?	
		prints this help message.

THEEND

# if the PERL version is less than 5, just end it now
$perlVersion = $];
if ($] < 5) {
	print "You are trying to run patchk.pl under PERL version $].\nIt requires PERL 5 or greater.\n";
	print "Please try running the script again using PERL 5 or greater.\n";
	exit;
}

# run in debug mode
#$debug = 1;

$separator= "======================================================================================\n";
$separator_html = "<hr noshade width=90% align=center>";

$sec_header=<<'ROGUE';
Patch  Installed Latest   Synopsis
  ID   Revision  Revision
------ --------- -------- ------------------------------------------------------------
ROGUE
#
$sec_header_html=<<'SECHEADEREND';
<tr>
  <th>Patch ID</th>
  <th>Current<br>Revision</th>
  <th>Latest<br>Revision</th>
  <th align="left">Synopsis</th>
</tr>
SECHEADEREND

$sec_header_w_age=<<'ZION';
Patch  Ins Lat Age  Require    Incomp  Synopsis
  ID   Rev Rev        ID         ID
------ --- --- --- --------- --------- -----------------------------------------
ZION
#
$sec_header_w_age_html=<<'SECHEADERWAGEEND';
<tr>
  <th>Patch ID</th>
  <th>Ins<br>Rev</th>
  <th>Lat<br>Rev</th>
  <th>Age</th>
  <th>Require ID</th>
  <th>Incomp ID</th>
  <th>Synopsis</th>
</tr>
SECHEADERWAGEEND

$pkg_header=<<'LARN';
Patch    Package   Lat Age Synopsis
  ID     Name      Rev
------ - --------- --- --- ------------------------------------------------------------
LARN
#
$pkg_header_html=<<'PKGHEADEREND';
<tr>
  <th>Patch ID</th>
  <th>Package<br>Name</th>
  <th>Lat<br>Rev</th>
  <th>Age</th>
  <th>Synopsis</th>
</tr>
PKGHEADEREND

$disclaimer=<<'MORIA';
Report Note:

Recommended patches are considered the most important and highly
recommended patches that avoid the most critical system, user, or
security related bugs which have been reported and fixed to date.
A patch not listed on the recommended list does not imply that it
should not be used if needed.  Some patches listed in this report
may have certain platform specific or application specific dependencies
and thus may not be applicable to your system.  It is important to
carefully review the README file of each patch to fully determine
the applicability of any patch with your system.
MORIA

$PROGNAME = "patchk";
$REVISION = "1.3";
$VERSION = "1.1";

#============================================== 
# Setting parameters
#============================================== 

# include timelocal from standard library
#require "timelocal.pl";
use Time::Local;

# location of the cross reference file
$DATADIR=@ENV{XREF};
if ( $DATADIR eq '' ) {
	$DATADIR=$0;
	if ( $DATADIR !~ /\// ) {
		$DATADIR='.';
	}
	else {
		$DATADIR=~s/\/[^\/]*$//;
	}
}

$XREF="$DATADIR/patchdiag.xref";
$filename = "patches" . time . ".html";
$html_file = "/tmp/" . $filename;


#============================================== 
# Subroutines
#============================================== 
sub alreadydisplayed{
#	
#	true if patch has already been displayed
#
	local($searchid) = $_[0];
	shift @_;
	local(@searcharray) = @_;
	local($i);
#	$TRUE = 1;
#	$FALSE = 0;
        foreach $i ( @searcharray ) {
             if ($searchid == $i) { return $TRUE }
        }
	return $FALSE
}

sub checkpkginfofile{
#
#	true if pkginfo is specified, exists and is readable
#
   	$pfile = shift @ARGV;
	if ( $pfile eq '' ) { 
		print "$PROGNAME: no pkginfo file specified.\n";
		print "\t  Rerun command with proper parameters \n";
		die "$usage"; 
	}
	-r $pfile || die "$PROGNAME: Can't find pkginfo file ($pfile)!";
}

sub checkshowrevfile{
#
#	true if showrev file is specified, exists and is readable
#
   	$sfile = shift @ARGV;
	if ( $sfile eq '' ) { 
		print "$PROGNAME: no showrev file specified.\n";
		print "\t  Rerun command with proper parameters \n";
		die "$usage"; 
	}
        -r $sfile || die "$PROGNAME: Can't find showrev file ($sfile)!"
}

sub checkarch{
#
#	true if valid architecture
#
	$system_arch = shift @ARGV;
	if ( $system_arch ne "sparc" && 
	     $system_arch ne "i386" &&
	     $system_arch ne "ppc" &&
	     $system_arch ne "" ) {
		print "$PROGNAME: incorrect architecture parameter ($system_arch)\n";
		print "\t  Rerun command with correct arch.\n";
		print "\t  $PROGNAME accepts: \'sparc\', \'i386\' and \'ppc\'.\n";
		exit;
	}
}

sub checkos{
#
#	true if OS type is valid
#
	$system_os = shift @ARGV; 
	if ( $system_os !~ /[0-9][0-9]*\.[0-9].*/) {
		print "$PROGNAME: OS version specified ($system_os)\n";
		print "\t  doesn't seems to be valid.\n";
		print "\t  Please specify a valid SunOS version number\n";
		print "\t  such as '5.5' and try again.\n";
		exit;
	}
}

sub checkhostname{
#
#       set flag on if remote host name is specified
#
        $hostname = shift @ARGV;
        if ( $hostname ne "" ) { $localhost = $FALSE; }
}

sub checkxref{
#
#	true if xref file exists and is readable
#
	if (( ! -e $XREF ) && ( -e uc($XREF))) {
		$XREF = uc($XREF);
	}
	if ( ! -e $XREF ) {
		print "$PROGNAME: cross reference file specified by\n";
		print "\t  the environment variable XREF ($XREF) or the -x option\n";
		print "\t  does not exist.\n";
		print "\t  Please check the directory and make sure the file\n";
		print "\t  exists or please modify the XREF environment variable\n";
		print "\t  in the startup script.\n";
		exit;
	}
	if ( ! -r $XREF ) {
		print "$PROGNAME: cross reference file specified by\n";
		print "\t  the environment variable XREF ($XREF) or the -x option\n";
		print "\t  is not readable.\n";
		print "\t  Please check the permissions on the file and the directory\n";
		print "\t  and modify if necessary before retrying.\n";
		exit;
	}
	if ( ! -f $XREF ) {
		print "$PROGNAME: cross reference file specified by\n";
		print "\t  the environment variable XREF ($XREF) or the -x option\n";
		print "\t  is not a file.\n";
		print "\t  Please check the path or the name that you specified\n";
		print "\t  and modify if necessary before retrying.\n";
		exit;
	}
}

sub calculateage{
#
#       calculate the age of the patch according to current date
#
        $DAY = 24 * 60 * 60;
        %MONTHS = ( "Jan", 0,
                    "Feb", 1,
                    "Mar", 2,
                    "Apr", 3,
                    "May", 4,
                    "Jun", 5,
                    "Jul", 6,
                    "Aug", 7,
                    "Sep", 8,
                    "Oct", 9,
                    "Nov", 10,
                    "Dec", 11 );
        ( $lmonth, $day, $year ) = split(/\//, $_[0]);
        $month = $MONTHS{$lmonth};
        $start = timelocal( 1, 1, 1, $day, $month, $year );
        $end = time;
#print "this is test:start=$start,end=$end,day=$day,month=$month,yr=$year\n";
        $age = int( ( $end - $start ) / $DAY );
}

sub retrieveids{
#
#	retrieve require or incompatible patch ids which are embedded in architecture or
#	package field
#
	$i = 0;
	local(@temp_list) = split( /\;/, $_[0] );
        local(@id_list);
	foreach $token( @temp_list ) {
		if ( $token =~ /^\d+/ ) {
			$id_list[$i++] = $token;
		}
	}
	return @id_list;
}

sub preformat{
#
#	preformat the patch id print
#	
	$reqId = "         ";
	$incmpId = "         ";
	$reqCount = @req_list;
	$incmpCount = @incmp_list;
	$firstTime = $TRUE;

	if (($reqCount | $incmpCount) == 0)
	{
		&printuninstalled;
	}
	else {
		while ( ( $reqCount != 0 ) || ( $incmpCount != 0 ) ) {
			$reqId = "         ";
			$incmpId = "         ";
			if ($reqCount != 0) {
				$reqId = shift( @req_list );
				$reqCount = @req_list;
			}
			if ($incmpCount != 0) {
				$incmpId = shift( @incmp_list );
				$incmpCount = @incmp_list;
			}

			if ($firstTime eq $TRUE) {
				&printuninstalled;
				$firstTime = $FALSE;
			}
			else {
				&printpatchid;
			}
		}
	}
}

sub printinstalled{
	&printp ( ($htmlformat) ? "<tr valign=top>\n  <td><input type=\"checkbox\" name=\"" . &getCheckboxName() . "\" value=\"patches/$id\">  $id&nbsp;</td>\n  <td align=center><font color=\"blue\">$irev&nbsp;</font></td>\n  <td align=\"center\">$crev&nbsp;</td>\n  <td align=left>$synopsis&nbsp;</td>\n</tr>" :
	  "$id    $irev        $crev    $synopsis\n" );
}

sub printcurrent{
	&printp ( ($htmlformat) ?  "<tr valign=top>\n  <td>&nbsp;&nbsp;$id&nbsp;</td>\n  <td align=center><font color=\"green\">$irev&nbsp;</font></td>\n  <td align=\"center\"><font color=\"green\">CURRENT</font></td>\n  <td align=left>$synopsis&nbsp;</td>\n</tr>" :
	"$id    $irev     CURRENT  $synopsis\n" );
}

sub printuninstalled{
	if ($htmlformat) {
	  &printp ("<tr valign=top>\n  <td><input type=\"checkbox\" name=\"" . &getCheckboxName() . "\" value=\"patches/$id\">  $id&nbsp;</td>\n  <td align=center>$irev&nbsp;</td>\n  <td align=center>$crev&nbsp;</td>\n  <td align=center>$age&nbsp;</td>\n  <td align=center>$reqId&nbsp;</td>\n  <td align=center>$incmpId&nbsp;</td>\n  <td align=left>$synopsis&nbsp;</td>\n</tr>");
	} else {
	  printf "%6d %3s %3s %3d %9s %9s %s\n", $id, $irev, $crev, $age, $reqId,
$incmpId, $synopsis;
	}
}

sub printpatchid{
	if ($htmlformat) {
		&printp ("<tr valign=top>\n  <td>&nbsp;</td>\n  <td>&nbsp;</td>\n  <td>&nbsp;</td>\n  <td>&nbsp;</td>\n  <td>$reqId&nbsp;</td>\n  <td>$incmpId&nbsp;</td>\n  <td>&nbsp;</td>\n</tr>");
	} else {
	        &printp ("                   $reqId $incmpId\n");
	}
}

sub printlong{
	if ($htmlformat) {
	  &printp ("<tr valign=top>\n  <td><input type=\"checkbox\" name=\"" . &getCheckboxName() . "\" value=\"patches/$id\">  $id&nbsp;&nbsp;&nbsp;$glyph</td>\n  <td align=center>$package</td>\n  <td align=center>$crev</td>\n  <td align=center>$age</td>\n  <td>$synopsis</td></tr>");
	} else {
          printf "%6d %1s %-10s %2s %3d %s\n", $id, $glyph, $package, $crev, $age, $synopsis;
        }

}

sub printpkg{
	if ($htmlformat) {
		&printp ("<tr valign=top>\n  <td>&nbsp;</td>\n  <td>$package</td>\n  <td>&nbsp;</td>\n  <td>&nbsp;</td>\n  <td>&nbsp;</td>\n</tr>");
	} else {
		&printp ("         $package\n");
	}
}

# call this instead of print, so that it either prints to STDOUT 
# or (if we're in HTML mode) prints to the .html file
sub printp {
	my($arg);
	if (@_) {
		if ($htmlformat) {
			if (open(HTMLFILE, ">>$html_file")) {
				foreach $arg (@_) {
					print HTMLFILE "$arg";
				}
				close HTMLFILE;
			} else {
				$html_file = $filename;
				( open(HTMLFILE, ">>$html_file") || die "Unable to write to file " . $html_file );
				foreach $arg (@_) {
					print HTMLFILE "$arg";
				}
				close HTMLFILE;
			}
			
		} else {
			foreach $arg (@_) {
				print "$arg";
			}
		} 
	}
}

sub makeDateFromTime {
	my($arg);
	my(@months);
	if (!@_) {
		return "Jan/00/00";
	}
	foreach $arg (@_) {
		($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($arg);
		@months = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
		if ($year > 100) { $year = ($year - 100); }
		if ($year < 10) { $year = "0$year"; }
		if ($mday < 10) { $mday = "0$mday"; }
		return "$months[$mon]/$mday/$year";
	}
}
		

sub getCheckboxName {
	return "doc" . $counterVar++;
}

sub compareXrefDateToCurrentDate {
	chomp ($datestamp);
	if ($datestamp =~ /(Jan|Feb|Mar|Apr|Mar|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\/[0-3]{1}[0-9]{1}\/[0-9]{2}$/) {
		if (($datestamp ne $currentDate) && ($datestamp ne $yesterDate)) {
			print <<DONEWARNING
	
============================= WARNING =============================
The date of the cross-reference (patchdiag.xref) file is $datestamp, 
while the date reported by your system is $currentDate. Processing 
of this program will continue, but you may have an out-of-date 
cross-reference file. If you are not sure that you have the most 
up-to-date cross-reference file, please visit
  http://sunsolve.Sun.COM/private-cgi/patchDownload.pl?target=patchdiag.xref&method=H
or
  ftp://sunsolve.sun.com/pub/patches/patchdiag.xref
to retrieve it, and run this program again.
===================================================================

DONEWARNING
		}
	}
}
	

#============================================== 
# BEGIN
#============================================== 

# Boolean defines
$TRUE = 1;
$FALSE = 0;

$blank=' ';

# process the commandline arguments

$mode = "AUDIT";     # default mode
$datamode = "LOCAL"; # default data mode - xref coadjacent
$localhost = $TRUE;
$htmlformat = $FALSE;

while ( @ARGV ) {
	$_ = shift;
	if    (/-[^- ]*l/ ) { $mode = "LONG"; }
	elsif (/-[^- ]*p/ ) { 
		$mode = "PKGINFO"; 

		&checkpkginfofile;
		&checkshowrevfile;
		&checkos;
		&checkarch;
		&checkhostname;
	}
	elsif (/-[^- ]*s/ ) { 
		if ( $mode ne "PKGINFO" ) { $mode = "SHOWREV"; }

		&checkshowrevfile;
		&checkos;
		&checkarch;
		&checkhostname;
	}
	elsif (/-[^- ]*x/ ) { 
		$datamode = "EXTRA";
		$XREF = shift;
	}
	elsif (/-[^- ]*[h?]/ ) { 
		print $usage;
		exit;
	}
	elsif (/-[^- ]*b/ ) {
		$htmlformat = $TRUE;
	}
	else { 
		print "Unknown option: $_\n";
		print "$usage";
		die "$PROGNAME: Please specify the correct option and try the command again.\n";
	}
}
# if we're in HTML mode, we need to set up variables to store patch IDs, for hidden fields
# near the end of the script that get submitted with the patchsuite form
$currently_installed_patches = "";
$recommended_patches = "";
$security_patches = "";
$other_patches = "";
$y2kinst_patches = "";
$y2kuninst_patches = "";
# The array below will be a cross-reference array, which stores currently-installed
# patches and their installed revisions.  Where the patch ID will be 
# $installed_patches_and_revs[n], the patch revision number will be 
# $installed_patches_and_revs[n+1]
@installed_patches_and_revs = ();

$counterVar = 0;

&checkxref;
# if mode requires input files, then make sure that the system_os is specified
if (( $mode eq "PKGINFO" || $mode eq "SHOWREV" ) && $system_os eq '' ) {
	print "$PROGNAME: no os version specified.\n";
	print "\t  Please specify the SunOS version of the system from which the\n";
	print "\t  information was obtained and rerun the command.\n";
	print "\t  Please note that SunOS version numbers are like \"5.4\".\n";
	exit;
}
	
if ( $mode eq "PKGINFO" && $sfile eq '' ) {
	print "$PROGNAME: -p option requires a showrev output file as well.\n";
	print "\t  Please provide the name of the showrev output file and try\n";
	print "\t  the command again\n";
	exit;
}

# capture the uname output - needed for all options

open( UNAME, "/usr/bin/uname -nrp |" );
$uname = <UNAME>;
close( UNAME );

if ( $mode eq "AUDIT" || $mode eq "LONG" ){
# 	parse uname output to get OS & Arch
	($name, $os, $arch) = split( / /, $uname);
	$arch =~ s/[\n\t ]*//g;
	if ( $arch eq "" ) { $arch = "ERROR";}
}
else {
	$name = "Remote System";
	$arch = "sparc";
	if ( $system_arch ne '' ){ $arch = $system_arch;}
	$os = $system_os;
}

if ($localhost == $FALSE) {$name=$hostname};

# capture the date stamp of the XREF file

open( XREF, "head -1 $XREF |");
$datestamp=<XREF>;
$datestamp=~s/^.* OF //;
$datestamp=~s/ ##//;

# capture the current date and format in the same manner as that expected from the XREF file
#($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
#@months = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
#if ($year > 100) { $year = ($year - 100); }
#if ($year < 10) { $year = "0$year"; }
#if ($mday < 10) { $mday = "0$mday"; }
#$currentDate = "$months[$mon]/$mday/$year";
$currentDate = &makeDateFromTime( time );
$yesterDate = &makeDateFromTime( (time - 86400) );
&compareXrefDateToCurrentDate();
print ("processing...\n");
# standard processing

if ( $mode eq "AUDIT" || $mode eq "LONG" || $mode eq "PKGINFO" || $mode eq "SHOWREV" )
{
 
  if ($htmlformat) {
  	$topPartOfHtml = <<"ENDOFTOPHTML";
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>Sun(TM) Patch Check Tool Report</title>

<style type="text/css">
  BODY, TH, TD, P, DIV, SPAN, .main, .date-stamp, .redlink, INPUT, SELECT, TEXTAREA, FORM, UL, OL, DL, H1, H2, H3, H4, H5, H6, B, STRONG, I, U, LI, .sunfont {font-size:10pt;font-family:geneva, helvetica, arial, "lucida sans", sans-serif}
  H1, H2, H3, H4, H5, H6 {margin:2px 0px;padding:0px}
  H1, H2, H3, H1 SPAN, H2 SPAN, H3 SPAN {font-size:16pt}
  .large {font-size:16pt}
  H4, H4 SPAN {font-size:15pt}
  H5, H6, H5 SPAN, H6 SPAN, BIG, .big, BIG SPAN {font-size:12pt}
  SMALL, .small, SUP, BR, SMALL SPAN {font-size:9pt}  
  .green {color:#090}
  .srsdkgrn {color:#9F9}
  .srsltgrn {color:#9F9}
  .srsred {color:#F99}
  .srsyel {color:#FF9}
  TD.srsdkgrn, TH.srsdkgrn, TR.srsdkgrn TD, TR.srsdkgrn TH, TABLE TR TD.srsdkgrn, TABLE TR TH.srsdkgrn {background:#9F9;color:#000}
  TD.srsltgrn, TH.srsltgrn, TR.srsltgrn TD, TR.srsltgrn TH, TABLE TR TD.srsltgrn, TABLE TR TH.srsltgrn {background:#9F9;color:#000}
  TD.srsred, TH.srsred, TR.srsred TD, TR.srsred TH, TABLE TR TD.srsred, TABLE TR TH.srsred {background:#F99;color:#000}
  TD.srsyel, TH.srsyel, TR.srsyel TD, TR.srsyel TH, TABLE TR TD.srsyel, TABLE TR TH.srsyel {background:#FF9;color:#000}
  TD.statmsg, TH.statmsg, TR.statmsg TD, TR.statmsg TH, TABLE TR TD.statmsg, TABLE TR TH.statmsg {background:#FFF;color:#F00;font-weight:bold;text-transform:uppercase}
  CODE, KBD, TT {font-family:monaco, courier, courier new;font-size:10pt;color:#66
  6}
  A:link {color:#669}
  A:active {color:#F00}
  A:visited {color:#336}
  A:hover {color:#99C}
  DT {font-weight:bold;padding-top:5px}
  UL {list-style:disc}
  UL UL {list-style:circle}
  UL UL UL {list-style:square}
  HR {color:#000;height:1px}
  
<!-- (** -->
  /* TEMPLATE CLASSES */ 
  .gnlnk {color:#F90}
  .brd {padding:3px 8px;font-weight:bold}
  .mstmnu {padding-top:0px;padding-bottom:1px;padding-left:2px;margin-top:0px;margin-bottom:0px;float:left}
  .srchbx {padding-top:0px;padding-bottom:1px;margin-top:0px;margin-bottom:0px;float:right}
  .gfbtn {padding-left:3px;padding-right:3px}
  .hde {visibility:hidden}
  A.nonu:link, A.nonu:visited, A.nonuc:active {text-decoration:none;color:#000}
  A.nonu:active, A.nonu:hover, A.nonuc:link, A.nonuc:visited {text-decoration:none;color:#F00}
  A.nonuc:hover {text-decoration:none;color:#333}
  TD.citm {padding-right:2px;color:#F00;text-align:right}
  TD.itm {padding-right:2px;color:#000;text-align:right}
  TD.rcitm {padding-right:2px;color:#F00;text-align:left}    
  TD.ritm {padding-right:2px;color:#000;text-align:left}
  A.nonuw:link, A.nonuw:visited {text-decoration:none;color:#FFF}
  A.nonuw:active {text-decoration:none;color:#F00}
  A.nonuw:hover {text-decoration:none;color:#CCF}
  A.undw:link, A.undw:visited {color:#FFF}
  A.undw:active {color:#F00}
  A.undw:hover {color:#CCF}
  TD.tid {color:#FFF;font-weight:bold;padding-left:4px;text-indent:4px}
  TD.wb1 {background:#C03;font-size:4pt}
  TD.wb2 {background:#C90;font-size:4pt}
  TD.wb3 {background:#CC3;font-size:4pt}
  TD.wb4 {background:#F90;font-size:4pt}
  TD.cpyftr {background:#000}
  DIV.cpyftr {padding:3px 7px 7px 8px;color:#FFF}

        /* CUSTOM CLASSES */
.prev-next {color:#C33;text-align:center}
.prev-next A:link, .prev-next A:visited, A.redlink:link, A.redlink:visited, A.redlink:active {color:#C33}
.prev-next A:hover, A.redlink:hover {color:#F00}
.frm, .bttn, SPAN.pull, SPAN.pull SELECT {background:#CCF;font-weight:bold;text-decoration:none;color:#000} 
.linespace, P.intro {line-height:112%}
.just {text-align:justify}
.bold, TR.bold TD, TR.bold TH {font-weight:bold}
.italic, TR.italic TD, TR.italic TH {font-style:italic}
.whtbld {color:#FFF;font-weight:bold}
.blkbld {color:#000;font-weight:bold}
.redbld {color:#F00;font-weight:bold}
.blknote, .note {color:#000;font-weight:bold;text-transform:uppercase}
.rednote, .new {color:#F00;font-weight:bold;text-transform:uppercase}
.updated {color:#F00;font-weight:bold;text-transform:uppercase;letter-spacing:.2em}
P.intro {font-weight:bold;color:#669}
P.quote {color:#900;padding-left:4%;padding-right:4%}
P.credit {padding-left:60px;padding-right:30px}
P.compact {margin-top:0px}
A.blklink:link, A.blklink:visited, A.blklink:active {color:#000}
A.blklink:hover {color:#666}
TD.black, TH.black, TR.black TD, TR.black TH, TABLE TR TD.black, TABLE TR TH.black {background:#000;color:#FFF}
TD.promo, TH.promo, TR.promo TD, TR.promo TH, TABLE TR TD.promo, TABLE TR TH.promo {background:#FC6;color:#000}                  
TD.present, TH.present, TR.present TD, TR.present TH, TABLE TR TD.present, TABLE TR TH.present {background:#C60;color:#FFF}
TD.dkred, TH.dkred, TR.dkred TD, TR.dkred TH, TABLE TR TD.dkred, TABLE TR TH.dkred {background:#C33;color:#FFF}
TD.ltred, TH.ltred, TR.ltred TD, TR.ltred TH, TABLE TR TD.ltred, TABLE TR TH.ltred {background:#F99;color:#000}
TD.dkblue, TH.dkblue, TR.dkblue TD, TR.dkblue TH, TABLE TR TD.dkblue, TABLE TR TH.dkblue {background:#669;color:#FFF}
TD.dktan, TH.dktan, TR.dktan TD, TR.dktan TH, TABLE TR TD.dktan, TABLE TR TH.dktan {background:#C96;color:#000}
TD.lttan, TH.lttan, TR.lttan TD, TR.lttan TH, TABLE TR TD.lttan, TABLE TR TH.lttan {background:#FFC;color:#000}
TD.dkgrey, TH.dkgrey, TR.dkgrey TD, TR.dkgrey TH, TABLE TR TD.dkgrey, TABLE TR TH.dkgrey {background:#666;color:#FFF}
TD.ltgrey, TH.ltgrey, TR.ltgrey TD, TR.ltgrey TH, TABLE TR TD.ltgrey, TABLE TR TH.ltgrey {background:#CCC;color:#000}
TD.ltblue, TH.ltblue, TR.ltblue TD, TR.ltblue TH, TABLE TR TD.ltblue, TABLE TR TH.ltblue {background:#CCF;color:#000}
TD.white, TH.white, TR.white TD, TR.white TH, TABLE TR TD.white, TABLE TR TH.white {background:#FFF;color:#000}
TABLE.promo {background:#FC6}
TABLE.present {background:#C60}
TABLE.dkgrey {background:#666}     
TABLE.ltgrey {background:#CCC}
TABLE.dkblue {background:#669}
TABLE.ltblue {background:#CCF}
TABLE.black {background:#000}
TABLE.white {background:#FFF}
TABLE.dkred {background:#C33}
TABLE.ltred {background:#F99}
TABLE.dktan {background:#C96}
TABLE.lttan {background:#FFC}
TABLE.pqt {margin:7px;padding:0px}
TABLE.pqt TD {background:#FFC;margin:0px;padding:0px}
DIV.pq {border:solid 1px #000;padding:5px 5px 0px 5px;margin:0px}
DIV.pq .quote {color:#000;font-weight:bold;padding:0px 0px 3px 0px;margin:0px}
DIV.pq .credit {font-weight:normal;padding:5px 0px 5px 0px;margin:0px}

        /* SUN.NET + MYSUN CLASSES */
A.btn:link, A.btn:visited {background:#CCF;text-decoration:none;color:#000;font-weight:normal}
A.btn:hover {background:#99C;text-decoration:none;color:#000;font-weight:normal}

A.btn:active {background:#C33;text-decoration:none;color:#FFF;font-weight:normal}                                               
TD.appbx, TH.appbx, TR.appbx TD, TR.appbx TH {background:#DDD;color:#000}
TABLE.appbx {background:#DDD}
TD.appcnt, TH.appcnt, TR.appcnt TD, TR.appcnt TH {background:#FFF;color:#000}
TABLE.appcnt {background:#FFF}
.pipe {color:#669}
.tbar {background:#669;color:#FFF;font-weight:bold}

        /* OLD CLASSES + DO NOT USE */
.localheader {font-size:15px;text-decoration:none;color:#DDD;}
.locallink, .localsublink {font-size:12px;text-decoration:none;color:#DDD;font-weight:normal}
A:link
.nonu {text-decoration:none;color:#000}
.nonuw {text-decoration:none;color:#FFF}
A:visited
.nonu {text-decoration:none}  
</style>

<!-- META INFORMATION BEGIN -->

<LINK REL="Stylesheet" TYPE="text/css" TITLE="Sunstyle" HREF="/style.css">

<!-- META INFORMATION END -->
<SCRIPT language="JavaScript">
<!--
function gotoFunction() {
		self.location = document.productGoto.productList.options[document.productGoto.productList.selectedIndex].value;
}
// -->
</SCRIPT>
<!-- **) -->

</head>
<body bgcolor="#666699">
<!-- (** -->
<!-- MASTHEAD BEGIN -->
<TABLE BORDER="0" CELLSPACING="0" CELLPADDING="0" WIDTH="100%" BGCOLOR="#000000">

<!-- LOGO/ID/GEN LINKS ROW BEGIN -->
<TR VALIGN="TOP">
<TD ALIGN="RIGHT" ROWSPAN="2" WIDTH="1%" BGCOLOR="#666699"><A HREF="http://sunsolve.sun.com/"><IMG SRC="http://sunsolve.sun.com/images/sunlogo.gif" WIDTH="119" HEIGHT="60" ALT="Sun Microsystems, Inc." BORDER="0"></A></TD>
<TD COLSPAN="3" WIDTH="99%">
<TABLE BORDER="0" CELLSPACING="0" CELLPADDING="0" WIDTH="100%"><TR>
<TD WIDTH="1" VALIGN="TOP"><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="1" HEIGHT="3" ALT="spacer"></TD>
<TD COLSPAN="2" VALIGN="TOP"><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="500" HEIGHT="1" ALT="spacer"></TD></TR>
<TR><TD WIDTH="1" BGCOLOR="#CCCCFF" VALIGN="TOP" ROWSPAN="2"><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="1" HEIGHT="19" ALT="spacer"></TD>

<!-- ID BEGIN -->
<TD NOWRAP HEIGHT="20" CLASS="tid"><A HREF="http://www.sun.com" CLASS="nonuw">sun.com</A></TD>
<!-- ID END -->

<TD ALIGN="RIGHT" NOWRAP CLASS="gnlnk">

			<!-- GENERAL LINKS BEGIN -->
<A HREF="http://www.sun.com/MySun/"><FONT COLOR="#FFFFFF" CLASS="nonuw">My Sun</FONT></A> |
<A HREF="http://www.sun.com/worldwide/"><FONT COLOR="#FFFFFF" CLASS="nonuw">Regional Sites</FONT></A> |
<A HREF="http://www.sun.com/siteindex/"><FONT COLOR="#FFFFFF" CLASS="nonuw">Site Index</FONT></A> |
<A HREF="http://www.sun.com/howtobuy/"><FONT COLOR="#FFFFFF" CLASS="nonuw">How To Buy</FONT></A>&nbsp;</FONT>
<!-- GENERAL LINKS END -->



</TD></TR>
<TR><TD COLSPAN="2" WIDTH="100%"><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="499" HEIGHT="1" ALT="spacer"></TD></TR>
<TR><TD ALIGN="RIGHT" COLSPAN="3" BGCOLOR="#CCCCFF"><IMG SRC="http://sunsolve.sun.com/images/fade.gif" WIDTH="1" HEIGHT="1" ALT="black dot"></TD></TR>
</TABLE>
</TD></TR>
<!-- LOGO/ID/GEN LINKS ROW END -->

<!-- PULL DOWN/SEARCH ROW BEGIN -->
<TR BGCOLOR="#666699"><TD HEIGHT="35">

<!-- SHORTCUTS PULL DOWN TABLE BEGIN -->
<FORM NAME="productGoto" ACTION="http://www.sun.com/cgi-bin/gotopic.cgi" METHOD="POST" CLASS="mstmnu">
<TABLE BORDER="0" CELLSPACING="0" CELLPADDING="0">
<TR><TD>
<SPAN CLASS="pull"><SELECT NAME="productList" ONCHANGE="gotoFunction()" ONBLUR="return options[0].selected = true">
<OPTION VALUE="#">SELECT A TOPIC
<OPTION VALUE="#">----------------------------
<OPTION VALUE="http://www.sun.com/store/">SUNSTORE
<OPTION VALUE="http://www.sun.com/dot-com/">HOW TO .COM
<OPTION VALUE="http://www.sun.com/dot-com/keynotes/">&nbsp;&gt; Executive Keynotes
<OPTION VALUE="http://www.sun.com/dot-com/perspectives/">&nbsp;&gt; Executive Perspectives
<OPTION VALUE="http://www.sun.com/dot-com/reading/">&nbsp;&gt; Executive Reading
<OPTION VALUE="http://www.sun.com/dot-com/studies/">&nbsp;&gt; Case Studies
<OPTION VALUE="http://www.sun.com/products-n-solutions/">PRODUCTS &amp; SOLUTIONS
<OPTION VALUE="http://www.sun.com/products-n-solutions/hardware/">&nbsp;&gt; Hardware
<OPTION VALUE="http://www.sun.com/products-n-solutions/software/">&nbsp;&gt; Software
<OPTION VALUE="http://www.sun.com/products-n-solutions/solutions/">&nbsp;&gt; Solutions, Resources &amp; Guides
<OPTION VALUE="http://www.sun.com/products-n-solutions/markets/">&nbsp;&gt; Markets &amp; Industries
<OPTION VALUE="http://www.sun.com/service/">SUPPORT, TRAINING &amp; CONSULTING
<OPTION VALUE="http://www.sun.com/service/online/">&nbsp;&gt; Online Support Center
<OPTION VALUE="http://www.sun.com/service/support/">&nbsp;&gt; Support Services
<OPTION VALUE="http://suned.sun.com/">&nbsp;&gt; Training
<OPTION VALUE="http://www.sun.com/service/sunps/">&nbsp;&gt; Consulting
<OPTION VALUE="http://www.sun.com/service/solutions/">&nbsp;&gt; Business Advantage Services
<OPTION VALUE="http://www.sun.com/service/channel/">&nbsp;&gt; Reseller Programs
<OPTION VALUE="http://www.sun.com/developers/">SUN DEVELOPER CONNECTION
<OPTION VALUE="http://www.sun.com/developers/communities/">&nbsp;&gt; Sun Technologies
<OPTION VALUE="http://www.sun.com/developers/tools/">&nbsp;&gt; Hardware, Software &amp; Tools
<OPTION VALUE="http://www.sun.com/developers/support/">&nbsp;&gt; Technical Support/Education
<OPTION VALUE="http://www.sun.com/developers/promote/">&nbsp;&gt; Co-Marketing
<OPTION VALUE="http://www.sun.com/aboutsun/">ABOUT SUN
<OPTION VALUE="http://www.sun.com/aboutsun/coinfo/">&nbsp;&gt; Company Information
<OPTION VALUE="http://www.sun.com/aboutsun/media/">&nbsp;&gt; Media Center
<OPTION VALUE="http://www.sun.com/aboutsun/investor/">&nbsp;&gt; Investor Relations
<OPTION VALUE="http://www.sun.com/aboutsun/sponsorships/">&nbsp;&gt; Sponsorships
<OPTION VALUE="http://java.sun.com/">JAVA.SUN.COM
</SELECT></SPAN></TD>
<TD><INPUT CLASS="gfbtn" TYPE="IMAGE" BORDER="0" SRC="http://sunsolve.sun.com/images/go.gif" VALUE="GO"></TD></TR>
</TABLE>
</FORM>
<!-- SHORTCUTS PULL DOWN TABLE END -->

</TD><TD ALIGN="RIGHT">

	<TABLE BORDER="0" CELLSPACING="0" CELLPADDING="2" CLASS="srchbx">
<TR VALIGN="MIDDLE" ALIGN="RIGHT">
<TD><FORM ACTION="http://www.sun.com/search/index.cgi" method=post></TD>
<TD><INPUT TYPE=TEXT SIZE="13" NAME="SYMBOL" VALUE=""></TD>
<TD><INPUT TYPE="image" BORDER="0" SRC="http://sunsolve.sun.com/images/searchbttn.gif"></TD>
<TD></FORM></TD>
</TR>
</TABLE>


</TD>
<TD VALIGN="TOP" ALIGN="RIGHT"><IMG SRC="http://sunsolve.sun.com/images/fade.gif" WIDTH="1" HEIGHT="22" ALT="black fade"></TD></TR>
<!-- PULL DOWN/SEARCH ROW END -->

</TABLE>
<!-- MASTHEAD END -->

<!-- NAV/BODY/FOOT BEGIN -->
<TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0">
<TR BGCOLOR="#000000"><TD COLSPAN="4"><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="620" HEIGHT="2" ALT="spacer"></TD></TR>

<!-- BREADCRUMB ROW BEGIN -->
<TR><TD BGCOLOR="#CCCCFF" COLSPAN="4"><DIV CLASS="brd">

<!-- BREADCRUMB BEGIN -->

<A HREF="http://www.sun.com/index.html"><FONT COLOR="#000000" CLASS="nonu" FACE="Geneva, Arial, Helvetica" SIZE="2">Home</FONT></A>
<IMG SRC="http://sunsolve.sun.com/images/right.gif" WIDTH="9" HEIGHT="9" ALT="" HSPACE="2">&nbsp;
<A HREF="http://sunsolve.sun.com/show.pl?target=home"><FONT COLOR="#000000" CLASS="nonu" FACE="Geneva, Arial, Helvetica" SIZE="2">SunSolve Online</FONT></A> 


<!-- BREADCRUMB END -->

</DIV></TD></TR>
<!-- BREADCRUMB ROW END -->

<TR VALIGN="TOP" BGCOLOR="#FFFFFF">

<!-- NAV CELL BEGIN -->
<TD WIDTH="145" ROWSPAN="2">
<TABLE WIDTH="100%" BORDER="0" CELLSPACING="0" CELLPADDING="0" BGCOLOR="#CCCCFF">

<!-- ============== -->
<!-- NAV ROWS BEGIN -->
<!-- ============== -->

<!-- 2 COL WHITE SPACER BEGIN -->

<TR BGCOLOR="#FFFFFF">
<TD><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="16" HEIGHT="1" ALT="spacer"></TD>
<TD><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="125" HEIGHT="1" ALT="spacer"></TD>
</TR>

<!-- 2 COL WHITE SPACER END -->

<TR VALIGN="TOP">
<TD COLSPAN="2">
			<TABLE BORDER="0" CELLSPACING="0" CELLPADDING="4" WIDTH="100%">

					<TR VALIGN="TOP" BGCOLOR="#333333">
					<TD COLSPAN="2"><FONT COLOR="#FFFFFF" SIZE="2">
						<B>Status:</B> Not Logged In</FONT></TD>
					</TR>

					<TR VALIGN="TOP" BGCOLOR="#CCCCCC">
					<TD COLSPAN="2"><FORM>
<!-- No can do!
					User Name:<BR>
					<INPUT TYPE="TEXT" SIZE="13" NAME="name" VALUE=""><BR>
					Password:<BR>
					<INPUT TYPE="TEXT" SIZE="13" NAME="passwrd" VALUE=""><BR>
-->
					<A HREF="http://sunsolve.sun.com/private-cgi/show.pl?target=home_con">
					<IMG BORDER="0" SRC="http://sunsolve.sun.com/images/login.gif"></a>&nbsp;
					<A HREF="http://sunsolve.sun.com/show.pl?target=registerFrontPage">
					<IMG BORDER="0" SRC="http://sunsolve.sun.com/images/register.gif"></a><br>
				   <FONT size=1><A HREF="http://sunsolve.sun.com/pub-cgi/lost-passwd.pl">Forgot Your Password?</A></FONT>
					</FONT></TD>
					</TR>
					</FORM>
				</TABLE>

</TD></TR>


<!-- 2 COL WHITE SPACER BEGIN -->

<TR BGCOLOR="#FFFFFF">
<TD><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="16" HEIGHT="1" ALT="spacer"></TD>
<TD><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="125" HEIGHT="1" ALT="spacer"></TD>
</TR>

<!-- 2 COL WHITE SPACER END -->

<!-- SECTION MANAGER BEGIN -->

			<!-- Beginning of Nav area -->
	<tr valign="TOP" bgcolor="#FFFFFF">
	<td rowspan="2" align="RIGHT" nowrap>
	<FONT COLOR="#FF0000" SIZE="2">-&nbsp; </FONT></a></td> 
	<td><a href="http://sunsolve.sun.com/show.pl?target=home">
	<font color="#FF0000" class="nonu" face="Geneva, Arial, Helvetica" size="2">SunSolve Online</font></a></td>
	</tr>
	<tr bgcolor="#FFFFFF"><td><table border="0" cellspacing="0" cellpadding="0" width="100%"><tr><td>
</td></tr></table>
	<tr valign="TOP" >
	<td rowspan="2" align="RIGHT" nowrap>
	<img src="http://sunsolve.sun.com/images/right.gif" width="9" height="9" alt="More" border="0"></a></td> 
	<td><a href="http://sunsolve.sun.com/pub-cgi/show.pl?target=patches/patch-access">
	<font color="#000000" class="nonu" face="Geneva, Arial, Helvetica" size="2">Patches</font></a></td>
	</tr>
	<tr ><td><table border="0" cellspacing="0" cellpadding="0" width="100%"><tr><td>
</td></tr></table>
	<tr valign="TOP" >
	<td rowspan="2" align="RIGHT" nowrap>
	<img src="http://sunsolve.sun.com/images/right.gif" width="9" height="9" alt="More" border="0"></a></td> 
	<td><a href="http://sunsolve.sun.com/pub-cgi/show.pl?target=help/collections">
	<font color="#000000" class="nonu" face="Geneva, Arial, Helvetica" size="2">Support Documents</font></a></td>
	</tr>
	<tr ><td><table border="0" cellspacing="0" cellpadding="0" width="100%"><tr><td>
</td></tr></table>
	<tr valign="TOP" >
	<td rowspan="2" align="RIGHT" nowrap>
	<img src="http://sunsolve.sun.com/images/right.gif" width="9" height="9" alt="More" border="0"></a></td> 
	<td><a href="http://sunsolve.sun.com/pub-cgi/show.pl?target=security/sec">
	<font color="#000000" class="nonu" face="Geneva, Arial, Helvetica" size="2">Security Information</font></a></td>
	</tr>
	<tr ><td><table border="0" cellspacing="0" cellpadding="0" width="100%"><tr><td>
</td></tr></table>
	<tr valign="TOP" >
	<td rowspan="2" align="RIGHT" nowrap>
	<img src="http://sunsolve.sun.com/images/right.gif" width="9" height="9" alt="More" border="0"></a></td> 
	<td><a href="http://sunsolve.sun.com/pub-cgi/search.pl?mode=advanced">
	<font color="#000000" class="nonu" face="Geneva, Arial, Helvetica" size="2">Advanced Search</font></a></td>
	</tr>
	<tr ><td><table border="0" cellspacing="0" cellpadding="0" width="100%"><tr><td>
</td></tr></table>

<!-- BIG SPACER BEGIN -->
<TR><TD COLSPAN="2"><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="2" HEIGHT="8" ALT="spacer"></TD></TR>
<!-- BIG SPACER END -->

<!-- 2 COLUMN WHITE SPACER BEGIN -->
<TR BGCOLOR="#FFFFFF"><TD><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="16" HEIGHT="1" ALT="spacer"></TD><TD><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="125" HEIGHT="1" ALT="spacer"></TD></TR>
<!-- 2 COLUMN WHITE SPACER END -->

<!-- SPACER BEGIN --><TR><TD COLSPAN="2"><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="3" HEIGHT="3" ALT="spacer"></TD></TR><!-- SPACER END -->

<!-- RELATED HEADING BEGIN -->

<TR><TD>&nbsp;</TD><TD CLASS="blkbld">SunSolve Related:</TD></TR>

<!-- RELATED HEADING END -->
		<tr valign="top" ><td align="right">
		<FONT COLOR="#000000" class="itm">-</td>
		<td><a href=http://sunsolve.sun.com/show.pl?target=link><font color="#000000" class="nonu">
		SunSolve Servers</font></a></td></tr>
		<tr valign="top" ><td align="right">
		<FONT COLOR="#000000" class="itm">-</td>
		<td><a href=http://sunsolve.sun.com/show.pl?target=about_sunsolve><font color="#000000" class="nonu">
		About SunSolve</font></a></td></tr>
		<tr valign="top" ><td align="right">
		<FONT COLOR="#000000" class="itm">-</td>
		<td><a href=http://sunsolve.sun.com/feedback.pl><font color="#000000" class="nonu">
		Feedback</font></a></td></tr>
		<tr valign="top" ><td align="right">
		<FONT COLOR="#000000" class="itm">-</td>
		<td><a href=http://sunsolve.sun.com/show.pl?target=help/sitemap><font color="#000000" class="nonu">
		Site Map</font></a></td></tr>
		<tr valign="top" ><td align="right">
		<FONT COLOR="#000000" class="itm">-</td>
		<td><a href=http://sunsolve.sun.com/show.pl?target=etc><font color="#000000" class="nonu">
		/etc</font></a></td></tr>
		<tr valign="top" ><td align="right">
		<FONT COLOR="#000000" class="itm">-</td>
		<td><a href=http://sunsolve.sun.com/show.pl?target=home><font color="#000000" class="nonu">
		SunSolve Home</font></a></td></tr>
		<tr valign="top" ><td align="right">
		<FONT COLOR="#000000" class="itm">-</td>
		<td><a href=http://sunsolve.sun.com/show.pl?target=help/faq><font color="#000000" class="nonu">
		Help</font></a></td></tr>

<!-- End of Nav area -->


<!-- BIG SPACER BEGIN -->
<TR><TD COLSPAN="2"><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="2" HEIGHT="8" ALT="spacer"></TD></TR>
<!-- BIG SPACER END -->

<!-- 2 COL WHITE SPACER BEGIN -->

<TR BGCOLOR="#FFFFFF"><TD><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="16" HEIGHT="1" ALT="spacer"></TD>
<TD><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="125" HEIGHT="1" ALT="spacer"></TD></TR>

<!-- 2 COL WHITE SPACER END -->
      
<!-- SPACER BEGIN -->
<TR><TD COLSPAN="2"><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="3" HEIGHT="3" ALT="spacer"></TD></TR>
<!-- SPACER END -->


<!-- SUNSOLVE SIDENAV SEARCH BEGIN -->
<TR><TD>&nbsp;</TD><TD CLASS="blkbld">Search SunSolve:</TD></TR>
<TR><TD>&nbsp;</TD><TD><FORM ACTION="http://sunsolve.sun.com/search.pl" method=post>
<TABLE BORDER="0" CELLSPACING="0" CELLPADDING="2">
        <TR>
        <TD><INPUT TYPE="TEXT" SIZE="12" NAME="zone_32" VALUE=""></TD>
        <TD><BR></TD>
        </TR>
        <TR>
        <TD><INPUT TYPE="image" BORDER="0" SRC="http://sunsolve.sun.com/images/searchbttn.gif" VSPACE="
2"><INPUT TYPE="hidden" name=mode value=results><INPUT TYPE="hidden" name=origin
 value=quick></TD>
        <TD></FORM></TD>
        </TR>
        </TABLE><BR>
</TD></TR>
	<!-- SUNSOLVE SIDENAV SEARCH END -->
	
	<!-- SECTION MANAGER END -->

	<!-- BOLT ON -->

	<!-- PRINT / EMAIL -->
<!-- BIG SPACER BEGIN -->
<TR><TD COLSPAN="2"><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="2" HEIGHT="8" ALT="spacer"></TD></TR>
<!-- BIG SPACER END -->
	
<!-- SIDE NAV = LAST SPACER BEGIN -->
<TR><TD COLSPAN="2"><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="145" HEIGHT="5" ALT="spacer"></TD></TR>
<!-- SIDE NAV = LAST SPACER END -->

<!-- ============== -->
<!--  NAV ROWS END  -->
<!-- ============== -->

</TABLE><BR></TD>
<!-- NAV CELL END -->

<!-- LEFT MARGIN BEGIN -->
<TD WIDTH="10" ROWSPAN="2">&nbsp;&nbsp;</TD>
<!-- LEFT MARGIN END -->

<TD><DIV CLASS="main">
<!--startindex-->

	<!-- ============ -->
	<!-- MAIN CONTENT -->
	<!-- ============ -->

<!--BEGIN CONTENT TABLE-->
<img src="http://sunsolve.sun.com/images/title1.gif" width="455" height="55" ALT="SunSolve Online">

<SSO_INLINE name="home1"></SSO_INLINE><br>

<!-- SUNSOLVE CONTENTS BEGIN -->

<!-- **) -->
<table border=0 cellpadding=3 cellspacing=0 bgcolor="#FFFFFF" >
   <tr>
     <td>
     <FORM METHOD=POST ACTION="http://sunsolve.sun.com/private-cgi/mark1.pl">
     <INPUT TYPE="HIDDEN" NAME="HOSTNAME" VALUE="$name">
     <INPUT TYPE="HIDDEN" NAME="pageName" VALUE="PatchTool_PatchReport">
     <INPUT TYPE="HIDDEN" NAME="action" VALUE="download_now">
     <center>
     <a name="thetop"><font size=5><b>Sun Patch Check Report</b></font></a><br>
     $currentDate<br>
     Patch Check Version: $VERSION<br>
     <table cellspacing=5>
      <tr>
        <td><b>Hostname:</b>$name</td>
        <td><b>SunOS Vers:</b> $os </td>
      </tr>
      <tr>
        <td><b>System Type:</b> $arch </td>
        <td><b>Patch XREF File Date:</b> $datestamp</td>
      </tr>
      </table>
    </center>
ENDOFTOPHTML
    &printp($topPartOfHtml);
    
  } else {
    &printp ($separator);
    &printp ("System Name: $name\t SunOS Vers: $os\t Arch: $arch\n");
    &printp ("Cross Reference File Date: $datestamp\n");
    &printp ("Patch Check Version: $VERSION\n");
    &printp ($separator);
  }
  &printp ($disclaimer);

if ($htmlformat) {
  &printp ($separator_html);
  &printp ("<center>\n<a href=#installed_patches>Installed Patches</a> | <a href=#uninstalled_recommended_patches>Uninstalled Recommended Patches</a><br><a href=#uninstalled_security_patches>Uninstalled Security Patches</a> | <a href=#uninstalled_y2k_patches>Uninstalled Y2K Patches</a> | <a href=#other_related_uninstalled_patches>Other Related Uninstalled Patches</a>$separator_html\n</center>");
  &printp ("<center><a href=\"#patchsuite\">Patchsuite Generation</a></center>");
  &printp ($separator_html);
  &printp ("<table border=1 width=\"100%\" cellpadding=1>\n<tr>\n  <th colspan=4><a name=\"installed_patches\"></a><h2>Installed Patches</h2></th>\n</tr>");
  &printp ($sec_header_html);
} else {
  &printp ($separator);
  &printp ("INSTALLED PATCHES\n");
  &printp ($sec_header);
}

#	capture the showrev listing
	if( $mode eq "SHOWREV" || $mode eq "PKGINFO" ) 
	{
		open( SHOWREV, "<$sfile" );
	}
	else
	{
		open( SHOWREV, "/usr/bin/showrev -p |" );
	}
	
	$/="";
	$showrev = <SHOWREV>;
	$/="\n";
	close( SHOWREV );
	
#	split showrev output, so that we get one patch per line
	@showrev = split(/\n/, $showrev); 
	
#	pick out the patch number (######-##)
#	and put it into an associative array with the patch number as key
	foreach $line (@showrev) {
		if ($line =~ m/^Patch:\s+(\d{6})-(\d{2}).*/) {
	
			#Via match above $1 is patchid, $2 is rev

			if( $installed_patches{$1} eq '' || $2 > $installed_patches{$1} ) {
				$installed_patches{$1} = $2;
				$installed_patches++;
			}
			# else the patch is an old rev of the patch & we just ignore
		}
	}
	
	
# 	Read cross-reference file into memory
#
	open(XREF, "<$XREF");
	$/="";
	$xref = <XREF>;
	$/="\n";
	close XREF;

	@xref = split( /\n/, $xref );

#	iterate thru all installed patches...
	foreach $id (sort(keys(%installed_patches))) {
		@ret=grep( /^$id\|/, @xref );
		@return = reverse sort @ret;
	
		( $junk1, $crev, $reldate, $rFlag, $sFlag, $oFlag, $byFlag, $junk2, 
		  $archs, $pkgs, $synopsis ) = split( /\|/, $return[0]); # this ok since
									 # we should get
									 # 1 line back
	
		$irev = $installed_patches{$id};
		if ( @return eq "" ) { 
			$crev = "N/A";
			$synopsis = "NOT FOUND IN CROSS REFERENCE FILE!" 
		}
		if ( $irev == $crev ) { &printcurrent; }
		else { &printinstalled; }

#		Store id number in mentioned array
		@displayed[++$#displayed] = $id;
			
		if ($htmlformat && ($irev != $crev)) {
			# Add this id to the correct string, for use in the hidden field
			$currently_installed_patches .= "$id ";
			## and add the id and its installed rev number to the cross-ref array
			push(@installed_patches_and_revs, "$id");
			push(@installed_patches_and_revs, $irev);
		}
	}
	
#	find all the recommended patches for OS that are NOT installed
	
#	print new headers for recommended patches
if ($htmlformat) {
  &printp ("</table>\n <small>(<a href=\"#thetop\">back to top</a>)</small>\n$separator_html" .
  "<table border=1 width=\"100%\" cellpadding=1>\n" .
  "<tr>\n" .
  "  <th colspan=7><a name=\"uninstalled_recommended_patches\"></a><h2>Uninstalled Recommended Patches</h2></th>\n" .
  "</tr>\n" .
  $sec_header_w_age_html);
ENDOFREC
} else {
	&printp ("$separator\n");
	&printp ("UNINSTALLED RECOMMENDED PATCHES\n\n");
	&printp ($sec_header_w_age);
}
	
	$foundone = $FALSE;
	($solaris_vers = $os) =~ s/^5/2/;
#
# Check for Solaris 7 and above
#
        $os7 = substr($os,2,1);   # get the number after the 1st (.) of the SunOS

        if ( $os7 ge 7 ) { $solaris_vers = $os7 };
#
        if ($arch =~ "i386") {$solaris_vers = $solaris_vers."_x86";}

	@recmd=grep( /$arch[\.;]|all/, grep( /\|R\|/, grep( /\|$solaris_vers\|/, @xref ) ) );

	foreach $recommend ( @recmd ) {
		( $id, $crev, $reldate, $rFlag, $sFlag, $oFlag, $byFlag, $junk2, 
	  	  $archs, $pkgs, $synopsis ) = split( /\|/, $recommend);
	
		if ( $rFlag ne "R" ) { next;}
		if ( $archs !~ /$arch[\.;]|all/ ) { next;}
		$irev = "N/A";

		@req_list = &retrieveids( $archs );
		@incmp_list = &retrieveids( $pkgs );

		$already_installed = $FALSE; 
		foreach $i ( keys(%installed_patches) ) {
			if ($id == $i) { $already_installed = $TRUE;last }
		}
		if ( $already_installed ne $TRUE ) {
			&calculateage( $reldate );
			&preformat;

#			Store id number in mentioned array
			$displayed[++$#displayed] = $id;
	
#			Setting this for nice print out
			$foundone = $TRUE;
			
			if ($htmlformat) {
				# Add this id to the correct string, for use in the hidden field
				$recommended_patches .= "$id ";
				# If this patch has another required patch(es), add it too if it isn't currently installed
				foreach $reqPatchId (&retrieveids( $archs )) {
				    $reqIdNoSpaces = "$reqPatchId";
				    $reqIdNoSpaces =~ s/ //g;
				    if ($reqIdNoSpaces ne "") {
					$shouldAdd = 1;
					for ($i=0; $i<@installed_patches_and_revs; $i=$i+2) {
						@temp = split("-", $reqPatchId);
					 if ($temp[0] eq $installed_patches_and_revs[$i] && $temp[1] <= $installed_patches_and_revs[$i+1]) {
						    	$shouldAdd = 0;
						    	last;
						    }
					} # end for
					if ($shouldAdd == 1) {
						$recommended_patches .= "$temp[0] ";
					} # end if shouldAdd
				    } # end if reqId isn't empty
				} # end foreach
			}
		}
	}
	if ( $foundone ne $TRUE) {
		if ($htmlformat) {&printp("<tr><td>");}
		&printp ("All Recommended patches installed!\n");
		if ($htmlformat) {&printp("</td></tr>");}
	}
	if ($htmlformat) {&printp ("</table>\n <small>(<a href=\"#thetop\">back to top</a>)</small>\n$separator_html")}
	close( RECMD );
	
#	find all the security patches for OS that's NOT installed
	
#	print new headers for recommended patches
if ($htmlformat) {
  &printp ("<table border=1 width=\"100%\" cellpadding=1>\n" .
  "<tr>\n" .
  "  <th colspan=7><a name=\"uninstalled_security_patches\"></a><h2>Uninstalled Security Patches</h2></th>\n</tr>\n" .
  "<tr>\n  <td colspan=7><b>note:</b> This list includes the Security patches that are also Recommended</td>\n" .
  "</tr>\n" .
  $sec_header_w_age_html);
} else {
	&printp ("$separator\n");
	&printp ("UNINSTALLED SECURITY PATCHES\n\n");
	&printp ("NOTE: This list includes the Security patches that are also Recommended\n\n");
	&printp ("$sec_header_w_age");
}

	$foundone = $FALSE;
	@scrty=grep( /\|S\|/, grep( /\|$solaris_vers\|/, @xref ) );

	foreach $security( @scrty ) {
		( $id, $crev, $reldate, $rFlag, $sFlag, $oFlag, $byFlag, $junk2, 
	  	  $archs, $pkgs, $synopsis ) = split( /\|/, $security);
	
		if ( $sFlag ne "S" ) { next;}
		if ( $archs !~ /$arch[\.;]|all/ ) { next;}
		$irev = "N/A";

                @req_list = &retrieveids( $archs );
                @incmp_list = &retrieveids( $pkgs );

		$already_installed = $FALSE; # using F and T as booleans here.
		foreach $i ( keys(%installed_patches) ) {
			if ($id == $i) { $already_installed = $TRUE;last }
		}
		if ( $already_installed ne $TRUE ) {
			&calculateage( $reldate );
			&preformat;

#			Store id number in mentioned array
			$displayed[++$#displayed] = $id;
			$foundone = $TRUE;
			
			if ($htmlformat) {
				# Add this id to the correct string, for use in the hidden field
				$security_patches .= "$id ";
				# If this patch has another required patch(es), add it too if it isn't currently installed
				foreach $reqPatchId (&retrieveids( $archs )) {
				    $reqIdNoSpaces = "$reqPatchId";
				    $reqIdNoSpaces =~ s/ //g;
				    if ($reqIdNoSpaces ne "") {
					$shouldAdd = 1;
					for ($i=0; $i<@installed_patches_and_revs; $i=$i+2) {
						@temp = split("-", $reqPatchId);
					 if ($temp[0] eq $installed_patches_and_revs[$i] && $temp[1] <= $installed_patches_and_revs[$i+1]) {
						    	$shouldAdd = 0;
						    	last;
						    }
					} # end for
					if ($shouldAdd == 1) {
						$security_patches .= "$temp[0] ";
					} # end if shouldAdd
				    } # end if reqId isn't empty
				} # end foreach
			}
		}
	}
	if ( $foundone ne $TRUE) {
		if ($htmlformat) {&printp("<tr><td>");}
		&printp ("All security patches installed!\n");
		if ($htmlformat) {&printp("</td></tr>");}
	}
	if ($htmlformat) {printp ("</table>\n <small>(<a href=\"#thetop\">back to top</a>)</small>\n$separator_html")}
	close( SECURITY );

#	find all the Y2K patches for OS that's NOT installed
	
#	print new headers for recommended patches
if ($htmlformat) {
  &printp ("<table border=1 width=\"100%\" cellpadding=1>\n" .
  "<tr>\n  <th colspan=7><a name=\"uninstalled_y2k_patches\"></a><h2>Uninstalled Y2K Patches</h2></th>\n</tr>" .
  "<tr>\n  <td colspan=7><b>note:</b> This list includes the Y2K patches that are also Recommended</td>\n</tr>\n" .
  $sec_header_w_age_html);
ENDOFY2K
} else {
	&printp ($separator);
	&printp ("\n");
	&printp ("UNINSTALLED Y2K PATCHES\n\n");
	&printp ("NOTE: This list includes the Y2K patches that are also Recommended\n\n");
	&printp ($sec_header_w_age);
}
	$foundone = $FALSE;
	@y2k_list=grep( /\|Y/, grep( /\|$solaris_vers\|/, @xref ) );

	foreach $y2k( @y2k_list ) {
		( $id, $crev, $reldate, $rFlag, $sFlag, $oFlag, $byFlag, $junk2, 
	  	  $archs, $pkgs, $synopsis ) = split( /\|/, $y2k);
#		if ( ( $byFlag ne "Y " ) && ( $byFlag ne "YB" ) ){ next;}
		if ($byFlag !~ /Y/){ next;}
		if ( $archs !~ /$arch[\.;]|all/ ) { next;}
		$irev = "N/A";

                @req_list = &retrieveids( $archs );
                @incmp_list = &retrieveids( $pkgs );

		$already_installed = $FALSE; # using F and T as booleans here.
		foreach $i ( keys(%installed_patches) ) {
			if ($id == $i) { $already_installed = $TRUE;last }
		}
		if ( $already_installed ne $TRUE ) {
			&calculateage( $reldate );
			&preformat;

#			Store id number in mentioned array
			$displayed[++$#displayed] = $id;
			$foundone = $TRUE;
			
			if ($htmlformat) {
				# Add this id to the correct string, for use in the hidden field
				$y2kuninst_patches .= "$id ";
				# If this patch has another required patch(es), add it too if it isn't currently installed
				foreach $reqPatchId (&retrieveids( $archs )) {
				    $reqIdNoSpaces = "$reqPatchId";
				    $reqIdNoSpaces =~ s/ //g;
				    if ($reqIdNoSpaces ne "") {
					$shouldAdd = 1;
					for ($i=0; $i<@installed_patches_and_revs; $i=$i+2) {
						@temp = split("-", $reqPatchId);
					 if ($temp[0] eq $installed_patches_and_revs[$i] && $temp[1] <= $installed_patches_and_revs[$i+1]) {
						    	$shouldAdd = 0;
						    	last;
						    }
					} # end for
					if ($shouldAdd == 1) {
						$y2kuninst_patches .= "$temp[0] ";
					} # end if shouldAdd
				    } # end if reqId isn't empty
				} # end foreach
			}
		}
	}
	if ( $foundone ne $TRUE) {
		if ($htmlformat) {&printp("<tr><td>");}
		&printp ("All Y2K patches installed!\n");
		if ($htmlformat) {&printp("</td></tr>");}
	}
	if ($htmlformat) {
	  &printp ("</table>\n <small>(<a href=\"#thetop\">back to top</a>)</small>\n$separator_html");
	} else {
          &printp ($separator);
	}
}

if ($mode eq "LONG" || $mode eq "PKGINFO" ) {

        # slurp the output of pkginfo -l
	if( $mode eq "PKGINFO" ) 
	{
		open( PKGINFO, "<$pfile" );
	}
	else
	{
        	open( PKGINFO, "/usr/bin/pkginfo -l|" );
	}

        $/="\0x07"; # 0x07 is the bell; arbitrary choice -MN
        $pkginfo = <PKGINFO>;
        $/="\n";

        close( PKGINFO );

        # massaging text to make searches & split easier
        $pkginfo =~ s/\n\n/#/g;
        $pkginfo =~ s/\n/|/g;
        $pkginfo =~ s/\s*[A-Z]+:\s*//g;
        @pkginfo = split(/#/, $pkginfo);

#	print the headers for the other patches
	if ($htmlformat) {
	&printp ("<table border=1 cellpadding=5>\n" .
		"<tr>\n  <th colspan=5><a name=\"other_related_uninstalled_patches\"></a><h2>Other Related Uninstalled Patches</h2></th>\n</tr>\n" .
		"<tr>\n  <td colspan=5><b>note:</b> This is determined by the packages that have been installed on the system.<br>&nbsp;<br>\n" .
		"  When one patch refers to multiple packages, we list the additional packages in the next lines.<br>&nbsp;<br>\n" .
		"  The various 'S', 'R', '*' marks denote unbundled packages that are designated as 'Security' or 'Recommended'.<br>&nbsp;<br>\n" .
		"  <ul>\n" .
		"    S = Security<br>\n" .
		"    R = Recommended Unbundled<br>\n" .
		"    * = Both Security and Recommended Unbundled<br><br>\n  </td>\n</tr>\n" .
		 $pkg_header_html);

	} else {
		&printp ("\nOTHER RELATED UNINSTALLED PATCHES\n\n");
		&printp ("NOTE: This is determined by the packages that have been\n");
		&printp ("      installed on the system.\n\n");
		&printp ("      When one patch refers to multiple packages, we list the\n");
		&printp ("      additional packages in the next lines.\n\n");
		&printp ("      The various 'S','R','*' marks denote unbundled packages\n");
		&printp ("      that is designated as an 'Security' or 'Recommended'.\n\n");	
		&printp ("         S = Security\n"); 
		&printp ("         R = Recommened Unbundled\n"); 
		&printp ("         * = Both Security and Recommended Unbundled\n\n$pkg_header");
	}

#	taking a arch specific version of the xref. (attempt to speed things
#	up a bit)
#
	@arch = grep( /$arch[\.;]|all/, @xref );

	$= = $#xref; # setting the page length to be max possilbe
		     # this is so that we don't see TOP format again.

	$count = 1;
        foreach $section (@pkginfo) {
                ( $package, $name, $category, $archs, $version,
                  $basedir, $vendor, $desc, $pstamp, $instdate,
                  $hotline, $status, $files ) = split(/\|/, $section);

                $pattern = $package.":".$version.";";
                $pattern =~ s/\+\+/\\+\\+/;
		@result = grep( /$pattern/, @arch );
                for($i=0;$i <= $#result; $i++) {
                        # Checking to see if the package is mentioned
                        # in the cross reference file (maybe multiple
                        # so we're going all the way thru w/ the for loop)
                        if ( $result[$i] =~ m/^(\d{6})\|(\d{2})\|([^\|]+)\|([^\|]+)\|([^\|]+)\|[^\|]+\|[^\|]+\|[^\|]+\|[^\|]+\|[^\|]*$pattern[^\|]*\|(.*)$/) {
				$id = $1;
				$crev = $2;
				$reldate = $3;
				$r_flag = $4;
				$s_flag = $5;
				$synopsis = $6;

				if( $r_flag eq 'R' && $s_flag eq 'S' ) {
					$glyph = '*';
				}
				elsif ( $r_flag eq 'R' ) {
					$glyph = 'R';
				}
				elsif ( $s_flag eq 'S' ) {
					$glyph = 'S';
				}
				else { $glyph = " " ;}

			#	Now need to check if the id has
			#	been displayed before.
				$return = &alreadydisplayed( $id, @displayed ); 
				if ( ! $return ) {
					if ( $sortlist{$id} eq '' ) {
	                                	$sortlist{$id}="$crev|$reldate|$glyph|$synopsis|$package";
					}
					else {
						$tmp = $sortlist{$id};
	                                	$sortlist{$id}="$tmp;$package";
					}

					if ($htmlformat) {
						# Add this id to the correct string, for use in the hidden field
						$other_patches .= "$id ";
						# If this patch has another required patch(es), add it too if it isn't currently installed
				#		foreach $reqPatchId (&retrieveids( $archs )) {
				 #   			$reqIdNoSpaces = "$reqPatchId";
				 #   			$reqIdNoSpaces =~ s/ //g;
				 #   			if ($reqIdNoSpaces ne "") {
				#				$shouldAdd = 1;
				#				for ($i=0; $i<@installed_patches_and_revs; $i=$i+2){
				#					@temp = split("-", $reqPatchId);
				#					 if ($temp[0] eq $installed_patches_and_revs[$i] && $temp[1] <= $installed_patches_and_revs[$i+1]) {
				#		    				$shouldAdd = 0;
				#		    				last;
				#		    			 }
				#				} # end for
				#				if ($shouldAdd == 1) {
				#					$other_patches .= "$temp[0] ";
				#				} # end if shouldAdd
				 #   			} # end if reqId isn't empty
				#		} # end foreach
					}
				}
                        }
                }
        }

#	sort patchids & printing
	foreach $id (sort(keys(%sortlist))) {
		( $crev, $reldate, $glyph, $synopsis, $package ) =split(/\|/, $sortlist{$id});
		&calculateage( $reldate );
		if ( $package !~ m/.*;.*/) { 
			&printlong;
		}
		else { 
			$pack = $package; 
			$after = $FALSE;
	
			foreach $package ( split( /\;/, $pack ) ) {
				if ( $after eq $TRUE ) { 
					&printpkg;
				}
				else {
				        &printlong;
				}
				$after = $TRUE;
			}
		}
	}
	if ($htmlformat) { 
		&printp ("</table>\n <small>(<a href=\"#thetop\">back to top</a>)</small>\n$separator_html"); 
	} else {
		&printp ($separator);
	}
}	
#============================================== 
# END OF NON-HTML
#============================================== 

if ($htmlformat) {
# first, we need to see if any of the 'groups' of patches are empty.  If any group is empty,
# we do not want to print out a checkbox option for that group.  For groups that aren't empty,
# we do want to print out the associated checkbox.
  if ($other_patches ne "") {
  	$checkPackage = "<input type=\"checkbox\" name=\"PACKAGE\"> Other Related Uninstalled Patches <a href=\"#other_related_uninstalled_patches\">view</a><BR>";
  } else {
  	$checkPackage = "";
  }
  if ($security_patches ne "") {
  	$checkSecurity = "<input type=\"checkbox\" name=\"SECURITY\"> Uninstalled Security Patches <a href=\"#uninstalled_security_patches\">view</a><BR>";
  } else {
  	$checkSecurity = "";
  }
  if ($y2kuninst_patches ne "") {
  	$checkY2kuninst = "<input type=\"checkbox\" name=\"Y2KUNINST\"> Uninstalled Y2K Patches <a href=\"#uninstalled_y2k_patches\">view</a><BR>";
  } else {
  	$checkY2kuninst = "";
  }
  if ($y2kinst_patches ne "") {
  	$checkY2kinst = "<input type=\"checkbox\" name=\"Y2KINST\"> Downreved Installed Y2K Patches <a href=\"#installed_patches\">view</a><BR>";
  } else {
  	$checkY2kinst = "";
  }
  if ($recommended_patches ne "") {
  	$checkRecommended = "<input type=\"checkbox\" name=\"RECOMMENDED\"> Uninstalled Recommended Patches <a href=\"#uninstalled_recommended_patches\">view</a><BR>";
  } else {
  	$checkRecommended = "";
  }
  if ($currently_installed_patches ne "") {
  	$checkInstalled = "<input type=\"checkbox\" name=\"INSTALLED\"> Downreved Installed Patches <a href=\"#installed_patches\">view</a><BR>";
  } else {
  	$checkInstalled = "";
  }
 
 # now, print out the bottom part of the HTML page, including the bulk of the form stuff
  	$bottomPartOfHtml = <<"ENDOFBOTTOMHTML";
  <br>
  <input type=hidden name=INSTALLED_PATCHES value="$currently_installed_patches">
  <input type=hidden name=RECOMMENDED_PATCHES value="$recommended_patches">
  <input type=hidden name=SECURITY_PATCHES value="$security_patches">
  <input type=hidden name=OTHER_PATCHES value="$other_patches">
  <input type=hidden name=Y2KINST_PATCHES value="$y2kinst_patches">
  <input type=hidden name=Y2KUNINST_PATCHES value="$y2kuninst_patches">
  <a name="patchsuite">
  <table border="1" width="100%" bordercolor="#000000" cellspacing="0" cellpadding="0" bgcolor="#000000">
  <tr>
    <th width="100%"><b class="large"><font color="#FFFFFF">Patchsuite Generation</font></b></th>
   </tr>
   </table>
   <b><font face="Arial, Helvetica, sans-serif" size="4" color="#009900">Step 1:&nbsp;&nbsp;</font></b>
   <font face="Arial, Helvetica, sans-serif" size="2">A patchsuite (tarfile) can be generated based on the patch IDs you have selected above. Or you can select an entire set of patches below.</font>
  <ul>
  $checkY2kinst
  $checkInstalled
  $checkRecommended
  $checkSecurity
  $checkY2kuninst
  $checkPackage
  </ul>
  <hr noshade size="1">
  <b><font face="Arial, Helvetica, sans-serif" size="4" color="#009900">Step 2:&nbsp;&nbsp;</font></b><font face="Arial, Helvetica, sans-serif" size="2">Click <i><b>Create Patchsuite</b></i>.</font>
  <p>
  <b>Note:</b> In order to use the Patch Retrieval feature, you must be registered with SunSolve Online (requires a Sun Support contract - <a href="http://sunsolve.sun.com/pub-cgi/show.pl?target=registerFrontPage">Register</a>).
  </p>
  <br>
  <input type="submit" value="Create Patchsuite">&nbsp;&nbsp;
  <input type="reset" value="Clear">
  </form>
  <form action=http://sunsolve.sun.de/private-cgi/mark.pl?action=download>
  <ol>
    <li><font face="Arial, Helvetica, sans-serif" size="2">You will be asked to log in to SunSolve if you have not already done so in this session.</font></li>
    <li><font face="Arial, Helvetica, sans-serif" size="2">Save the tar file</font></li>
    <li><font face="Arial, Helveitca, sans-serif" size="2">Extract the contents of the tar file</font></li>
    <li><font face="Arial, Helvetica, sans-serif" size="2">Install the patches using the instructions in the README file.</font></li>
  </form>
  <hr>
  <br>
  </td></tr>
</table>
<!-- (** -->
</TR>
<!-- CONTENT FOOTER ROW BEGIN -->

<TR VALIGN="BOTTOM" ALIGN="CENTER" BGCOLOR="#FFFFFF">
<TD><BR>
<!-- CONTENT FOOTER BEGIN -->
<nobr>SunSolve Online:</nobr>&nbsp;
<A HREF="http://sunsolve.sun.com/private-cgi/show.pl?target=home_con">Login</A> | 
<A HREF="http://sunsolve.sun.com/show.pl?target=registerFrontPage">Register</A> | 
<A HREF="http://sunsolve.sun.com/show.pl?target=patches/patch-access">Patches</A> | 
<A HREF="http://sunsolve.sun.com/show.pl?target=help/collections">Support Documents</A> | 
<A HREF="http://sunsolve.sun.com/show.pl?target=security/sec">Security Information</A> | 
<A HREF="http://sunsolve.sun.com/search.pl?mode=advanced">Advanced Search</A> | 
<A HREF="http://sunsolve.sun.com/show.pl?target=link">SunSolve Servers</A> | 
<A HREF="http://sunsolve.sun.com/show.pl?target=about_sunsolve">About SunSolve</A> | 
<A HREF="http://sunsolve.sun.com/feedback.pl">Feedback</A> | 
<A HREF="http://sunsolve.sun.com/show.pl?target=help/sitemap">Site Map</A> | 
<A HREF="http://sunsolve.sun.com/show.pl?target=etc">/etc</A> | 
<A HREF="http://sunsolve.sun.com/show.pl?target=help/faq">Help</A>


<!-- CONTENT FOOTER END -->

<BR><BR></TD></TR>

<!-- CONTENT FOOTER ROW END -->

<TR><TD COLSPAN="4">

<!-- PAGE FOOTER TABLE BEGIN -->

<!-- WEBTONE BEGIN -->
<TABLE BORDER="0" CELLSPACING="0" CELLPADDING="0" WIDTH="100%" BGCOLOR="#FFFFFF">
<TR><TD CLASS="wb1">&nbsp;</TD><TD CLASS="wb2">&nbsp;</TD><TD CLASS="wb3">&nbsp;</TD><TD CLASS="wb4">&nbsp;</TD></TR>
<!-- WEBTONE END -->
<TR><TD COLSPAN="4" CLASS="cpyftr">

<!-- COPYRIGHT BEGIN -->

<DIV CLASS="cpyftr">Copyright 1994-2000 Sun Microsystems, Inc., 901 San Antonio Road, Palo Alto, CA 94303 USA. All rights reserved.<BR>
<A HREF="http://www.sun.com/share/text/termsofuse.html" CLASS="undw">Terms of Use</A>. <A HREF="http://www.sun.com/privacy/" CLASS="undw">Privacy Policy</A>. <A HREF="http://www.sun.com/cgi-bin/comment-form.pl" CLASS="undw">Feedback</A></DIV>

<!-- COPYRIGHT END -->

</TD></TR></TABLE>
</TD></TR>
<!-- CONTENT PUSHING ROW BEGIN ---- DO NOT REMOVE -->

<TR><TD COLSPAN="2">&nbsp;</TD>
<TD><IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="420" HEIGHT="1" ALT="spacer" BORDER="0"> <IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="420" HEIGHT="1" ALT="spacer" BORDER="0"> <IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="200" HEIGHT="1" ALT="spacer" BORDER="0"> <IMG SRC="http://sunsolve.sun.com/images/dot.gif" WIDTH="200" HEIGHT="1" ALT="spacer" BORDER="0"></TD>
<TD>&nbsp;</TD></TR>

<!-- CONTENT PUSHING ROW END ---- DO NOT REMOVE -->

<!-- CONTENT PUSHING ROW END ---- DO NOT REMOVE -->
</TABLE>

<!-- NAV/CONTENT/FOOTER TABLE END -->

<!-- **) -->
</body></html>
ENDOFBOTTOMHTML
  &printp($bottomPartOfHtml);
  
  print "\nThe patch report file\n  " . $html_file . "\nhas been created. ";
  print "Would you like to open it in your Web browser? (Y|N)";
  $| = 1;
  $_ = <STDIN>;
  chomp;
  if ($_ eq "Y" || $_ eq "y") {
    print "\nPlease enter the path to your preferred browser: (enter C to cancel)";
    $| = 1;
    $_ = <STDIN>;
    chomp;
    if ( ($_ ne "C") && ($_ ne "c") ) {
    	$pid = fork;
    	if ($pid == 0) {
      		if ( exec ($_, $html_file) == 0) {
         		print "\nThere was an error launching the browser.\nPlease launch the browser manually and load " . $html_file . ".\n";
      		}
    	}
    } else {
       print ("\nAction cancelled.\n\nTo view the file later, just load the following URL into your browser: \n  file:" .   $html_file);
       print ("\nWith SunSolve Online registration, you will be able to select your\n");
       print ("desired patches and receive a tar file from Sun containing those patches.\n\n");
    }
  } else {
     print ("\nTo view the file later, just load the following URL into your browser: \n  file:" . $html_file);
     print ("\nWith SunSolve Online registration, you will be able to select your\n");
     print ("desired patches and receive a tar file from Sun containing those patches.\n\n");
  }
  
}
##################################
# END
##################################
