#!/usr/bin/perl # Don't give warnings about patches for bundled but uninstalled packages $CHECK_PACKAGES=1; # Try harder to compare the archicture type $CHECK_MACH=0; # Check unbundled products as well as core components of Solaris $CHECK_UNBUNDLED=1; # Shows the names of unbundled packages $SHOW_UNBUNDLED=0; $0=~s!.*/!!; $interactive=(-t STDIN) && (-t STDOUT) && (-t STDERR); $custom=0; $short=0; while (@ARGV) { $_=shift; if ($_ eq '-h' || $_ eq '--help') { my $s=" "x(length($0)); print <<"ENDOFHELP"; Usage: $0 [-i|-q] [-n] [-p pkginfo] [-s showrev] [-x xref] [-a arch] $s [-m mach] [-v ver] -i interactive (prints progress dots) -q quiet -n just output the patch numbers instead of printing formatted output -p get package database from specified file instead of 'pkginfo -l' -s get patch database from specified file instead of 'showrev -p' -x get cross reference file from specified file instead of ./patchdiag.xref -a use specified architecture instead of 'uname -p' [sparc|i386|ppc|...] -m use specified machine instead of 'uname -m' [sun4u|sun4m|sun4d|...] -v use specified OS version instead of 'uname -r' [5.5|5.51|5.6|...] ENDOFHELP exit(0); } ($interactive=1, next) if $_ eq '-i'; ($interactive=0, next) if $_ eq '-q'; ($short=1, next) if $_ eq '-n'; if ($_=~/^-[psxam]$/) { $arg=shift || die("$0: $_ needs an argument"); } else { die("$0: Unrecognised option $_\n"); } $custom=1; ($pkginfofile=$arg, next) if $_ eq '-p'; ($showreffile=$arg, next) if $_ eq '-s'; ($xreffile=$arg, next) if $_ eq '-x'; ($arch=$arg, next) if $_ eq '-a'; ($mach=$arg, next) if $_ eq '-m'; ($osver=$arg, next) if $_ eq '-v'; } $pkginfofile="pkginfo -l |" unless defined($pkginfofile); $showrevfile="showrev -p |" unless defined($showrevfile); $xreffile="patchdiag.xref" unless defined($xreffile); unless (defined($arch)) { chomp($arch=`uname -p`) || die("error from uname -p\n"); } unless (defined($mach)) { chomp($mach=`uname -m`) || die("error from uname -m\n"); } unless (defined($osver)) { chomp($osver=`uname -r`) || die("error from uname -r\n"); } $osver=~s/^5/2/; unless ($custom) { chomp($machine=`uname -n`) || die("error from uname -n\n"); } print STDERR "Reading package database." if $interactive; open(PKGINFO, $pkginfofile) || die("Can't open pkginfo ($pkginfofile): $!\n"); my $pack; my $pc=0; while () { $pc=0 if $pc++==100; print STDERR "." if $interactive && !$pc; chomp(); $pack=$' if /^\s*PKGINST\s*:\s*/; $pkg{"$pack:$'"}=1 if /^\s*VERSION\s*:\s*/; } close(PKGINFO); print STDERR "\nReading patch cross reference file." if $interactive; open(XREF, $xreffile) || die("Can't open cross reference file ($xreffile): $!\n"); chomp($xrefdate=); $xrefdate=~s/^.* OF (.*) \#\#$/$1/; $pc=0; while () { $pc=0 if $pc++==100; print STDERR "." if $interactive && !$pc; chomp(); my ($patch, $rev, $date, $recommended, $security, $obsolete, $badpatch, $vers, $archs, $pkgs, $synopsis)=split /\|/; undef $security unless $security eq 'S'; undef $recommended unless $recommended=~/^[?R]$/; undef $obsolete unless $obsolete eq 'O'; undef $badpatch unless $badpatch eq 'B'; $oldrev=(@{$xref{$patch}})[1]; next if defined($oldrev) && $oldrev>$rev; $xref=$xref{$patch}=[$patch, $rev, $date, $recommended, $security, $obsolete, $badpatch, $vers, $archs, $pkgs, $synopsis]; $irev{$patch}=" -"; next unless $vers eq $osver || ($CHECK_UNBUNDLED && $vers eq "Unbundled"); next unless $CHECK_MACH || $archs=~/$arch[\.;]|all;/; my $found=0; if ($CHECK_MACH) { $archs=~s/;$//; my @archs=split(/;/, $archs); my $longestsub=''; for (@archs) { ($found=1, last) if $_ eq 'all'; ($found=1, last) if $_ eq "$arch.$mach"; if ("$arch.$mach"=~/^$_/) { $longestsub=$_ if length($_)>length($longestsub); $found=2; next; } $found=0 if "$arch.$mach"!~/^$_/ && /^$longestsub/; } next unless $found; } if ($CHECK_PACKAGES || $vers eq "Unbundled") { my $found=0; $pkgs=~s/;$//; my @pkgs=split(/;/, $pkgs); for (@pkgs) { ($found=1, last) if exists($pkg{$_}); } next unless $found; } $uninstrecommended{$patch}=$xref if $recommended; $uninstsecurity{$patch}=$xref if $security; } close(XREF); print STDERR "\nReading patch database." if $interactive; open(SHOWREV, $showrevfile) || die("Can't open showrev ($showrevfile): $!\n"); $pc=0; while() { $pc=0 if $pc++==100; print STDERR "." if $interactive && !$pc; next unless /^Patch: (\d+)-(\d+)/; my ($patch, $irev)=($1, $2); next if defined($irev{$patch}) && $irev{$patch}>$irev; if (exists($xref{$patch})) { my $xref=$xref{$patch}; my ($xrev, $recommended, $security, $synopsis) =(@{$xref})[1,3,4,10]; $irev{$patch}=$irev; delete $uninstrecommended{$patch}; delete $uninstsecurity{$patch}; if ($irev==$xrev) { delete $outofdaterecommended{$patch}; delete $outofdatesecurity{$patch}; } else { $outofdaterecommended{$patch}=$xref if $recommended; $outofdatesecurity{$patch}=$xref if $security; } } } close(SHOWREV); print STDERR "\n" if $interactive; print "PATCH REPORT FOR $xrefdate", $custom?"\n":" - $machine\n" unless $short; format LONG= @<<<<<<@<< @<< @@ @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $patch, $xrev, $irev{$patch}, $recommended, $security, $synopsis ~ @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $pkgs . format SHORT= @<<<<<-@<< $patch, $xrev . $~ = ('LONG', 'SHORT')[$short]; header('OUT OF DATE RECOMMENDED PATCHES (not including security patches)'); $done=0; for (keys (%outofdaterecommended)) { ($patch, $xrev, $recommended, $security, $vers, $pkgs, $synopsis) =(@{$outofdaterecommended{$_}})[0,1,3,4,7,9,10]; unless ($security) { if ($SHOW_UNBUNDLED && $vers eq 'Unbundled') { $pkgs=~s/:.*;/;/g; $pkgs=~s/;$//; } else { $pkgs=''; } write; $done=1; } } print "(No patches)\n" unless $done || $short; header('UNINSTALLED RECOMMENDED PATCHES (not including security patches)'); $done=0; for (keys (%uninstrecommended)) { ($patch, $xrev, $recommended, $security, $vers, $pkgs, $synopsis) =(@{$uninstrecommended{$_}})[0,1,3,4,7,9,10]; unless ($security) { if ($SHOW_UNBUNDLED && $vers eq 'Unbundled') { $pkgs=~s/:.*;/;/g; $pkgs=~s/;$//; } else { $pkgs=''; } write; $done=1; } } print "(No patches)\n" unless $done || $short; header('OUT OF DATE SECURITY PATCHES'); $done=0; for (keys (%outofdatesecurity)) { ($patch, $xrev, $recommended, $security, $vers, $pkgs, $synopsis) =(@{$outofdatesecurity{$_}})[0,1,3,4,7,9,10]; if ($SHOW_UNBUNDLED && $vers eq 'Unbundled') { $pkgs=~s/:.*;/;/g; $pkgs=~s/;$//; } else { $pkgs=''; } write; $done=1; } print "(No patches)\n" unless $done || $short; header('UNINSTALLED SECURITY PATCHES'); $done=0; for (keys (%uninstsecurity)) { ($patch, $xrev, $recommended, $security, $vers, $pkgs, $synopsis) =(@{$uninstsecurity{$_}})[0,1,3,4,7,9,10]; if ($SHOW_UNBUNDLED && $vers eq 'Unbundled') { $pkgs=~s/:.*?;/;/g; $pkgs=~s/;$//; } else { $pkgs=''; } write; $done=1; } print "(No patches)\n" unless $done || $short; sep(); print "END OF PATCH REPORT\n" unless $short; sub header { return if $short; sep(); print "\n$_[0]\n"; print " Latest Inst RS Synopsis\n--------- ---- -- ", "-"x61, "\n"; } sub sep { print "="x79,"\n" unless $short; }