Blame | Last modification | View Log | RSS feed
#!/bin/ksh -hp#set -x## @(#) patchrm.ksh 2.4 99/04/06 SMI### Copyright (c) 1996-1999 Sun Microsystems, Inc. All Rights Reserved. Sun# considers its source code as an unpublished, proprietary trade secret, and# it is available only under strict license provisions. This copyright# notice is placed here only to protect Sun in the event the source is# deemed a published work. Dissassembly, decompilation, or other means of# reducing the object code to human readable form is prohibited by the# license agreement under which this code is provided to the user or company# in possession of this copy.## 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 52.227-7013# and in similar clauses in the FAR and NASA FAR Supplement.## Exit Codes:# 0 No error# 1 Usage error# 2 Attempt to backout a patch that hasn't been applied# 3 Effective UID is not root# 4 No saved files to restore# 5 pkgrm failed# 6 Attempt to back out an obsoleted patch# 7 Attempt to restore CPIO archived files failed# 8 Invalid patch id format# 9 Prebackout script failed# 10 Postbackout script failed# 11 Suspended due to administrative defaults# 12 Patchrm could not locate the backout data# 13 The relative directory supplied can't be found# 14 Patchadd has been interrupted, re-invoke patchadd# 15 This patch is required by a patch already installed, can't back it out## Set up the path to use with this script.PATH=/usr/sadm/bin:/usr/sbin:/usr/bin:$PATHexport PATHumask 007# Global FilesTMPSOFT=/tmp/soft.$$ADMINFILE=/tmp/admin.$$LOGFILE=/tmp/backoutlog.$$RESPONSE_FILE=/tmp/response.$$TEMP_REMOTE=/tmp/temp_remote.$$INSTPATCHES_FILE=/tmp/MyShowrevFile.$$force=nopkginstlist=pkglist=ret=curdir=diPatch="no"ObsoletedBy="none"ThisPatchFnd="no"PatchedPkgs=""InstPkgs=""RebootRqd="no"netImage="none"compatsAlreadyChecked="no"unReqAlreadyChecked="no"typeset -i dbSum=0ROOTDIR="/"PATCHDB="/var/sadm/patch"PATCH_UNDO_ARCHIVE="none"OBS_PATCH_UNDO_ARCHIVE="none"TEMP_PATCH_UNDO_ARCHIVE="none"PKGDB="/var/sadm/pkg"SOFTINFO="/var/sadm/softinfo"NEW_SOFTINFO="/var/sadm/system/admin/INST_RELEASE"OLD_SOFTINFO="/var/sadm/softinfo/INST_RELEASE"MGRSOFTINFO="none"TRGSOFTINFO="none"CONTENTS="/var/sadm/install/contents"TMP_LIB_DIR="/tmp/TmpLibDir.$$"PKGDBARG=""PATCH_PID=""DASHB_SUPPLIED="no"# This tells pkgadd to not check mounted FS's. Used in the mini-root.MOPTION=""# Version string of the patch data base file. Change this# anytime the format of the .patchDB file changes. Also# needs to be changed in patchadd.PATCHDBVER="1.0"# Needed utilitiesDF=/usr/sbin/dfRM=/usr/bin/rmMV=/usr/bin/mvSED=/usr/bin/sedAWK=/usr/bin/awkNAWK=/usr/bin/nawkCAT=/usr/bin/catLS=/usr/bin/lsEGREP=/usr/bin/egrepGREP=/usr/bin/grepFGREP=/usr/bin/fgrepCP=/usr/bin/cpFIND=/usr/bin/findUNAME=/usr/bin/unameMOUNT=/sbin/mountUMOUNT=/sbin/umountSUM=/usr/bin/sumrecreatePatchDB="no"PatchIdFormat='^[A-Z]*[0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9]$'## Description:# Execute the prebackout script if it is executable. Fail if the# return code is not 0.## Parameters:# $1 - package database directory# $2 - patch number# Globals Set:# nonefunction execute_prebackout{typeset -i retcode=0if [ -x $1/$2/prebackout ]then/usr/bin/gettext "Executing prebackout script...\n"$1/$2/prebackoutretcode=$?if (( retcode != 0 ))then/usr/bin/gettext "prebackout script exited with return code $retcode.\n"/usr/bin/gettext "Patchrm is exiting.\n\n"exit 9fifi}## Description:# Check to see if patchadd was interrupted, prompt# usr to reinvoke patchadd.## Globals Set:# RECOVERDIRfunction check_file_recovery{if [[ -f "$RECOVERDIR/.$PatchNum" ]]then/usr/bin/gettext "The installation of patch $PatchNum was interrupted.\nPatchadd needs to be re-invoked to ensure proper installation of the patch.\n"patch_quit 14fi}## Description:# Execute the postbackout script if it is executable. Fail if the# return code is not 0.## Parameters:# $1 - package database directory# $2 - patch number# Globals Set:# nonefunction execute_postbackout{typeset -i retcode=0if [ -x $1/$2/postbackout ]then/usr/bin/gettext "Executing postbackout script...\n"$1/$2/postbackoutretcode=$?if (( retcode != 0 ))then/usr/bin/gettext "postbackout script exited with return code $retcode.\nPatchrm exiting.\n\n"exit 10fifi}# Quit patchrm and clean up any remaining temporary files.function patch_quit { # exit codeif [[ $1 -ne 0 ]]then/usr/bin/gettext "\nPatchrm is terminating.\n"fiexit $1}## Description:# Return the base code of the provided patch. The base code# returned will include the version prefix token (usu "-").## Parameters Used:# $1 - patch number#function get_base_code {ret_value=${1:%[0-9]}last_value=$1while [[ $ret_value != $last_value ]]dolast_value=$ret_valueret_value=${last_value%[0-9]}donecur_base_code=${ret_value%?}}## Description:# Return the version number of the provided patch.## Parameters Used:# $1 - patch number# $2 - base code#function get_vers_no {cur_vers_no=${1:#$2?}}## Description:# Give a list of applied patches similar in format to the showrev -p# command. Had to write my own because the showrev command won't take# a -R option.## Parameters:# $1 - package database directory## Globals used# PatchNum## Globals Set:# diPatch# ObsoletedBy# ThisPatchFnd# PatchedPkgs## Revision History# 1995-08-01 Added PATCH_OBSOLETES and expanded the tests for# direct instance patches since all necessary# is reviewed at this time, this function also# tests for obsolescence, dependencies and# incompatibilities.#function eval_inst_patches{typeset -i TestCount=0typeset -i ArrayCount=0typeset -i PatchFound=0typeset -i req_count=0typeset -i sr_count=0set -A PkgArrElemset -A ObsArrElemset -A ReqsArrElemset -A IncsArrElemset -A PatchArrElem# Use the file /var/sadm/patch/.patchDB instead of# gathering the informationif [[ -s "$PATCHDBFILE" && "$recreatePatchDB" = "no" ]]; then$GREP -v "Version" $PATCHDBFILEreturnelif [[ "$is_an_instpatches" = "yes" ]]thencat $INSTPATCHES_FILEreturnfiolddir=$(pwd)## First get the old-style patches and obsoletions#if [ -d $1 -a -d $PATCHDB ]thencd $1patches=patches=$(grep -l SUNW_PATCHID ./*/pkginfo | \xargs $SED -n 's/^SUNW_PATCHID=//p' | sort -u)if [ "$patches" != "" ]thenfor apatch in $patchesdooutstr="Patch: $apatch Obsoletes: "# Scan all the installed packages for this# patch number and return the effected# package instancespatchvers=$(grep -l "SUNW_PATCHID=$apatch" \./*/pkginfo | $SED 's,^./\(.*\)/pkginfo$,\1,' )# If there's a PATCH_INFO entry then this# is really a direct instance patchfor package in $patchversdobreak;done$(grep "PATCH_INFO_$apatch" $package/pkginfo 1>/dev/null 2>&1)if [[ $? -eq 0 ]]thencontinuefiPatchFound=1obsoletes_printed="n"for vers in $patchversdoif [ "$obsoletes_printed" = "n" ]thenoutstr="$outstr$($SED -n \'s/SUNW_OBSOLETES=//p' \./$vers/pkginfo) Packages: "outstr="$outstr$vers $($SED -n \'s/VERSION=//p' \./$vers/pkginfo)"obsoletes_printed="y"elseoutstr="$outstr, $vers $($SED \-n 's/VERSION=//p' \./$vers/pkginfo)"fidone# The current patch is a progressive# instance patchif [[ $apatch = "$PatchNum" ]]thendiPatch="no"ThisPatchFnd="yes"fiecho $outstr | tee -a $INSTPATCHES_FILEdonefifi## Now get the direct instance patches## DIPatches is a non-repeating list of all patches applied# to the system.#typeset -i TempCount=0InstPkgs=$(pkginfo -R $ROOTDIR | $NAWK ' { print $2; } ')for package in $InstPkgsdoDIPatches=$(pkgparam -R $ROOTDIR $package PATCHLIST)for patch in $DIPatchesdoget_base_code $patchpatch_base=$cur_base_codeget_vers_no $patch $patch_basepatch_vers=$cur_vers_noPatchFound=1;# Get the obsoletes from each installed packagetmpStr=""tmpStr=$(pkgparam -R $ROOTDIR $package PATCH_INFO_$patch)obsoletes=${tmpStr##*Obsoletes:}obsoletes=${obsoletes%%Requires:*}#obsoletes=$(echo $tmpStr | $GREP Obsoletes: | $NAWK ' \#{ print substr($0, match($0, "Obsoletes:")+11) } ' | \#$SED 's/Requires:.*//g')# Get the requires from each installed packagereqs=${tmpStr##*Requires:}reqs=${reqs%%Incompatibles:*}#reqs=$(echo $tmpStr | $GREP Requires: | $NAWK ' \#{ print substr($0, match($0, "Requires:")+10) } ' | \#$SED 's/Incompatibles:.*//g')# Get the incompatibles from each installed packageincs=${tmpStr##*Incompatibles:}#incs=$(echo $tmpStr | $GREP Incompatibles: | $NAWK ' \#{ print substr($0, match($0, "Incompatibles:")+15) } ')if [[ -n "$obsoletes" ]]thenfor obs in $obsoletes;doPatchArrElem[$ArrayCount]=$patch;ObsArrElem[$ArrayCount]=$obs;PkgArrElem[$ArrayCount]=$package;ArrayCount=ArrayCount+1;doneelsePatchArrElem[$ArrayCount]=$patch;ObsArrElem[$ArrayCount]="";PkgArrElem[$ArrayCount]=$package;ArrayCount=ArrayCount+1;fiif [[ -n "$reqs" ]]thenfor req in $reqs;doPatchArrElem[$ArrayCount]=$patch;ReqsArrElem[$ArrayCount]=$req;PkgArrElem[$ArrayCount]=$package;ArrayCount=ArrayCount+1;doneelsePatchArrElem[$ArrayCount]=$patch;ReqsArrElem[$ArrayCount]="";PkgArrElem[$ArrayCount]=$package;ArrayCount=ArrayCount+1;fiif [[ -n "$incs" ]]thenfor inc in $incs;doPatchArrElem[$ArrayCount]=$patch;IncsArrElem[$ArrayCount]=$inc;PkgArrElem[$ArrayCount]=$package;ArrayCount=ArrayCount+1;doneelsePatchArrElem[$ArrayCount]=$patch;IncsArrElem[$ArrayCount]="";PkgArrElem[$ArrayCount]=$package;ArrayCount=ArrayCount+1;fi# Check for already installedif [[ "$patch" = "$PatchNum" ]]thenThisPatchFnd="yes"diPatch="yes"fiCheckInstallingCompats $patch $patch_base $patch_verscompatsAlreadyChecked="yes"donedoneCheckUninstalledReqsunReqAlreadyChecked="yes"while [[ $TestCount -lt $ArrayCount ]]dotypeset -i TempCount=TestCount+1# Scan all entries matching the current onePatchArrEntry=${PatchArrElem[$TestCount]} # Current oneObsArrEntry=${ObsArrElem[$TestCount]}PkgArrEntry=${PkgArrElem[$TestCount]}ReqsArrEntry=${ReqsArrElem[$TestCount]}IncsArrEntry=${IncsArrElem[$TestCount]}if [[ "$PatchArrEntry" = "used" ]]thenTestCount=TestCount+1continuefiwhile [[ $TempCount -lt $ArrayCount ]]dotypeset -i dont_use;## If this is another line describing this patch#if [[ ${PatchArrElem[$TempCount]} = $PatchArrEntry ]]thendont_use=0;PatchArrElem[$TempCount]="used"for pkg in $PkgArrEntrydoif [[ $pkg = ${PkgArrElem[$TempCount]} ]]thendont_use=1;break;fidoneif [[ $dont_use = 0 ]]thenPkgArrEntry="$PkgArrEntry ${PkgArrElem[$TempCount]}"fidont_use=0;for obs in $ObsArrEntrydoif [[ $obs = ${ObsArrElem[$TempCount]} ]]thendont_use=1;break;fidoneif [[ $dont_use = 0 ]]thenObsArrEntry="$ObsArrEntry ${ObsArrElem[$TempCount]}"fidont_use=0;for inc in $IncsArrEntrydoif [[ $inc = ${IncsArrElem[$TempCount]} ]]thendont_use=1;break;fidoneif [[ $dont_use = 0 ]]thenIncsArrEntry="$IncsArrEntry ${IncsArrElem[$TempCount]}"fidont_use=0;for req in $ReqsArrEntrydoif [[ $req = ${ReqsArrElem[$TempCount]} ]]thendont_use=1;break;fidoneif [[ $dont_use = 0 ]]thenReqsArrEntry="$ReqsArrEntry ${ReqsArrElem[$TempCount]}"fifiTempCount=TempCount+1doneif [[ $PatchArrEntry = "$PatchNum" ]]; thenexport PatchedPkgs="$PkgArrEntry"fi# Now make it comma separated listsPkgArrEntry=$(echo $PkgArrEntry | $SED s/\ /,\ /g)ObsArrEntry=$(echo $ObsArrEntry | $SED s/\ /,\ /g)ReqsArrEntry=$(echo $ReqsArrEntry | $SED s/\ /,\ /g)IncsArrEntry=$(echo $IncsArrEntry | $SED s/\ /,\ /g)outstr="Patch: $PatchArrEntry Obsoletes: $ObsArrEntry \Requires: $ReqsArrEntry Incompatibles: $IncsArrEntry \Packages: $PkgArrEntry"echo $outstr | tee -a $INSTPATCHES_FILETestCount=TestCount+1doneif [[ ! -f "$PATCHDBFILE" || "$recreatePatchDB" == "yes" ]]; thenpkginfoParamSumecho "Version $PATCHDBVER $dbSum" > $PATCHDBFILEcat $INSTPATCHES_FILE >> $PATCHDBFILEchmod 600 $PATCHDBFILE > /dev/null 2>&1ficd $olddir;}# Description:# Export variables that prebackout or postbackout may need.function exportVars{export PatchNum="$PatchNum"export ROOTDIR="$ROOTDIR"}## Description:# Get the sum of the PATCHID and the PATCHLIST parameters.#function pkginfoParamSum{dbSum=$($NAWK '/PATCHID/ {print} /PATCHLIST/ {print}' \$PKGDB/*/pkginfo 2>/dev/null | $SUM | $NAWK '{print $1}')}## Description#function CheckUninstalledReqs{req_count=0;for req in $Requires; doif [[ ${ReqArrElem[$req_count]} = "no" ]]thenReqdPatchCnt=ReqdPatchCnt+1UninstReqs="$UninstReqs $req"fireq_count=req_count+1;doneif [[ $validate = "no" ]]thenReqdPatchCnt=0fi}# Description:# Find installing compatibility issues.## Parameters# $1 - installing patch# $2 - installed patch base code# $3 - installed patch version#function CheckInstallingCompats{# Check for incompatible patchesfor incompat in $Incompatdoget_base_code $incompatif [[ "$2" = "$cur_base_code" ]]thenget_vers_no $incompat $cur_base_codeif [[ $3 -ge $cur_vers_no ]]thenInstIncompat=$1fifidone# Check for required patchesreq_count=0;for required in $Requires; doget_base_code $requiredif [[ "$2" = "$cur_base_code" ]]thenget_vers_no $required $cur_base_codeif [[ $3 -ge $cur_vers_no ]]thenReqArrElem[$req_count]="yes"fifireq_count=req_count+1donefor obs_entry in $obsoletesdoget_base_code $obs_entryif [[ "$cur_base_code" = "$PatchBase" ]]thenget_vers_no $obs_entry $cur_base_codeif [[ $cur_vers_no -ge $PatchVers ]]thenObsoletedBy=$1elseObsoletePast=$PatchBaseObsoletedBy=$1fifidone}# Description:# Print out the usage message to the screen# Parameters:# nonefunction print_usage{cat<<EOFUsage: patchrm [-f] [-B backout_dir] [-R <client_root_path> | -S <service>][-C <net_install_image>] <patch_id>EOF# This line gets inserted after Usage message.# [-C <net_install_image>]}# Description:# Patch obsolecense message, printed if the patch being backed# out was superceded by other patches# Parameters:# $1 - patch ID# $2 - patch revision number#function print_obsolete_msg{outstr="This patch was obsoleted by patch $1"if [[ "$2" = "none" ]]thenoutstr="$outstr."elseoutstr="$outstr-$2."fi/usr/bin/gettext "$outstr\n\nPatches must be backed out in the reverse order in\nwhich they were installed.\n\nPatchrm exiting.\n\n"}# Description:# Find the appropriate softinfo files for the manager and the target.# Parameters:# $1 ROOT of target filesystem# Globals set:# TRGSOFTINFO# MGRSOFTINFO# Globals used:# OLD_SOFTINFO# NEW_SOFTINFOfunction find_softinfos{if [[ "$netImage" = "boot" ]]thenreturnfiif [[ -f $NEW_SOFTINFO ]]thenMGRSOFTINFO=$NEW_SOFTINFOelif [[ -f $OLD_SOFTINFO ]]thenMGRSOFTINFO=$OLD_SOFTINFOfiif [[ "$1" = "/" || "$1" = "" ]]thenTRGSOFTINFO=MGRSOFTINFOelif [[ -f $1$NEW_SOFTINFO ]]thenTRGSOFTINFO=$1$NEW_SOFTINFOelif [[ -f $1$OLD_SOFTINFO ]]thenTRGSOFTINFO=$1$OLD_SOFTINFOfi}# Description:# Check the host system for 2.6 existence.#function check_for_2_6{# Only the managing hosts OS is checked for now# 9/21/96mgrOS=mgrOS=$($UNAME -r)if [[ "$mgrOS" -le "5.5.1" ]]then/usr/bin/gettext "WARNING: patchrm must be executed from a 2.6 or later system.\n\n"exit $?fi}# Description:# Parse the arguments and set all affected global variables# Parameters:# Arguments to patchrm# Globals Set:# force# PatchNum# ROOTDIR# PATCHDB# PKGDB# PKGDBARG# CONTENTS# Globals used:# Mgrprodver# MGRSOFTINO# TRGSOFTINFO#function parse_args{# Inserted for readability reasonsecho ""service_specified="n"rootdir_specified="n"origdir=$(pwd)while [[ "$1" != "" ]]docase $1 in-f) force="yes"shift;;-B) shiftif [[ -d $1 ]]thendetermine_directory $1if [[ $ret = 0 ]]thenPATCH_UNDO_ARCHIVE=$1elsePATCH_UNDO_ARCHIVE=$curdirfiDASHB_SUPPLIED="yes"TEMP_PATCH_UNDO_ARCHIVE=$PATCH_UNDO_ARCHIVEelse/usr/bin/gettext "Specified backout directory $1 cannot be found.\n"exit 1fishift;;-V) echo "@(#) patchrm.ksh 2.4 99/04/06"exit 0shift;;-S) shiftif [[ "$service_specified" != "n" ]]then/usr/bin/gettext "Only one service may be defined.\n"print_usageexit 1elif [[ "$rootdir_specified" != "n" ]]then/usr/bin/gettext "The -S and -R options are mutually exclusive.\n"print_usageexit 1fifind_softinfos /export/$1get_OS_version "$TRGSOFTINFO" "$MGRSOFTINFO" "$1"if [ "$1" != "$Mgrprodver" ]thenif [ -d "/export/$1$PKGDB" ]thenROOTDIR=/export/$1PATCHDB=$ROOTDIR$PATCHDBPKGDB=$ROOTDIR$PKGDBSOFTINFO=$ROOTDIR$SOFTINFOPKGDBARG="-R $ROOTDIR"CONTENTS=$ROOTDIR$CONTENTSservice_specified="y"else/usr/bin/gettext "The $1 service cannot be found on this system.\n"print_usagepatch_quit 1fifishift;;-R) shiftif [[ "$rootdir_specified" != "n" ]]then/usr/bin/gettext "Only one client may be defined.\n"print_usageexit 1elif [[ "$service_specified" != "n" ]]then/usr/bin/gettext "The -S and -R options are mutually exclusive.\n"print_usageexit 1fiif [[ -d "$1" ]]thendetermine_directory $1if [[ $ret = 0 ]]thenROOTDIR=$1elseROOTDIR=$curdirfiPATCHDB=$ROOTDIR/var/sadm/patchPKGDB=$ROOTDIR/var/sadm/pkgSOFTINFO=$ROOTDIR$SOFTINFOPKGDBARG="-R $ROOTDIR"CONTENTS=$ROOTDIR$CONTENTSrootdir_specified="y"else/usr/bin/gettext "The $1 directory cannot be found on this system.\n"print_usageexit 1fishift;;-C) shiftif [[ "$service_specified" = "y" || "$rootdir_specified" = "y" ]]then/usr/bin/gettext "The -S, -R and -C arguments are mutually exclusive.\n"print_usagepatch_quit 1fiif [ ! -d "$1" ]then/usr/bin/gettext "The path to the net install image $1 cannot be found on this disk.\n"print_usagepatch_quit 1elsedetermine_directory $1if [[ $ret = 0 ]]thenROOTDIR=$1elseROOTDIR=$curdirfiPATCHDB=$ROOTDIR$PATCHDBPKGDB=$ROOTDIR$PKGDBPKGDBARG="-R $ROOTDIR"netImage="boot"fishift;;-*) print_usageexit 1;;*) break;;esacdonePatchNum=$1PATCHDBFILE=$ROOTDIR/var/sadm/patch/.patchDBRECOVERDIR=$ROOTDIR/var/sadm/.patchRec## If there is no patch number specified, exit with an error.#if [[ "$PatchNum" = "" ]]then/usr/bin/gettext "No patch number was specified.\n"print_usageexit 1fi}# Description:# Derive the full path name from a (possibly) relative path name.# Parameters:# $1 - command line argument## Globals Used:# ret# curdirfunction determine_directory{$(valpath -a $1)ret=$?if [[ $ret != 0 ]]thencd $1 3>/dev/nullif [[ $? = 0 ]]thencurdir=$(pwd)cd $origdirelse/usr/bin/gettext "Can not determine relative directory.\n"patch_quit 13fielsereturnfi}# Description:# Make sure the effective UID is '0'# Parameters:# nonefunction validate_uid{typeset -i uiduid=$(id | $SED 's/uid=\([0-9]*\)(.*/\1/')if (( uid != 0 ))then/usr/bin/gettext "You must be root to execute this script.\n"exit 3fi}# Description:# Get the product version <name>_<version> of local Solaris installation# Parameters:# $1 target host softinfo directory path# $2 managing host softinfo directory path# $3 root of the target host# Globals Set:# prodver#function get_OS_version{# If this a patch to a net install image we don't care about# the managing and target host we know it will be a 2.6 or# beyond OS.if [[ "$netImage" = "boot" ]]thenMgrProduct="Solaris"MgrOSVers="2.6"Mgrprodver=$MgrProduct"_"$MgrOSVersTrgOSVers=$MgrOSVersProduct=$MgrProductprodver=$Mgrprodverreturnfiif [[ "$2" != "none" ]]thenMgrProduct=$($SED -n 's/^OS=\(.*\)/\1/p' $2)MgrOSVers=$($SED -n 's/^VERSION=\(.*\)/\1/p' $2)Mgrprodver=$MgrProduct"_"$MgrOSVerselseMgrProduct="Solaris"MgrOSVers=$(uname -r | $SED -n -e 's/5\./2\./p' -e 's/4\./1\./p')Mgrprodver=$MgrProduct"_"$MgrOSVersfiif [[ $3 = "/" ]] # If there's not a clientthenProduct=$MgrProductTrgOSVers=$MgrOSVersprodver=$Mgrprodver# OK, there is a clientelif [[ "$1" = "none" ]] # but no softinfo filethen/usr/bin/gettext "patchrm is unable to find the INST_RELEASE file for the target\nfilesystem. This file must be present for patchrm to function correctly.\n"patch_quit 11elseProduct=$($SED -n 's/^OS=\(.*\)/\1/p' $1)TrgOSVers=$($SED -n 's/^VERSION=\(.*\)/\1/p' $1)prodver=$Product"_"$TrgOSVersfi}# Description:# Build the admin script for pkgadd# Parameters:# none# Globals Used:# ADMINFILEfunction build_admin{if [[ "$PatchMethod" = "direct" && -f /var/sadm/install/admin/patch ]]thenADMINFILE=/var/sadm/install/admin/patchelsecat >$ADMINFILE <<EOFmail=instance=uniquepartial=nocheckrunlevel=nocheckidepend=nocheckrdepend=nocheckspace=quitsetuid=nocheckconflict=nocheckaction=nocheckbasedir=defaultEOFfi}# Description:# Restore old versions of files# Parameters:# $1 - patch database directory# $2 - patch number# $3 - package command relocation argument# $4 - path name of contents file#function restore_orig_files{olddir=file=ownerfound=srch=cfpath=instlist=filelist=if [[ ! -f $1/$2/.nofilestosave ]]then/usr/bin/gettext "Restoring previous version of files...\n"if [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]thenolddir=$PATCH_UNDO_ARCHIVEelseolddir=$(pwd)olddir=$olddir/saveficd $ROOTDIR# Must retain backwards compatibility to restore# archives which were not stored as filesif [[ -f $olddir/archive.cpio ]]thenfilelist=$(cat $olddir/archive.cpio | cpio -it 2>/dev/null)cpio -idumv -I $olddir/archive.cpioelseif [[ -f $olddir/archive.cpio.Z ]]thenfilelist=$(zcat $olddir/archive.cpio.Z | \cpio -it 2>/dev/null)zcat $olddir/archive.cpio.Z | cpio -idumvelsefilelist=$($FIND . -print | $SED "s/^.//")$FIND . -print | cpio -pdumv /fifiif [[ $? -ne 0 ]]then/usr/bin/gettext "Restore of old files failed.\nSee Install.info file for instructions.\n"$RM -f /tmp/*.$$remove_librariesexit 7fi/usr/bin/gettext "Making package database consistent with restored files:\n"$RM -f /tmp/fixfile.$$ > /dev/null 2>&1for file in $filelistdoif [[ ! -f $file || -h $file ]]thencontinuefi# if file failed validation when the patch was# installed, don't do an installf on it. It should# continue to fail validation after the patch is# backed out.file1=$(expr $file : '\(\/.*\)')if [[ "$file1" = "" ]]thenfile1="/"$filefisrch="^$file1\$"if [[ -f $1/$2/.validation.errors ]] && \grep "$srch" $1/$2/.validation.errors >/dev/null 2>&1thencontinuefi# The following commands find the file's entry in the# contents file, and return the first field of the# entry. If the file is a hard link, the first field# will contain an "=". This will cause the -f test to# fail and we won't try to installf the file.srch="^$file1[ =]"cfpath=$(grep "$srch" $CONTENTS | $SED 's/ .*//')if [[ "$cfpath" = "" || ! -f "$ROOTDIR$cfpath" ]]thencontinuefiownerfound=no# Parsing pkgchk output is complicated because all text# may be localized. Currently the only line in the# output which contains a tab is the line of packages# owning the file, so we search for lines containing a# tab. This is probably reasonably safe. If any of the# text lines end up with tabs due to localization, the# pkginfo check should protect us from calling installf# with a bogus package instance argument.pkgchk $3 -lp $file1 | grep ' ' | \while read instlistdofor i in $instlistdopkginfo $3 $i >/dev/null 2>&1if [[ $? -eq 0 ]]thenecho $i $file1 >> /tmp/fixfile.$$ownerfound=yesbreakfidoneif [[ $ownerfound = "yes" ]]thenbreakfidonedoneif [[ -s /tmp/fixfile.$$ ]]then$SED 's/^\([^ ]*\).*/\1/' /tmp/fixfile.$$ | sort -u | \while read pkginstdogrep "^${pkginst} " /tmp/fixfile.$$ | \$SED 's/^[^ ]* \(.*\)/\1/' | \if [[ "$ROOTDIR" != "/" ]]theninstallf $PKGDBARG $pkginst -installf $PKGDBARG -f $pkginstelseinstallf $pkginst -installf -f $pkginstfidoneficd $olddirfi}## Description:# Change directory to location of patch# Parameters:# $1 - patch database directory# $2 - patch number# Globals Set:# patchdir# PatchBase# PatchVersfunction activate_patch{result=""if [[ "$recreatePatchDB" = "yes" || ! -f "$PATCHDBFILE" ]]; theneval_inst_patches $PKGDB > /dev/null 2>&1else # New style patch data baseresult=$($GREP "Patch: $PatchNum" $PATCHDBFILE)if [[ -n $result ]]; thenThisPatchFnd="yes"PatchedPkgs=$($GREP "Patch: $PatchNum" $PATCHDBFILE | \$NAWK ' {print substr($0, match($0, "Packages:")+10) }' | \$SED 's/,//g')for p in $PatchedPkgs; dopList=""pList=$(pkgparam -f $PKGDB/$p/pkginfo PATCHLIST | \$GREP $PatchNum)if [[ -n "$pList" ]]; thendiPatch="yes"breakelsediPatch="no"fidonefifiif [[ $ThisPatchFnd = "yes" ]]thenpatchdir=$1/$2# For direct instance patches, this may not be hereif [[ -d $patchdir ]]thencd $patchdirfi## Get the patch base code (the number up to the version prefix)# and the patch revision number (the number after the version prefix).#get_base_code $PatchNumPatchBase=$cur_base_codeget_vers_no $PatchNum $cur_base_codePatchVers=$cur_vers_noelse/usr/bin/gettext "Patch $2 has not been applied to this system.\n"if [[ -d $1/$2 ]]then/usr/bin/gettext "Will remove directory $1/$2\n"$RM -r $1/$2fipatch_quit 2fi}# Description:# Find the package instances for this patch# Parameters:# $1 - package database directory# $2 - patch number# Globals Set:# pkginstlistfunction get_pkg_instances{pkginst=j=for j in $1/*doif grep -s "SUNW_PATCHID *= *$2" $j/pkginfo > /dev/null 2>&1thenpkginst=$(basename $j)pkginstlist="$pkginstlist $pkginst"fidone}# Description:# Check to see if this patch was obsoleted by another patch.# Parameters:# $1 - patch database directory# $2 - patch ID# $3 - patch revisionfunction check_if_obsolete{if [[ "$diPatch" = "yes" ]]thenif [[ "$ObsoletedBy" = "none" ]]thenreturnelseprint_obsolete_msg "$ObsoletedBy" "none"exit 6fielsePatchid=oldbase=oldrev=opatchid=obase=obsoletes=i=j=if [[ -d $1 ]]thencd $1for i in * Xdoif [[ $i = X || "$i" = "*" ]]thenbreakelif [[ ! -d $i ]]thencontinueficd $ifor j in */pkginfo Xdoif [[ "$j" = "X" || "$j" = "*/pkginfo" ]]thenbreakfiPatchid=$($SED -n 's/^[ ]*SUNW_PATCHID[ ]*=[ ]*\([^ ]*\)[ ]*$/\1/p' $j)if [[ "$Patchid" = "" ]]thencontinuefioldbase=${Patchid%-*}oldrev=${Patchid#*-}if [[ $oldbase = $2 && $3 -lt $oldrev ]]thenprint_obsolete_msg "$2" "$oldrev"exit 6fiobsoletes=$($SED -n 's/^[ ]*SUNW_OBSOLETES[ ]*=[ ]*\([^ ]*\)[ ]*$/\1/p' $j)while [ "$obsoletes" != "" ]doopatchid=$(expr $obsoletes : '\([0-9\-]*\).*')obsoletes=$(expr $obsoletes : '[0-9\-]*[ ,]*\(.*\)')# patchrevent infinite loop. If we couldn't# find a valid patch id, just quit.if [[ "$opatchid" = "" ]]thenbreak;fiobase=$(expr $opatchid : '\(.*\)-.*')if [[ "$obase" = "" ]]then# no revision field in opatchid,# might be supported someday# (we don't use the revision# field for obsoletion testing)obase=$opatchidfiif [[ $obase = $2 && $2 != $oldbase ]]thenprint_obsolete_msg "$Patchid" "none"exit 6fidonedonecd $1donefifi}# Description:# Check to see if originally modified files were saved. If not,# the patch cannot be backed out.# Parameters:# $1 - patch database directory# $2 - patch numberfunction check_if_saved{if [[ ! -f $1/$2/.oldfilessaved && ! -f $1/$2/.nofilestosave ]]then/usr/bin/gettext "Patch $2 was installed without backing up the original files.\nIt cannot be backed out.\n"exit 4fi}# Description:# Get the list of packages# Parameters:# $1 - patch database directory# $2 - patch number# Globals Set:# pkglistfunction get_package_list{pkg=i=cd $1/$2for i in */pkgmapdopkg=`expr $i : '\(.*\)/pkgmap'`pkglist="$pkglist $pkg"done}# Description:# Parameters:# $1 - patch database directory# $2 - patch number# $3 - softinfo directory# $4 - product version# Globals Used:# TMPSOFTfunction cleanup{$RM -f /tmp/*.$$if [[ -d $1 ]]thencd $1if [[ -f softinfo_sed ]]thensed -f softinfo_sed $3/$4 > $TMPSOFT$MV $3/$4 $3/sav.$4$CP $TMPSOFT $3/$4fi$RM -fr ./$2/*$RM -fr $2if [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]thenPATCH_UNDO_ARCHIVE=$(dirname $PATCH_UNDO_ARCHIVE)$RM -fr $PATCH_UNDO_ARCHIVE/$2fifiif [[ "$netImage" = "boot" && -d $ROOTDIR/mnt/root ]]thenrestore_net_imagefiif [[ -f "$PATCHDBFILE" ]]; thenInsertPkgDBSumfi}# Description:# Insert the sum of all the PATCHLIST and PATCHID parameters# to determine if the PATCHDBFILE needs to be recreated.function InsertPkgDBSum{pkgDBSum=$($NAWK '/PATCHID/ {print} /PATCHLIST/ {print}' \$PKGDB/*/pkginfo 2>/dev/null | $SUM | $NAWK '{print $1}')$NAWK -v ps="$pkgDBSum" '$1 ~ /Version/ { printf("%s %s %s\n", $1, $2, ps); next }{ print } ' $PATCHDBFILE > $PATCHDBFILE.tmp$MV -f $PATCHDBFILE.tmp $PATCHDBFILE}# Description:# Remove appropriate patch packages from the system# NOTE: this will not restore the overwritten or removed files, but will# remove any files which were added by the patch.# Parameters:# $1 - patch database directory# $2 - patch number# $3 - packaging command relocation argument# Globals Used:# ADMINFILE# pkginstlistfunction remove_patch_pkgs{pkgrmerr=i=if [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]thenif [[ ! -d $PATCH_UNDO_ARCHIVE ]]then/usr/bin/gettext "The backout data has been moved. Please supply\npatchrm with the new location of the archive.\n"patch_quit 12fififor i in $pkginstlistdo/usr/bin/gettext "\nRemoving patch package for $i:\n"echo pkgrm $3 -a $ADMINFILE -n $i $LOGFILEpkgrm $3 -a $ADMINFILE -n $i>$LOGFILE 2>&1pkgrmerr=$?cat $LOGFILE >>$1/$2/logcat $LOGFILE | grep -v "^$"$RM -f $LOGFILEif [[ $pkgrmerr != 0 && $pkgrmerr != 2 && $pkgrmerr != 10 && $pkgrmerr != 20 ]]then/usr/bin/gettext "pkgrm of $i package failed with return code $pkgrmerr.\nSee $1/$2/log for details.\n"$RM -fr /tmp/*.$$remove_librariesexit 5fidone}# Description:# Copy required libraries to TMP_LIB_DIR, set and# export LD_PRELOAD.# Parameters:# none# Environment Variables Set:# LD_PRELOAD#function move_libraries{typeset -i RevRev=$(uname -r | $SED -e 's/\..*$//')if (( Rev >= 5 ))thenif [[ ! -d $TMP_LIB_DIR ]]thenmkdir -p -m755 $TMP_LIB_DIRfiLD_PRELOAD=for Lib in libc libdl libelf libintl libw libgen libadmdoif [[ ! -f /usr/lib/${Lib}.so.1 ]]; thencontinuefi$CP /usr/lib/${Lib}.so.1 ${TMP_LIB_DIR}/${Lib}.so.1chown bin ${TMP_LIB_DIR}/${Lib}.so.1chgrp bin ${TMP_LIB_DIR}/${Lib}.so.1chmod 755 ${TMP_LIB_DIR}/${Lib}.so.1LD_PRELOAD="${LD_PRELOAD} ${TMP_LIB_DIR}/${Lib}.so.1"doneexport LD_PRELOADfi}# Description:# remove the TMP_LIB_DIR directory# Parameters:# none# Environment Variables Set:# LD_PRELOAD#function remove_libraries{LD_PRELOAD=export LD_PRELOAD$RM -rf $TMP_LIB_DIR}# Description:# unobsolete direct instance patches that this one obsoleted# Parameters:# none# Environment Variables Used:# ROOTDIR# InstPkgs# PatchNum#function di_unobsolete{cd $ROOTDIRcd var/sadm/pkgif [[ "$recreatePatchDB" = "no" ]]; thenInstPkgs=$(pkginfo -R $ROOTDIR | $NAWK ' { print $2; } ')fifor pkg in $InstPkgs; doPATCHLIST=$(pkgparam -R $ROOTDIR $pkg PATCHLIST)for Patchno in $PATCHLIST; docheck_remote_file $pkg $Patchnoarchive_path=$pkg/save/$Patchnoif [[ -f $archive_path/obsolete || -f $archive_path/obsolete.Z || -f $archive_path/remote ]]thenif [[ -f $archive_path/obsoleted_by ]]thenegrep -s $PatchNum $archive_path/obsoleted_byif [[ $? -eq 0 ]]thencat $archive_path/obsoleted_by | $NAWK -v patchno=$PatchNum '$0 ~ patchno { next; }{ print; } ' > $archive_path/obsoleted_by.newif [[ -f $archive_path/remote ]]thenrestore_remote_state $pkg $Patchnofiif [[ -s $archive_path/obsoleted_by.new ]]then$MV $archive_path/obsoleted_by.new $archive_path/obsoleted_byelse$RM -f $archive_path/obsoleted_by.new $archive_path/obsoleted_byif [[ -f $archive_path/remote ]]thencontinuefiif [[ -f $archive_path/obsolete ]]then$MV $archive_path/obsolete $archive_path/undoelse$MV $archive_path/obsolete.Z $archive_path/undo.Zfififififidonedone}# Description:# Load the patch compatibility arrays.## Parameters:# $1 - The line from the .patchDB.function LoadPtchArrays{installedPtch[$insPs]=""installedObs[$insPs]=""installedReq[$insPs]=""installedInc[$insPs]=""installedPkgs[$insPs]=""while (( "$#" != "0" ))docase $1 in"Patch:"|"Obsoletes:"|"Requires:"| \"Incompatibles:"|"Packages:" )mode=$1shift;;"Version" )break;;* )case $mode in"Patch:" )installedPtch[$insPs]=$1shift;;"Obsoletes:" )installedObs[$insPs]="${installedObs[$insPs]} $1"shift;;"Requires:" )installedReq[$insPs]="${installedReq[$insPs]} $1"shift;;"Incompatibles:" )installedInc[$insPs]="${installedInc[$insPs]} $1"shift;;"Packages:" )installedPkgs[$insPs]="${installedPkgs[$insPs]} $1"shift;;esacesacdone}# Description:# Check to see if any pkginfo files have changed since the last# patchadd or patchrm. If so, recreate the patch database.# NOTE: There will be times when the database is considered out# of sync due to a pkg command.#function check_PatchDBs{typeset -i pdbSum=0if [[ -f $PATCHDBFILE ]]; thenpkginfoParamSumpdbSum=$($NAWK ' $1 ~ /Version/ { print $3 } ' $PATCHDBFILE)if (( dbSum != pdbSum )); thenrecreatePatchDB="yes"$RM -f $PATCHDBFILEfielsepkginfoParamSumrecreatePatchDB="yes"fi}# Description:# Check to see if the patch being backed out has other patches# installed that require it to be there.# Parameters:# none# Locals Used# tmp# list# requires# obsPatch# pkg#function check_REQUIRE{set -A installedPtchset -A installedObsset -A installedReqset -A installedIncset -A installedPkgstypeset -i ctr=0typeset -i outctr=0typeset -i inctr=0typeset -i obctr=0typeset -i insPs=0typeset -i ptch=0typeset -i outPtch=0typeset -i reqStillMet=0requires=list=obsPatch=pkg=instBase=instVers=patchFile=""patchFileStripped=/tmp/patchDBstripped.$$# If the user doesn't care about the consequences# of not removing required patches first then we# skip this check.if [[ "$force" = "yes" ]]thenreturnfiif [[ -s "$PATCHDBFILE" ]]; thenpatchFile=$PATCHDBFILEelif [[ ! -s $INSTPATCHES_FILE ]]; thenreturnelsepatchFile=$INSTPATCHES_FILEfi$SED 's/,//g' $patchFile > $patchFileStrippedwhile read linedoLoadPtchArrays $lineinsPs=insPs+1done < $patchFileStripped#cd $PKGDBobsPatch=""ctr=1while (( ctr < insPs ))doget_base_code $patchinstBase=$cur_base_codeget_vers_no $patch $patch_baseinstVers=$cur_vers_noif [[ "$compatsAlreadyChecked" == "no" ]]; thenCheckInstallingCompats ${installedPtch[$ctr]} $instBase $instVersfictr=ctr+1doneif [[ "$unReqAlreadyChecked" == "no" ]]; thenCheckUninstalledReqsfictr=1while (( ctr < insPs ))do# We're only concerned about the patch being backed# out. If it obsoletes another patch we need to# check to see if the patch is required to be# installed.if [[ -n ${installedObs[$ctr]} ]]thenfor ob in ${installedObs[$ctr]}do# Only concerned with the patch that# is being backed out.if [[ ${installedPtch[$ctr]} != "$PatchNum" ]]thencontinuefiget_base_code $obobBase=$cur_base_codeobctr=0# We need to check every patch to see if# this patch obsoletes any patch that requires# it to be installed.while (( obctr < insPs ))dofor obReq in ${installedReq[$obctr]}doget_base_code $obReqobPatchBase=$cur_base_codeif [[ "$obBase" = "$obPatchBase" ]]then# If the requirement is still met# with a lower revision of an# installed patch then continueget_vers_no $ob $obBaseobVers=$cur_vers_noptch=0while (( ptch < insPs ))do# If there is only one patch# in the $obReq list there# will be an extra ' ' at the end# of the patch.get_base_code ${installedPtch[$ptch]}ptBase=$cur_base_codeget_vers_no ${installedPtch[$ptch]} \$cur_base_codeptVers=$cur_vers_noptch=ptch+1if [[ "$ptBase" != "$obBase" ]]thencontinuefiif [[ "$ptVers" -le "$obVers" ]]then# requirement still metreqStillMet=1breakfidoneif (( reqStillMet == 0 ))thenprint_require_msg ${installedPtch[$obctr]}fireqStillMet=0fidoneobctr=obctr+1donedonefi# Check any patch that has an require patch# contained in is PATCH_INFO line.if [[ -n ${installedReq[$ctr]} ]]thenfor req in ${installedReq[$ctr]}doget_base_code $reqreqBase=$cur_base_codeget_vers_no $req $cur_base_codereqVers=$cur_vers_noif [[ "$reqBase" = "$PatchBase" && \"$reqVers" -le "$PatchVers" || -n $obsPatch ]]then# We need to check all installed# patches incase a lower rev# is installed that still meets# the requirement. (sigh)ptch=0while (( ptch < insPs ))doget_base_code ${installedPtch[$ptch]}ptBase=$cur_base_codeget_vers_no ${installedPtch[$ptch]} $cur_base_codeptVers=$cur_vers_noptch=ptch+1if [[ "$ptBase" != "$reqBase" ]]thencontinuefiif [[ "$ptVers" -ge "$reqVers" && \"$PatchVers" != "$ptVers" ]]then# requirement still metreqStillMet=1breakfidoneif (( reqStillMet == 0 ))thenprint_require_msg ${installedPtch[$ctr]}fireqStillMet=0fidonefictr=ctr+1done}# Description:# Patch requires message.# out was superceded by other patches# Parameters:# $1 - required patch ID#function print_require_msg{/usr/bin/gettext "Patch $PatchNum is required to be installed by patch $1\nit cannot be backed out until patch $1 is backed out.\n"patch_quit 15}# Description:# Detect if there have been any implicit or explicit obsoletions.# Parameters:# none# Environment Variable Set:#function detect_obs{cd $ROOTDIRcd var/sadm/pkgif [[ $ThisPatchFnd = "no" ]]then/usr/bin/gettext "Patch $PatchNum has not been applied to this system.\n"exit 2fi## First scan for the undo and remote files and make sure, none of them have# been obsoleted#for pkg in $PatchedPkgs; doif [[ -f $pkg/pkginfo ]]thenif [[ -d $pkg/save/$PatchNum ]]thenif [[ -f $pkg/save/$PatchNum/remote ]]thencheck_remote_file $pkg $PatchNumif [[ ! -f $PATCH_UNDO_ARCHIVE/undo && ! -f $PATCH_UNDO_ARCHIVE/undo.Z ]]then/usr/bin/gettext "The backout archive has been moved.\nSupply the -B option to back out the patch.\n"patch_quit 12elif [[ -f $pkg/save/$PatchNum/obsoleted_by ]]thenObsoletedBy=$(cat $pkg/save/$PatchNum/obsoleted_by)print_obsolete_msg "$ObsoletedBy" "none"exit 6fielseif [[ -f $pkg/save/$PatchNum/obsolete || -f $pkg/save/$PatchNum/obsolete.Z ]]thenObsoletedBy=$(cat $pkg/save/$PatchNum/obsoleted_by)print_obsolete_msg "$ObsoletedBy" "none"exit 6elif [[ ! -f $pkg/save/$PatchNum/undo && ! -f $pkg/save/$PatchNum/undo.Z ]]then/usr/bin/gettext "Patch $PatchNum was installed without backing up the original files.\nIt cannot be backed out.\n"exit 4fifielse/usr/bin/gettext "Patch $PatchNum was installed without backing up the original files.\nIt cannot be backed out.\n"exit 4fielse/usr/bin/gettext "Patch $PatchNum was installed without backing up the original files.\nIt cannot be backed out.\n"exit 4fidone}# Description:# If backing out a patch in the mini-root invoke pkgadd with the -M option.# Parameters:# none# Globals Set:# MOPTION#function check_pkgadd_M_option {[[ "$mgrOS" > "5.5.1" ]] && [[ "$ROOTDIR" != "/" ]] && MOPTION="-M"}# Description:# backout a patch applied using direct instance patching# Parameters:# none# Environment Variable Set:#function di_backout{typeset -i Something_Backedout=0typeset -i exit_code=0cd $ROOTDIRcd var/sadm/pkg# The following is done since pkgadd will unpack the undo pkg in# /var/tmp. If backing out in the mini-root a writable scratch dir# needs to exist. /var/tmp is read only in the mini-root environment.#if [[ "$ROOTDIR" != "/" ]]; then#export TMPDIR="$ROOTDIR/var/sadm/patch/.tmp"#fi## With no obsoletions detected, we pkgadd the undo packages.#for pkg in $PatchedPkgs; docheck_remote_file $pkg $PatchNumif [[ "$PATCH_UNDO_ARCHIVE" != "none" && -f $PATCH_UNDO_ARCHIVE/undo.Z ]]thenuncompress $PATCH_UNDO_ARCHIVE/undo.Z 1> $LOGFILE 2>&1elif [[ -f $pkg/save/$PatchNum/undo.Z ]]thenuncompress $pkg/save/$PatchNum/undo.Z 1> $LOGFILE 2>&1fi# Get the prior patch list since the checkinstall script# doesn't have permission to make this enquiry.OLDLIST=$(pkgparam -R $ROOTDIR $pkg PATCHLIST)echo OLDLIST=\'$OLDLIST\' > $RESPONSE_FILEif [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]thenpkgadd $MOPTION -n -r $RESPONSE_FILE -R $ROOTDIR \-a $ADMINFILE -d $PATCH_UNDO_ARCHIVE/undo all \1>> $LOGFILE </dev/null 2>&1elsepkgadd $MOPTION -n -r $RESPONSE_FILE -R $ROOTDIR \-a $ADMINFILE -d $pkg/save/$PatchNum/undo all \1>> $LOGFILE </dev/null 2>&1fiexit_code=$?# Check for an apostrphe in the pkginfo file. This is needed# since pkgparam inserts '"'"' for any ' it finds.# This is a workaround for a bug in pkgparam. Pkgparam# is used in the generic preinstall script.$SED s,ApOsTrOpHe,\',g \$ROOTDIR/var/sadm/pkg/$pkg/pkginfo > /tmp/pkginfo.$$rm -f $ROOTDIR/var/sadm/pkg/$pkg/pkginfo 1>/dev/null 2>&1mv /tmp/pkginfo.$$ $ROOTDIR/var/sadm/pkg/$pkg/pkginfo \1>/dev/null 2>&1chmod 644 $ROOTDIR/var/sadm/pkg/$pkg/pkginform -f /tmp/pkginfo.$$# If it's a suspend (exit code 4), then the# message type is the appropriate patchrm# exit code and the appropriate message follows.# A suspend means, nothing has been installed.if (( exit_code == 4 )) # suspendthenMessage=$(egrep PaTcH_MsG $LOGFILE | $SED s/PaTcH_MsG\ //)if [[ $Message = "" ]]thenexit_code=5elseMsg_Type=$(echo $Message | $NAWK ' { print $1 } ')Message=$(echo $Message | $SED s/$Msg_Type\ //)/usr/bin/gettext "$Message\n" >> $LOGFILE/usr/bin/gettext "$Message\n"exit $Msg_Typefifiif ((exit_code == 5 ))then # administration/usr/bin/gettext "Backout has been halted due to administrative defaults.\n"cat $LOGFILEexit 11elif (( exit_code == 10 || exit_code == 20 ))then/usr/bin/gettext "NOTE: After backout the target host will need to be rebooted.\n"RebootRqd="yes"elif (( exit_code != 0 ))thenegrep ERROR $LOGFILEexit 7elseSomething_Backedout=1fidoneif (( Something_Backedout == 1 ))thendi_unobsoleteupdate_patchDBif [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]thenPATCH_UNDO_ARCHIVE=$(dirname $PATCH_UNDO_ARCHIVE)PATCH_UNDO_ARCHIVE=$(dirname $PATCH_UNDO_ARCHIVE)$RM -r $PATCH_UNDO_ARCHIVE/$PatchNumfielse/usr/bin/gettext "Patch number $PatchNum backout packages were not found.\n"fi}# Description# Update the new patch data base,function update_patchDB{if [[ ! -f $PATCHDBFILE ]]; thenreturnfi$FGREP -v "Patch: $PatchNum" $PATCHDBFILE > $PATCHDBFILE.tmp$MV -f $PATCHDBFILE.tmp $PATCHDBFILE}# Description:# check to see if the backout data is saved remotely# Parameters:# $1 - package associated with the patch# $2 - the patch number## Environment Variable Set:## PATCH_UNDO_ARCHIVE# OBS_PATCH_UNDO_ARCHIVEfunction check_remote_file{if [[ "$diPatch" = "yes" ]]thenif [[ ! -f $PKGDB/$1/save/$2/remote ]]thenreturnfiif [[ "$DASHB_SUPPLIED" = "yes" ]]thenif [[ $2 != "$PatchNum" ]]thenOBS_PATCH_UNDO_ARCHIVE=$TEMP_PATCH_UNDO_ARCHIVE/$2/$1elsePATCH_UNDO_ARCHIVE=$TEMP_PATCH_UNDO_ARCHIVE/$2/$1fielif [[ $2 != "$PatchNum" ]]thenOBS_PATCH_UNDO_ARCHIVE=$(grep "FIND_AT" $PKGDB/$1/save/$2/remote | $AWK -F= '{print $2}')OBS_PATCH_UNDO_ARCHIVE=$(dirname $OBS_PATCH_UNDO_ARCHIVE)elsePATCH_UNDO_ARCHIVE=$(grep "FIND_AT" $PKGDB/$1/save/$2/remote | $AWK -F= '{print $2}')PATCH_UNDO_ARCHIVE=$(dirname $PATCH_UNDO_ARCHIVE)fi# progressive instance logicelseif [[ ! -f $PATCHDB/$2/save/remote ]]thenreturnfiif [[ "$DASHB_SUPPLIED" = "yes" ]]thenPATCH_UNDO_ARCHIVE=$TEMP_PATCH_UNDO_ARCHIVE/$2/archive.cpioelsePATCH_UNDO_ARCHIVE=$(grep "FIND_AT" $PATCHDB/$2/save/remote | $AWK -F= '{print $2}')fiPATCH_UNDO_ARCHIVE=$(dirname $PATCH_UNDO_ARCHIVE)fi}# Description:# restore the STATE parameter back to the proper# state in the remote file# Parameters:# $1 - package associated with the patch# $2 - the patch number## Environment Variable Set:#function restore_remote_state{$(grep . $PKGDB/$1/save/$2/remote | $SED 's/STATE=.*/STATE=active/' > $TEMP_REMOTE)$RM -f $PKGDB/$1/save/$2/remote$MV $TEMP_REMOTE $PKGDB/$1/save/$2/remote$RM -f $TEMP_REMOTEchmod 644 $PKGDB/$1/save/$2/remote}# Description:# Call check_remote_file if the remote file is found# for progressive instance patches# Parameters:# $1 - patch database# $2 - the patch number## Globals Set:# nonefunction set_archive_path{if [[ ! -f $1/$2/remote ]]thencheck_remote_file $1 $2fi}# Description:# Setup the net install boot image to look like an installed system.# Parameters:# none# Globals Set:# none#function setup_net_image {if [[ "$netImage" != "boot" ]]thenreturnfi# Check to see if there was an interruption that left the loop back# mounts mounted for Net Install Patching.if [[ -d $ROOTDIR/mnt/root ]]thenrestore_net_imagefi# The .../Boot/.tmp_proto/root needs to be re-mapped to# .../Boot/tmp in order for the boot image to be patched# successfully.$MOUNT -F lofs -O $ROOTDIR/tmp $ROOTDIR/mnt$MOUNT -F lofs -O $ROOTDIR/.tmp_proto $ROOTDIR/tmp$MOUNT -F lofs -O $ROOTDIR/mnt/root/var $ROOTDIR/tmp/root/var# At this point patchrm thinks the net install image#is just like an installed image.}# Description:# Restore the net image to the way it was before mucking# with it in the setup_net_image function.# Parameters:# none# Globals Set:# none#function restore_net_image {if [[ "$netImage" != "boot" ]]thenreturnficd $origdir$UMOUNT $ROOTDIR/tmp/root/var$UMOUNT $ROOTDIR/tmp$UMOUNT $ROOTDIR/mnt}########################################################### Main routine########################################################### - Parse the argument list and set globals accordingly# - Make sure the user is running as 'root'# - Get the product version <name>_<version> of the local# Solaris installation# - activate the patchCmd=$0CmdArgs=$*validate_uidparse_args $*check_for_2_6find_softinfos $ROOTDIRget_OS_version $TRGSOFTINFO $MGRSOFTINFO $ROOTDIRcheck_file_recoverysetup_net_imagecheck_PatchDBs/usr/bin/gettext "Checking installed packages and patches...\n\n"activate_patch "$PATCHDB" "$PatchNum"exportVarsif [[ "$diPatch" != "yes" ]]thenecho $PatchNum | grep $PatchIdFormat >/dev/nullif [[ $? -ne 0 ]]then/usr/bin/gettext "Invalid patch id format: $PatchNum\n"exit 8fifi## Check to see if this patch was obsoleted by another patch#if [[ "$force" = "no" || "$diPatch" = "yes" ]]thencheck_if_obsolete "$PATCHDB" "$PatchBase" "$PatchVers"fiexecute_prebackout "$PATCHDB" "$PatchNum"# - Check to see if original files were actually saved# - Generate list of packages to be removed# - Find the package instances for this patch# - Build admin file for later use by pkgrm# - pkgrm patch packages# - Restore the original files which were overwritten by the patch# - Update the prodver file & cleanup tmp filesbuild_admin# If we're in the mini-root, invoke pkgadd with -M# or if the managing host is 2.6 or later.check_pkgadd_M_optionif [[ "$diPatch" = "yes" ]]thendetect_obscheck_REQUIRE/usr/bin/gettext "Backing out patch $PatchNum...\n\n"di_backout$RM -f $RESPONSE_FILEelseset_archive_path "$PATCHDB" "$PatchNum"check_if_saved "$PATCHDB" "$PatchNum"get_package_list "$PATCHDB" "$PatchNum"get_pkg_instances "$PKGDB" "$PatchNum"trap 'remove_libraries' HUP INT QUIT TERMmove_librariesremove_patch_pkgs "$PATCHDB" "$PatchNum" "$PKGDBARG"update_patchDBrestore_orig_files "$PATCHDB" "$PatchNum" "$PKGDBARG" "$CONTENTS"remove_librariesfiexecute_postbackout "$PATCHDB" "$PatchNum"cleanup "$PATCHDB" "$PatchNum" "$SOFTINFO" "$prodver"/usr/bin/gettext "Patch $PatchNum has been backed out.\n\n"exit 0