Blame | Last modification | View Log | RSS feed
#!/bin/ksh -hp#set -x## @(#) patchadd.ksh 2.5 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 apply a patch that's already been applied# 3 Effective UID is not root# 4 Attempt to save original files failed# 5 pkgadd failed# 6 Patch is obsoleted# 7 Invalid package directory# 8 Attempting to patch a package that is not installed# 9 Cannot access /usr/sbin/pkgadd (client problem)# 10 Package validation errors# 11 Error adding patch to root template# 12 Patch script terminated due to signal# 13 Symbolic link included in patch# 14 NOT USED# 15 The prepatch script had a return code other than 0.# 16 The postpatch script had a return code other than 0.# 17 Mismatch of the -d option between a previous patch# install and the current one.# 18 Not enough space in the file systems that are targets# of the patch.# 19 $SOFTINFO/INST_RELEASE file not found# 20 A direct instance patch was required but not found# 21 The required patches have not been installed on the manager# 22 A progressive instance patch was required but not found# 23 A restricted patch is already applied to the package# 24 An incompatible patch is applied# 25 A required patch is not applied# 26 The user specified backout data can't be found# 27 The relative directory supplied can't be found# 28 A pkginfo file is corrupt or missing# 29 Bad patch ID format# 30 Dryrun failure(s)# 31 Path given for -C option is invalid# 32 Must be running Solaris 2.6 or greater# 33 Bad formatted patch file or patch file not found## Set the path for use with these scripts.PATH=/usr/sadm/bin:/usr/sbin:/usr/bin:$PATHexport PATHumask 022# Global Files# Needed utilitiesDF=/usr/sbin/dfMV=/usr/bin/mvRM=/usr/bin/rmSED=/usr/bin/sedAWK=/usr/bin/awkNAWK=/usr/bin/nawkGREP=/usr/bin/grepEGREP=/usr/bin/egrepLS=/usr/bin/lsCP=/usr/bin/cpWC=/usr/bin/wcFIND=/usr/bin/findMD=/usr/bin/mkdirTOUCH=/usr/bin/touchDIFF=/usr/bin/diffTAIL=/usr/bin/tailMOUNT=/sbin/mountUMOUNT=/sbin/umountUNAME=/usr/bin/unameVALPATH=/usr/sadm/bin/valpathFGREP=/usr/bin/fgrepSUM=/usr/bin/summultiPtchInstall="no"multiPtchList=multiPtchStatus=lastPtchInList=patchdir=olddir=validate="yes"saveold="yes"netImage="none"dryrunDir="none"ROOTDIR="/"PATCHDB="/var/sadm/patch"PKGDB="/var/sadm/pkg"NEW_SOFTINFO="/var/sadm/system/admin/INST_RELEASE"OLD_SOFTINFO="/var/sadm/softinfo/INST_RELEASE"MGRSOFTINFO="none"TRGSOFTINFO="none"PKGDBARG=""INSTALL_PATCHDIR=""# This tells pkgadd to not check mounted FS's. Used in the mini-root.MOPTION=""PatchIdFormat='^[A-Z]*[0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9]$'# Version string of the patch data base file. Change this# anytime the format of the .patchDB file changes. Also needs# to be changed in patchrm.PATCHDBVER="1.0"# response file keywordsPATCH_UNCONDITIONAL="false"PATCH_PROGRESSIVE="true"PATCH_NO_UNDO="false"PATCH_BUILD_DIR="none"PATCH_UNDO_ARCHIVE="none"INTERRUPTION="no"DRYRUN="no"typeset -i Root_Kbytes_Needed=0typeset -i Kbytes_Required=0typeset -i Opt_Kbytes_Needed=0typeset -i Openwin_Kbytes_Needed=0typeset -i Usr_Kbytes_Needed=0typeset -i Var_Kbytes_Needed=0typeset -i ReqArrCount=0typeset -i ReqdPatchCnt=0typeset -i Something_Installed=0typeset -i interactive=0typeset -i req_count=0typeset -i dbSum=0typeset -i pdbSum=0# List of required commandsREQD_CMDS="/usr/sbin/removef /usr/sbin/installf /usr/sbin/pkgadd \/usr/bin/pkgparam /usr/bin/pkginfo"# Description:# Set the pid specific globals for use with multiple patch installation.# Parameters:# none#function set_globals{EXISTFILES=/tmp/existfiles.$$PATCHFILES=/tmp/patchfiles.$$PKGCOFILE=/tmp/pkgchk.out.$$VALERRFILE=/tmp/valerr.$$VALWARNFILE=/tmp/valwarn.$$ADMINTFILE=/tmp/admin.tmp.$$ADMINFILE=/tmp/admin.$$LOGFILE=/tmp/pkgaddlogTMP_ARCHIVE=/tmp/TmpArchive.$$TMP_FILELIST=/tmp/FileList.$$TMP_LIB_DIR=/tmp/TmpLibDir.$$INSTPATCHES_FILE=/tmp/MyShowrevFile.$$PARAMS_FILE=/tmp/ParamsFile.$$RESPONSE_FILE=/tmp/response.$$TEMP_REMOTE=/tmp/temp_remote.$$Obsoletes=Incompat=Requires=ObsoletePast=""UninstReqs=InstIncompat=Product=MgrProduct=OpenwinFS=OptFS=UsrFS=VarFS=ClientFS=pkglist=newpkglist=client="no"is_a_root_pkg="no"is_an_instpatches="no"ret=curdir=PatchNum=PatchBase=PatchVers=PatchMethod=PatchType=printpatches="no"ThisPatchFnd="no"ObsoletedBy="none"ReqdOSPatch="none"rootlist=isapplied="no"libs_are_moved="no"useRecFiles="no"recreatePatchDB="no"reapplied="no"Root_Kbytes_Needed=0Kbytes_Required=0Opt_Kbytes_Needed=0Openwin_Kbytes_Needed=0Usr_Kbytes_Needed=0Var_Kbytes_Needed=0ReqArrCount=0ReqdPatchCnt=0Something_Installed=0compatsAlreadyChecked="no"unReqAlreadyChecked="no"}# Description:# Usage message# Parameters:# none#function print_usage{cat << EOFUsage: patchadd [-u] [-d] [-B <backout_dir>][-S <service> | -R <client_root_path>][-C <net_install_image>] <patch>patchadd [-u] [-d] [-B <backout_dir>][-S <service> | -R <client_root_path>][-C <net_install_image>]-M patch_dir patch_id... | patch_dir patch_listpatchadd [-S <service> | -R <client_root_path>][-C <net_install_image>] -pEOF# This line is part of the usage msg}## Description:# Quit patchadd and clean up any remaining temporary files.## Parameters:# $1 - exitcode# $2 - Quit the entire installationfunction patch_quit { # exit codeif [[ "$lastPtchInList" != "$PatchNum" && $2 = "no" ]]then/usr/bin/gettext "WARNING: Skipping patch $PatchNum \n\n"returnelif [[ $1 -ne 0 ]]then/usr/bin/gettext "\nPatchadd is terminating.\n"fiif [[ "$netImage" != "none" && -d "$ROOTDIR/mnt/root" ]]thenrestore_net_imagefiremove_filesexit $1}## Description:# Remove the patch recovery directory if installation# was successful and any other files needing to be removed.## Globals Used:# RECOVERDIR# Something_Installedfunction remove_files {if (( Something_Installed == 1 ))then$RM -fr $RECOVERDIRfiif [[ $libs_are_moved = "yes" ]]thenremove_librariesfi$RM -f $INSTPATCHES_FILE$RM -f /tmp/*.$$.1$RM -f /tmp/archive.cpio*$RM -fr /tmp/*.$$$RM -f $patchFileStripped}## 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:# This function is an extension to the patch arch.# It allows patch/pkg engineers to include a script# that will execute before installpatch evaluates# dependencies. This is very risky and hopefully# this prePatch script is not malignent.## Parameters:# $1 - patch directory.# $2 - ROOTDIR# Globals Set:# none#function execute_prePatch{typeset -i retcode=0if [[ -x "$1/prePatch" ]]then/usr/bin/gettext "Executing prePatch script...\n"$1/prePatch "$1" "$2"retcode=$?if (( retcode != 0 ))then/usr/bin/gettext "The prePatch script exited with return code $retcode.\n"patch_quit 15 "no"return 0fifireturn 1}## Description:# If a prepatch executable exists in the $1 directory, execute it.# If the return code is 0, continue. Otherwise, exit with code 15.## Parameters:# $1 - patch directory.# Globals Set:# none#function execute_prepatch{typeset -i retcode=0if [[ -x "$1/prepatch" ]]then/usr/bin/gettext "Executing prepatch script...\n"$1/prepatchretcode=$?if (( retcode != 0 ))then/usr/bin/gettext "The prepatch script exited with return code $retcode.\n"patch_quit 15 "no"return 0fifireturn 1}## Description:# If a postpatch executable exists in the $1 directory, execute it.# If the return code is 0, continue. Otherwise, if this is not# a re-installation of the patch, execute the# patchrm script and exit with a return code 16.# If this is a re-installation, don't backout the patch. Instead,# send a message to the user.## Parameters:# $1 - patch database directory# $2 - patch number# $3 - patch directory.# Globals Set:# none#function execute_postpatch{# 31-July-2002 VC: added additional postpatch script location.#m_postpatch_List="$3/postpatch $1/$2/postpatch"for i in $m_postpatch_Listdotypeset -i retcode=0if [[ -x "$i" ]]then/usr/bin/gettext "Executing postpatch script...\n"$iretcode=$?if (( retcode != 0 ))then/usr/bin/gettext "The postpatch script exited with return code $retcode.\n"if [[ "$isapplied" = "no" ]]then$CP $1/$2/log /tmp/log.$2/usr/bin/gettext "Backing out patch:\n"cd $3if [[ "$ROOTDIR" != "/" ]]then/usr/sbin/patchrm $PKGDBARG $2else/usr/sbin/patchrm $2fi/usr/bin/gettext "See /tmp/log.$2 for more details.\n"else/usr/bin/gettext "Not backing out patch because this is a re-installation.\nThe system may be in an unstable state!\nSee $1/$2/log for more details.\n" |tee -a $1/$2/logfipatch_quit 16 "no"return 0fifidonereturn 1}# Description:# Check to see if the pkginfo command reports an error# before using it to evaluate the installed pkgs.## Parameters:# none## Globals used# PKGDB#function chk_pkginfo_cmd{if [[ "$netImage" != "none" ]]thenreturnfiprevDir=$(pwd)cd $PKGDBfor pkg in *dopkginfo -R $ROOTDIR $pkg > /dev/null 2>&1if [[ $? -ne 0 ]]then/usr/bin/gettext "The pkginfo file for package: $pkg is either corrupt or missing.\nA fsck of the file system or re-installing $pkg\nis recommended before installing any patches!\n"patch_quit 28 "yes"fidonecd $prevDir}# Description# Add the installing patches information into the patch data base.## Parameters:# $1 - patch numberfunction update_patchDB{# At this point the patch has installed and we now update# the new patch database.if [[ "$reapplied" = "yes" ]]; thenif (( Something_Installed == 1 )); then$RM -f $PATCHDBFILEreturnfifireallyNotThere=""pkginfoParamSumif [[ ! -f $PATCHDBFILE ]]; thenecho "Version $PATCHDBVER $dbSum" > $PATCHDBFILEchmod 644 $PATCHDBFILE > /dev/null 2>&1else$NAWK -v ps="$dbSum" '$1 ~ /Version/ { printf("%s %s %s\n", $1, $2, ps); next }{ print } ' $PATCHDBFILE > $PATCHDBFILE.tmp$MV -f $PATCHDBFILE.tmp $PATCHDBFILEfireallyNotThere=$($GREP "Patch:[ ]*$1" $PATCHDBFILE)if [[ -z "$reallyNotThere" ]]; thenif [[ -n "$Requires" && -n "$Incompat" ]]; thenecho "Patch: $1 Obsoletes: $Obsoletes Requires: $Requires Incompatibles: $Incompat Packages: $pkgDispList" >> $PATCHDBFILEelif [[ -n "$Requires" ]]; thenecho "Patch: $1 Obsoletes: $Obsoletes Requires: $Requires Incompatibles: $Incompat Packages: $pkgDispList" >> $PATCHDBFILEelif [[ -n "$Incompat" ]]; thenecho "Patch: $1 Obsoletes: $Obsoletes Requires: $Requires Incompatibles: $Incompat Packages: $pkgDispList" >> $PATCHDBFILEelseecho "Patch: $1 Obsoletes: $Obsoletes Requires: Incompatibles: Packages: $pkgDispList" >> $PATCHDBFILEfifi}# 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## Locals used# arg# tmpStr## Globals used# PatchNum# force## Globals Set:# ObsoletedBy# ThisPatchFnd# PatchedPkgs# ReqdOSPatchFnd The patch that this OS release requires was found## 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 sr_count=0set -A PkgArrElemset -A ObsArrElemset -A ReqsArrElemset -A IncsArrElemset -A PatchArrEleminstPtchs=""fnd=""# Use the file /var/sadm/patch/.patchDB instead of# gathering the informationif [[ -s "$PATCHDBFILE" && "$recreatePatchDB" = "no" ]]; thenif [[ "$printpatches" = "yes" ]]; theninstPtchs=$($GREP -v "Version" $PATCHDBFILE)if [[ -n "$instPtchs" ]]; then/usr/bin/gettext "$instPtchs\n\n"else/usr/bin/gettext "No patches installed\n\n"fireturnfifnd=$($GREP "^Patch:[ ]*$PatchNum" $PATCHDBFILE)if [[ -n "$fnd" ]]; thenThisPatchFnd="yes"fi$GREP -v "Version" $PATCHDBFILEreturnelif [[ "$is_an_instpatches" = "yes" ]]thencat $INSTPATCHES_FILEreturnfiolddir=$(pwd)## First get the old-style patches and obsoletions#if [[ -d $1 && -d $PATCHDB && $netImage != "product" ]]thencd $1patches=""# This gets old and new style patchespatches=$($GREP -l SUNW_PATCHID ./*/pkginfo 2>/dev/null | \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 2>/dev/null | \$SED 's,^./\(.*\)/pkginfo$,\1,' )# If there's a PATCH_INFO entry then this# is really a direct instance patchfor package in $patchversdobreak;done$($GREP -b "PATCH_INFO_$apatch" $package/pkginfo 1>/dev/null 2>&1)if [[ $? -eq 0 ]]thencontinuefiPatchFound=1# Get the obsoletes listobsoletes_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 direct instance patchif [[ $apatch = "$PatchNum" ]]thenThisPatchFnd="yes"fiif [[ "$printpatches" = "yes" ]]thenecho $outstr | tee -a $INSTPATCHES_FILEelseecho $outstr | tee -a $INSTPATCHES_FILEis_an_instpatches="yes"fidonefifi## Now get the direct instance patches## DIPatches is a non-repeating list of all patches applied# to the system.#if [[ "$netImage" = "product" ]]thenarg="-d"elsearg="-R"fipkginfo $arg $ROOTDIR | $NAWK ' { print $2; } ' | while read pkgdoDIPatches=$(pkgparam $arg $ROOTDIR $pkg 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 $arg $ROOTDIR $pkg 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]=$pkg;ArrayCount=ArrayCount+1;doneelsePatchArrElem[$ArrayCount]=$patch;ObsArrElem[$ArrayCount]="";PkgArrElem[$ArrayCount]=$pkg;ArrayCount=ArrayCount+1;fiif [[ -n "$reqs" ]]thenfor req in $reqs;doPatchArrElem[$ArrayCount]=$patch;ReqsArrElem[$ArrayCount]=$req;PkgArrElem[$ArrayCount]=$pkg;ArrayCount=ArrayCount+1;doneelsePatchArrElem[$ArrayCount]=$patch;ReqsArrElem[$ArrayCount]="";PkgArrElem[$ArrayCount]=$pkg;ArrayCount=ArrayCount+1;fiif [[ -n "$incs" ]]thenfor inc in $incs;doPatchArrElem[$ArrayCount]=$patch;IncsArrElem[$ArrayCount]=$inc;PkgArrElem[$ArrayCount]=$pkg;ArrayCount=ArrayCount+1;doneelsePatchArrElem[$ArrayCount]=$patch;IncsArrElem[$ArrayCount]="";PkgArrElem[$ArrayCount]=$pkg;ArrayCount=ArrayCount+1;fi# Check for already installedif [[ "$patch" = "$PatchNum" ]]thenThisPatchFnd="yes"fiif [[ $printpatches != "yes" ]]thencompatsAlreadyChecked="yes"CheckInstallingCompats $patch $patch_base $patch_versfidonedoneCheckUninstalledReqsunReqAlreadyChecked="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"if [[ "$printpatches" = "yes" ]]thenecho $outstr | tee -a $INSTPATCHES_FILEelseecho $outstr | tee -a $INSTPATCHES_FILEis_an_instpatches="yes"fiTestCount=TestCount+1donepkginfoParamSumif [[ ! -d $PATCHDB ]]; then$MD -p $PATCHDBfiecho "Version $PATCHDBVER $dbSum" > $PATCHDBFILEif [[ -s "$INSTPATCHES_FILE" ]]; thencat $INSTPATCHES_FILE >> $PATCHDBFILEchmod 644 $PATCHDBFILE > /dev/null 2>&1fiif [[ $PatchFound = 0 && $printpatches = "yes" ]]thenprint " No patches installed."ficd $olddir;}## 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:# Validate the patch directory, and parse out the patch number and# patch revision from the first pkginfo file found in the patch# packages.# Parameters:# $1 - patch directory# Globals Set:# PatchNum# PatchBase# PatchVersfunction activate_patch{cd $1for i in */pkginfodo## Find the patch number in one of the pkginfo files. If there is# no pkginfo file having a SUNW_PATCHID=xxxxxx entry, send an# error to the user and exit.#tmp=$($GREP PATCHID $i)if [[ -n $tmp ]]; thenPatchNum=$(pkgparam -f $i ${tmp:%=*})if [[ "$multiPtchInstall" = "no" ]]thenlastPtchInList=$PatchNumfielse/usr/bin/gettext "The packages in $1\n"/usr/bin/gettext "are not proper patch packages.\n"/usr/bin/gettext "See instructions for applying the patch in patchadd(1M).\n"patch_quit 7 "no"return 0fidone## 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_noreturn 1}# Description:# Check to see if there are any files leftover from a previous# installation. Set the unconditional flag if there are.# Parameters:# none# Globals Used:# PatchNumfunction check_file_recovery_dir{if [[ -f $RECOVERDIR/.$PatchNum && "$PatchMethod" = "direct" ]]thenPATCH_UNCONDITIONAL="true"fi}# Description:# Build the admin file for later use by non-interactive pkgadd# Parameters:# none# Globals Used:# ADMINTFILEfunction build_admin_file{if [[ "$PatchMethod" = "direct" && -f /var/sadm/install/admin/patch ]]thenADMINTFILE="patch"elsecat > $ADMINTFILE << EOFmail=instance=uniquepartial=nocheckrunlevel=nocheckidepend=nocheckrdepend=nocheckspace=quitsetuid=nocheckconflict=nocheckaction=nocheckEOFfi}# Description:# create a response file if it is necessary# Parameters:# $1 patch type# $2 patch methodfunction build_response_file{if [[ "$1" != "piPatch" ]]thenif [[ "$2" = "progressive" ]]thencat > $RESPONSE_FILE << EOFPATCH_PROGRESSIVE=$PATCH_PROGRESSIVEEOFelsecat > $RESPONSE_FILE << EOFPATCH_PROGRESSIVE=$PATCH_PROGRESSIVEPATCH_UNCONDITIONAL=$PATCH_UNCONDITIONALPATCH_NO_UNDO=$PATCH_NO_UNDOPATCH_BUILD_DIR=$PATCH_BUILD_DIRPATCH_UNDO_ARCHIVE=$PATCH_UNDO_ARCHIVEINTERRUPTION=$INTERRUPTIONEOFfifi}# Description:# See if there is any work to be done. If none of the packages to# which the patch applies are installed and there is no spooling work# to do for the client root templates, then you're done.# NEW:# If SUNWcar, SUNWcsd or SUNWcsr is included in the patch,# but the package is not on the list to be patched, then print an# error message and die. At least one instance of these packages# should be patched if included in the patch.# Parameters:# $1 - client status# $2 - were any of the packages root packages?# Globals Used:# pkglist# rootlist# patchdirfunction check_for_action{if [[ "$pkglist" = "" && "$rootlist" = "" ]]thenecho "check for action $pkglist- $rootlist"## In the first case, the system is not a client, however,# there are still no packages to patch. This will only# occur if the packages in question have not been installed# on the system.#if [[ $1 = "no" || $2 = "yes" ]]then/usr/bin/gettext "One or more patch packages included in\n$PatchNum are not installed on this system.\n"patch_quit 8 "no"return 0else## In the second case, the system is a client system.# There are two types of packages for client systems:# root packages (those packages installed on the client# machines) and packages installed only on the server.# Patchadd will exit if the machine is a client, and# there are no root packages to be patched.#/usr/bin/gettext "This patch is not applicable to client systems.\n"patch_quit 0 "no"return 0fifireturn 1}# Description:# Check to see if the patch has already been applied# Parameters:# $1 - patch database directory# $2 - patch number# Globals Set:# isapplied will be set to "yes" if this is a re-application of a patch.# This will not necessarily cause a bail out if there are packages that# should be installed that were not installed the first time the patch# was applied.#function check_if_applied{if [[ "$PatchMethod" = "direct" ]]thenif [[ "$ThisPatchFnd" = "yes" && $PATCH_UNCONDITIONAL != "true" ]]thenisapplied="yes"else$RM -fr "$1/$2"fielseif eval_inst_patches $PKGDB | $GREP -s "^Patch:[ ]*$2" > /dev/null 2>&1thenisapplied="yes"else$RM -fr "$1/$2"fifi}# Description:# Print space error message#function space_error_msg{/usr/bin/gettext "Not enough space in $1 to apply patch. $1 has $2 Kbytes available\n$1 needs $3 Kbytes free.\n"}# Description:# Check space needed against space available## Parameters:# None## Globals Used:# ROOTDIR# VarFS# ClientFS# OptFS# UsrFS# OpenwinFS# Root_Kbytes_Needed# Var_Kbytes_Needed# Opt_Kbytes_Needed# Usr_Kbytes_Needed# Openwin_Kbytes_Needed## Globals Set:# None#function check_fs_space{typeset -i Opt_Available=0typeset -i Openwin_Available=0typeset -i Root_Available=0typeset -i Usr_Available=0typeset -i Var_Available=0typeset -i exit_status=0if [[ "$DRYRUN" = "no" ]]then/usr/bin/gettext "Verifying sufficient filesystem capacity (exhaustive method)...\n"else/usr/bin/gettext "Verifying sufficient filesystem capacity (dry run method)...\n"return 1fi## Bear in mind that df -b gives the total kbytes available to# the super-user. That means we have to be conservative since# there's no pad.#Tmp_Available=$($DF -b $ROOTDIR | $SED -e '1d')Root_Available=${Tmp_Available:#* }## The root file system must have at least 1Mb of free# space or there will be problems after rebooting#Root_Available=Root_Available-1000if (( Root_Kbytes_Needed > Root_Available ))thenspace_error_msg $ROOTDIR $Root_Available $Root_Kbytes_Neededexit_status=18fiif [[ -n "$UsrFS" ]]thenTmp_Available=$($DF -b $ROOTDIR/usr | $SED -e '1d')Usr_Available=${Tmp_Available:#* }if (( Usr_Kbytes_Needed > Usr_Available ))thenspace_error_msg $ROOTDIR/usr $Usr_Available $Usr_Kbytes_Neededexit_status=18fifiif [[ -n "$OptFS" ]]thenTmp_Available=$($DF -b $ROOTDIR/opt | $SED -e '1d')Opt_Available=${Tmp_Available:#* }if (( Opt_Kbytes_Needed > Opt_Available ))thenspace_error_msg $ROOTDIR/opt $Opt_Available $Opt_Kbytes_Neededexit_status=18fifiif [[ -n "$VarFS" ]]thenTmp_Available=$($DF -b $ROOTDIR/var | $SED -e '1d')Var_Available=${Tmp_Available:#* }if (( Var_Kbytes_Needed > Var_Available ))thenspace_error_msg $ROOTDIR/var $Var_Available $Var_Kbytes_Neededexit_status=18fifiif [[ -n "$OpenwinFS" ]]thenTmp_Available=$($DF -b $ROOTDIR/usr/openwin | $SED -e '1d')Openwin_Available=${Tmp_Available:#* }if (( Openwin_Kbytes_Needed > Openwin_Available ))thenspace_error_msg $ROOTDIR/usr/openwin $Openwin_Available $Openwin_Kbytes_Neededexit_status=18fifiif (( exit_status != 0 ))thenpatch_quit $exit_status "no"return 0fireturn 1}# Description:# Compute the file system space requirements for /, /var, /opt,# /usr, and /usr/openwin to determine if there is enough free space# in which to place the patch.## Parameters:# None## Globals Used:## Globals Set:#function compute_fs_space_requirements{typeset -i size=0if [[ "$DRYRUN" = "yes" ]]thenreturnfiif [[ "$ROOTDIR" != "/" ]]thenVarFS=$($DF -a $ROOTDIR/var 2>/dev/null | $GREP var)OptFS=$($DF -a $ROOTDIR/opt 2>/dev/null | $GREP opt)UsrFS=$($DF -a $ROOTDIR/usr 2>/dev/null | $GREP usr)OpenwinFS=$($DF -a $ROOTDIR/usr/openwin 2>/dev/null | $GREP openwin)elseVarFS=$($DF -a /var 2>/dev/null | $GREP var)OptFS=$($DF -a /opt 2>/dev/null | $GREP opt)UsrFS=$($DF -a /usr 2>/dev/null | $GREP usr)OpenwinFS=$($DF -a /usr/openwin 2>/dev/null | $GREP openwin)fi# All sizes gathered to this point are in bytes. Need to# divide by a K.if [[ -z "$OpenwinFS" ]]thenRoot_Kbytes_Needed=Usr_Kbytes_Needed+Openwin_Kbytes_NeededOpenwin_Kbytes_Needed=0elseif (( Openwin_Kbytes_Needed > 0 ))thenOpenwin_Kbytes_Needed=Openwin_Kbytes_Needed/1024fifiif [[ -z "$UsrFS" ]]thenRoot_Kbytes_Needed=Root_Kbytes_Needed+Usr_Kbytes_NeededUsr_Kbytes_Needed=0elseif (( Usr_Kbytes_Needed > 0 ))thenUsr_Kbytes_Needed=Usr_Kbytes_Needed/1024fifiif [[ -z "$OptFS" ]]thenRoot_Kbytes_Needed=Root_Kbytes_Needed+Opt_Kbytes_NeededOpt_Kbytes_Needed=0elseif (( Opt_Kbytes_Needed > 0 ))thenOpt_Kbytes_Needed=Opt_Kbytes_Needed/1024fifi#Var_Kbytes_Needed=Var_Kbytes_Needed+Kbytes_Requiredif [[ -z "$VarFS" ]]thenRoot_Kbytes_Needed=Root_Kbytes_Needed+Var_Kbytes_NeededVar_Kbytes_Needed=0elseif (( Var_Kbytes_Needed > 0 ))thenVar_Kbytes_Needed=Var_Kbytes_Needed/1024fifiRoot_Kbytes_Needed=Root_Kbytes_Needed/1024}# Description:# Generate a list of packages to be installed. Remove from the previously# generated $pkglist any packages that have already been patched. This# procedure is called only for a patch re-installation.# Parameters:# $1 - package database directory# $2 - patch database directory# $3 - patch number# Globals Used:# pkglist# Globals Set:# pkglistfunction gen_uninstalled_pkgs{tmppkglist=""# Try to match up the arch with the instance.for pk in $pkglist; do# Get the installed instance that matches. Only need to check# the ARCH to determine if it is already installed.ptARCH=$(pkgparam -f $pk/pkginfo ARCH)tmppk=${pk:%.*}# Since pkginfo directs its error messages to stdout we# need to check for the existence of the pkg's directory# to avoid an annoying error by pkginfo.if [[ -d $PKGDB/$tmppk ]]; thenpkgNames=$(pkginfo -R $ROOTDIR -x $tmppk.\* | \$NAWK ' $1 ~ /[A-Z]/ {print $1}' 2>/dev/null)elsetmppkglist="$tmppkglist $pk"fifor pkn in $pkgNames; dopkPTCHD=$(pkgparam -R $ROOTDIR $pkn PATCHLIST | \$GREP -s $PatchNum 2>/dev/null)if [[ -n "$pkPTCHD" ]]; thencontinue# We know the pkg exists but hasn't been patched.elsearch=$(pkgparam -R $ROOTDIR $pkn ARCH 2>/dev/null)if [[ "$arch" = "$ptARCH" ]]; thentmppkglist="$tmppkglist $pk"fifidonedonepkglist="$tmppkglist"if [[ "$pkglist" = "" ]]then/usr/bin/gettext "Patch $3 has already been applied.\nSee patchadd(1M) for instructions.\n"patch_quit 2 "no"return 0else/usr/bin/gettext "Re-installing patch $3...\n"/usr/bin/gettext "\nRe-installing Patch.\n" >> $2/$3/log# Re-build the PATCHDB since that's the way we update it# when a patch pkg gets re-installed.reapplied="yes"fireturn 1}# Description:# Check to see if the patch is obsoleted by an earlier patch# Parameters:# none# Globals used:# PKGDB# PatchBase# PatchVers# Globals set:# isappliedfunction check_if_obsolete{if [[ "$PatchMethod" = "direct" ]]thenif [[ "$ObsoletedBy" = "none" ]]thenreturn 1elseprint_obsolete_msg "$ObsoletedBy"patch_quit 6 "no"return 0fielse## Search for patches that specifically obsolete the current# patch. Ignore if the PatchBase of the obsoletor is the same# as the obsoletee.#if eval_inst_patches $PKGDB | $GREP -v "Patch: $PatchBase" | \$GREP -s "Obsoletes:.*$PatchBase.*Packages:" > /dev/null 2>&1thenprint_obsolete_msg "$ObsoletedBy"eval_inst_patches $PKGDB | $GREP -v "Patch: $PatchBase" | \$GREP "Obsoletes:.*$PatchBase.*Packages:"patch_quit 6 "no"return 0fificurrentdir=$(pwd)## Now search for patches with the same patch base, but a greater# than rev. If an equal to rev, set the isapplied global to "yes"#oldRevs=cd $PKGDBoldRevs=$($GREP "SUNW_PATCHID=$PatchBase" ./*/pkginfo 2>/dev/null | \$SED 's/^.*-\([0-9][0-9]\).*$/\1/' | sort -u)if [[ "$oldRevs" != "" ]]thenoldRevs=$(echo $oldRevs | sort -u)for ii in $oldRevs Xdoif [[ "$ii" = "X" ]]thenbreak;fiif [[ "$ii" = "$PatchVers" ]]thenisapplied="yes"continueelif [[ "$ii" -gt "$PatchVers" ]]thenprint_obsolete_msg "$PatchBase-$ii"patch_quit 6 "no"return 0fidoneficd $currentdirreturn 1}# Description:# Determine if the patch contains any symbolic links. If so, die with# an error and a message to the user. I assume the patch will be tested# at least once in-house before getting to a non-sun user, so an# external user should NEVER see a symbolic link message.# Parameters:# None# Globals Set:# None.# Globals Used:# patchdir#function check_for_symbolic_link{$RM -f /tmp/symlink.$$ > /dev/null 2>&1olddir=$(pwd)cd $patchdirfor ii in * Xdoif [[ "$ii" = X ]]thenbreakfiif [[ ! -d "$ii" ]]thencontinuefi## Comment out ignoring symbolic links for packages with no current# instance. New packages will not be added using patchadd.## $GREP -s "VERSION=.*PATCH=" $1/$2/$ii/pkginfo# if [[ $? != 0 ]]; then# continue# fisymlinks=symlinks=$($SED -n '/^[^ ]*[ ]*s[ ]/p' $1/$2/$ii/pkgmap)if [[ "$symlinks" != "" ]]; then/usr/bin/gettext "Symbolic link in package $ii.\n" >> /tmp/symlink.$$fidoneif [[ -s /tmp/symlink.$$ ]]thencat /tmp/symlink.$$/usr/bin/gettext "Symbolic links cannot be part of a patch.\n"patch_quit 13 "no"return 0ficd $olddirreturn 1}# Description:# Find package instance of originally-installed package. Extract the# PKGID, ARCH, and VERSION by scanning the pkginfo files of each patch# package. Check to see if the packages that are being patched were# actually installed on the system in the first place.# Parameters:# $1 - package database directory# $2 - patch directory# Globals Set:# pkglist# is_a_root_pkg# Globals Used:# pkglistfunction check_pkgs_installed{i=j=pkginst=finalpkglist=minver=Pkgpatchver=Pkgarch=Pkginst=Pkgabbrev=Pkgver=Pkgtype=OrigPkgver=$TOUCH $LOGFILE# Search the installed pkginfo files for matches with the list# of packages to be patched. The package names are listed in# global pkglist. These names correspond to the package database# subdirectory names.#for i in $pkglist # for each package in the patchdo## Get the package abbreviation, architecture, version# and target filesystem.#Pkginst=$(basename $i)Pkgabbrev=$(pkgparam -f $i/pkginfo PKG)Pkgarch=$(pkgparam -f $i/pkginfo ARCH)Pkgpatchver=$(pkgparam -f $i/pkginfo VERSION)Pkgtype=$(pkgparam -f $i/pkginfo SUNW_PKGTYPE)echo "$Pkginst $Pkgabbrev $Pkgarch $Pkgpatchver $Pkgtype"if [[ "$Pkgtype" = "root" && "$service_specified" = "y" ]]thenis_a_root_pkg="yes"continueelif [[ "$Pkgtype" = "" ]]thenPkgtype="opt"fi## First the easy test, see if there's a package by# that name installed.#echo " check if this exists $1/$Pkgabbrev"if [ ! -d "$1/$Pkgabbrev" ] && [ ! -d $1/$Pkgabbrev.* ]then/usr/bin/gettext "Package not patched:\n" >> $LOGFILE/usr/bin/gettext "PKG=$Pkginst\n" >> $LOGFILE/usr/bin/gettext "Original package not installed.\n" >> $LOGFILEcontinuefi## At this point, there's a package of that name# installed. So now we have to look for the right# architecture and version. This is pretty easy for a# direct instance patch. For the progressive instance# patch, there's a lot of munging around with the various# installed versions.if [[ "$netImage" = "product" ]]thenarg="-d"elsearg="-R"fiif [[ "$PatchMethod" = "direct" ]]thenif [[ $ROOTDIR = "/" ]]thenpkginst=$(pkginfo -a $Pkgarch -v $Pkgpatchver $Pkgabbrev.\* 2>/dev/null | $NAWK ' { print $2 } ')elsepkginst=$(pkginfo $arg $ROOTDIR -a $Pkgarch -v $Pkgpatchver $Pkgabbrev.\* 2>/dev/null | $NAWK ' { print $2 } ')fiecho "Patch method direct $pkginst "if [[ -n $pkginst ]]thenfinalpkglist="$finalpkglist $i,$pkginst"else/usr/bin/gettext "Package not patched:\n" >> $LOGFILE/usr/bin/gettext "PKG=$Pkginst\n" >> $LOGFILE/usr/bin/gettext "Original package not installed.\n" >> $LOGFILEcontinuefielseecho "Patch method not direct $pkginst "## Get the package version number.#Pkgver=$($SED -n \-e 's/^[ ]*VERSION[ ]*=[ ]*\([^ ]*\)[ ]*$/\1/p' \-e 's/^[ ]*VERSION[ ]*=[ ]*\([^ ]*\),PATCH=.*$/\1/p' $i/pkginfo )minver=$(expr $Pkgver : '\(.*\)\.0$')while [ "$minver" != "" ]doPkgver=$minverminver=$(expr $Pkgver : '\(.*\)\.0$')donefor j in $1/$Pkgabbrev $1/$Pkgabbrev.* Xdoif [[ "$j" = "X" ]]thenbreakfiif [[ ! -d $j ]]thencontinue;fiOrigPkgver=$($SED -n 's/^VERSION=\(.*\)$/\1/p' $j/pkginfo)minver=$(expr $OrigPkgver : '\(.*\)\.0$')while [[ "$minver" != "" ]]doOrigPkgver=$minverminver=$(expr $OrigPkgver : '\(.*\)\.0$')doneif $GREP -s "^PKG=$Pkgabbrev$" $j/pkginfo >/dev/null 2>&1 \&& $GREP -s "^ARCH=$Pkgarch$" $j/pkginfo >/dev/null 2>&1 \&& [ "$OrigPkgver" = "$Pkgver" ] ;thenpkginst=$(basename $j)finalpkglist="$finalpkglist $i,$pkginst"break;else/usr/bin/gettext "Package not patched:\n" >> $LOGFILE/usr/bin/gettext "PKG=$Pkgabbrev\n" >> $LOGFILE/usr/bin/gettext "ARCH=$Pkgarch\n" >> $LOGFILE/usr/bin/gettext "VERSION=$OrigPkgver\n" >> $LOGFILEtmp=""tmp=$($GREP "^ARCH=$Pkgarch$" $j/pkginfo 2>/dev/null)if [[ "$tmp" = "" ]]then/usr/bin/gettext "Architecture mismatch.\n" >> $LOGFILEfiif [[ "$OrigPkgver" != "$Pkgver" ]]then/usr/bin/gettext "Version mismatch.\n" >> $LOGFILEfiecho "" >> $LOGFILEfidonefidonepkglist=$finalpkglist}# Description:# If validation is being done, and pkgchk reported ERRORs, bail out.# If no validation is being done, keep a list of files that failed# validation. If this patch needs to be backed out, don't do an installf# on these files. Any files that failed validation before the patch was# applied should still fail validation after the patch is backed out.# This will be the .validation.errors file in the patch directory.# Parameters:# $1 - validation status [ "yes" or "no" ]# Globals Used:# PKGCOFILE# VALERRFILEfunction check_validation{if [[ "$1" = "yes" && -s $PKGCOFILE ]]thenif $GREP -s ERROR $PKGCOFILE >/dev/null 2>&1then/usr/bin/gettext "The following validation error was found:\n"cat $PKGCOFILE/usr/bin/gettext "\nSee the Install.info file for instructions regarding patch validation errors.\n"patch_quit 10 "no"return 0fifiif [[ -s $VALWARNFILE ]]then$CP $VALWARNFILE $VALERRFILEfireturn 1}# Description:# Create the remote file associated with the backout data# Parameters:# $1 - patch database directory# $2 - patch number# Globals Used:# PATCH_UNDO_ARCHIVEfunction create_remote_file{cat > $1/$2/save/remote << EOF# Backout data stored remotelyTYPE=filesystemFIND_AT=$PATCH_UNDO_ARCHIVE/$2/archive.cpioSTATE=N/AEOF}# Description:# Create a spooling area in the sadm/patch/<patchID> tree for files# which are being replaced by the patch. Store the validation error# file with it.# Parameters:# $1 - patch database directory# $2 - patch number# Globals Used:# VALERRFILEfunction create_archive_area{if [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]; then/usr/bin/gettext "Creating patch archive area...\n"$MD -p -m 750 $PATCH_UNDO_ARCHIVE/$2chown -h -f -R root $PATCH_UNDO_ARCHIVE/$2chgrp -h -f -R sys $PATCH_UNDO_ARCHIVE/$2$MD -p -m 750 $1/$2/savechown -h -f -R root $1/$2chgrp -h -f -R sys $1/$2create_remote_file $1 $2elif [[ ! -d $1/$2/save ]]then/usr/bin/gettext "Creating patch archive area...\n"$MD -p -m 750 $1/$2/savechown -h -f -R root $1/$2chgrp -h -f -R sys $1/$2fiif [ -s $VALERRFILE ]then$CP $VALERRFILE $1/$2/.validation.errorsfi}# Description:# Scan the patch package maps for a list of affected files.# Parameters:# $1 - package database directory# $2 - package relocation argument## Locals Used# arg## Globals Used:# PKGCOFILE# PATCHFILES# pkglist#function gen_install_filelist{if [[ "$DRYRUN" = "yes" ]]thenreturnfipkgfiles=/tmp/pkgfiles.$$resfiles=/tmp/resolvedfiles.$$macrofiles=/tmp/pkgmacros.$$pkginst=pkginfofile=patchpkg=basedir=i=$RM -f $PATCHFILES/usr/bin/gettext "Generating list of files to be patched...\n"for i in $pkglistdopatchpkg=`expr $i : '\(.*\),.*'`pkginst=`expr $i : '.*,\(.*\)'`if [[ $pkginst = "" ]]thencontinuefipkginfofile="$1/$pkginst/pkginfo"pkgmapfile="$1/$pkginst/pkgmap"# Get the BASEDIRbasedir=$(pkgparam -f $pkginfofile BASEDIR)## Parse out the pkgmap files to get the file names.# First, get rid of all checksum info. Then get rid# of all info file entries. Replace all BASEDIR values# with emptiness (BASEDIR will be prepended). Delete# all entries that are the BASEDIR without a file# (directory entries). Get the file name. If it's a# symbolic link, keep the link, don't follow it to the# file.#$SED -e '/^:/d' \-e '/^[^ ][^ ]* i/d' \-e 's, \$BASEDIR/, ,' \-e '/ \$BASEDIR /d' \-e 's/^[^ ]* . \([^ ]*\) \([^ ]*\).*$/\2 \1/' \-e 's/=.*//' $patchpkg/pkgmap > $pkgfiles## Resolve any macros in the list of files before determining if# the file is relocatable.#if [[ -s $pkgfiles ]]then# resolve any macros in the list of files( # different shell$RM -f $macrofiles $resfiles# Extract every macro that may be meaningful# and throw quotes around all of the values# assigned.$NAWK -F= '$1 ~ /PATCHLIST/ { next; }$1 ~ /OBSOLETES/ { next; }$1 ~ /ACTIVE_PATCH/ { next; }$1 ~ /PATCH_INFO/ { next; }$1 ~ /UPDATE/ { next; }$1 ~ /SCRIPTS_DIR/ { next; }$1 ~ /PATCH_NO_UNDO/ { next; }$1 ~ /INSTDATE/ { next; }$1 ~ /PKGINST/ { next; }$1 ~ /OAMBASE/ { next; }$1 ~ /PATH/ { next; }{printf("%s=\"%s\"\n", $1, $2);} ' $pkginfofile > $macrofiles. $macrofilescat $pkgfiles |while read idoeval /usr/bin/echo $i >> $resfilesdone) # back to original shell## Prepend the basedir to the file name if the file is# relocatable, then add it to the pkgfile list.#$MV $resfiles $pkgfiles# The following line is being called in its own shell# do to on an x86 system a pkgmap file with ~230 lines# causes some internal jsh limit to get exhausted.(cat $pkgfiles | parse_sizes $patchpkg)$SED -e "s,^\([^/]\),$basedir/&," \-e 's,\/\/,\/,g' $pkgfiles > $resfiles## If there are some files to patch in the package, see if# they have validation errors. Ignore any validation errors# for files having class action scripts. The remaining# validation errors will be put in a validation error file.#if [[ -s $resfiles && "$PatchType" != "diPatch" ]]thencat $resfiles |while read jdojfile=$(echo $j | $SED 's/^\([^ ]*\).*/\1/')class=$(echo $j | $SED 's/^[^ ]* \(.*\)/\1/')badfile=badfile=$(pkgchk $2 -p $jfile\$patchpkg 2>&1 | \$GREP "^ERROR:" | \$SED -n 's/^ERROR:[ ]*//p')if [ "$badfile" != "" ]thenif [ "$class" != "" -a "$class" != "preserve" -a ! -f $patchdir/$patchpkg/install/i.$class ]thenpkgchk $2 -p $jfile\$patchpkg >> $PKGCOFILE 2>&1fiecho $jfile >> $VALWARNFILEfidonefi$SED 's/^\([^ ]*\).*/\1/' $resfiles >> $PATCHFILESfidone}# Description:# Set flag in case of power outage.# Parameters:## Globals Used:# RECOVERDIR# INTERUPTION# PatchNum#function file_recovery{if [[ "$PatchMethod" = "direct" ]]thenif [[ -d "$RECOVERDIR" ]]thenINTERRUPTION="yes"elseif [[ ! -d "$RECOVERDIR" ]]; then$MD $RECOVERDIRfi$TOUCH $RECOVERDIR/.$PatchNumsyncfifi}# Description:# Used in the file system space calculation. Determine where each# identified file will be placed, and add its size to the correct# running total.# Parameters:# $1 - patch package name# Globals Used:# Openwin_Kbytes_Needed# Usr_Kbytes_Needed# Opt_Kbytes_Needed# Var_Kbytes_Needed# Root_Kbytes_Needed#function parse_sizes{typeset -i size=0typeset -i installedSize=0while read Filename junkdo($GREP " $Filename " $1/pkgmap |while read part ftype f3 f4 f5 f6 f7 f8 Junkdocase $ftype inf|e|v)$($VALPATH -a $f4)ret=$?if [[ "$ret" != 0 ]]then# Prepend the basedir to# the relocatable objectsif [[ "$basedir" = "/" ]]thenpathname="$basedir$f4"elsepathname="$basedir/$f4"fielsepathname=$f4fi# Calculate the difference from the# installing object with the object# that is already installed.if [[ "$ROOTDIR" != "/" ]]then# Prepend the root path to the installed objecttmpPath="$ROOTDIR$pathname"elsetmpPath="$pathname"fiif [[ -f "$tmpPath" ]]theninstalledSize=$($WC -c $tmpPath | $NAWK ' \{ print $1 } ')size=$f8size=size-installedSizeif (( size < 0 ))thensize=0fielsesize=$f8ficase $pathname inusr\/openwin\/*|\/usr\/openwin\/*|openwin\/*|\/openwin\/*)Openwin_Kbytes_Needed=Openwin_Kbytes_Needed+size ;;usr\/*|\/usr\/*)Usr_Kbytes_Needed=Usr_Kbytes_Needed+size ;;var\/*|\/var\/*)Var_Kbytes_Needed=Var_Kbytes_Needed+size ;;opt\/*|\/opt\/*)Opt_Kbytes_Needed=Opt_Kbytes_Needed+size ;;*)Root_Kbytes_Needed=Root_Kbytes_Needed+size ;;esac;;i)size=$f4Var_Kbytes_Needed=Var_Kbytes_Needed+size;;d|l|s|p|b|c|x)$($VALPATH -a $f4)ret=$?if [[ "$ret" != 0 ]]then# Prepend the basedir to# the relocatable objectsif [[ "$basedir" = "/" ]]thenpathname="$basedir$f4"elsepathname="$basedir/$f4"fielsepathname=$f4ficase $pathname inusr\/openwin\/*|\/usr\/openwin\/*|openwin\/*|\/openwin\/*)Openwin_Kbytes_Needed=Openwin_Kbytes_Needed+512 ;;usr\/*|\/usr\/*)Usr_Kbytes_Needed=Usr_Kbytes_Needed+512 ;;var\/*|\/var\/*)Var_Kbytes_Needed=Var_Kbytes_Needed+512 ;;opt\/*|\/opt\/*)Opt_Kbytes_Needed=Opt_Kbytes_Needed+512 ;;*)Root_Kbytes_Needed=Root_Kbytes_Needed+512 ;;esac;;*);;esacdone)done}# Description:# Generate a list of files which are "to be patched." Determine their# total size in bytes to figure out the space requirements of backing# them up.# Parameters:# none# Globals Used:# PATCHFILES# EXISTFILES#function gen_patch_filelist{typeset -i tmp_total=0typeset -i kbytes_total=0typeset -i kb=0size=if [[ "$DRYRUN" = "yes" || "$PATCH_NO_UNDO" = "true" ]]thenreturnfiif [[ -s $PATCHFILES ]]thencat $PATCHFILES |while read jdoif $LS -d $ROOTDIR$j >/dev/null 2>&1thenecho "."$j >> $EXISTFILESsize=$($LS -Ldl $ROOTDIR$j)size=$(echo $size | $NAWK ' { print $5 } ')# size=$($WC -c $ROOTDIR$j)# size=$(echo $size | $SED 's/\ .*//')if [ "$size" != "" ]thentmp_total=tmp_total+$sizefiif (( tmp_total >= 1024 ))thenkb=tmp_total/1024tmp_total=tmp_total-kb*1024kbytes_total=kbytes_total+kbfi#breakfidone;if (( tmp_total > 0 ))thenkbytes_total=kbytes_total+1fiKbytes_Required=kbytes_totalelse$RM -f $EXISTFILESfi}# Description:# Assemble a list of the patch package IDs contained in the patch# (at least one directory with a pkginfo file must exist due to checks# in activate_patch)# Parameters:# none# Globals Set:# pkglist#function gen_patchpkg_list{pkg=for i in */pkginfo Xdoif [ "$i" = "X" ]thenbreakfipkg=`expr $i : '\(.*\)/pkginfo'`pkglist="$pkglist $pkg"done}# 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=$(uname -r | $SED -n -e 's/5\./2\./p' -e 's/4\./1\./p')if [[ "$MgrOSVers" < "2.6" ]]then/usr/bin/gettext "This system must be running Solaris 2.6 or later\nin order to install a patch to a Net Install Image."patch_quit 1 "yes"fiMgrprodver=$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 "patchadd is unable to find the INST_RELEASE file for the target filesystem.\nThis file must be present for patchadd to function correctly.\n"patch_quit 11 "yes"elseProduct=$($SED -n 's/^OS=\(.*\)/\1/p' $1)TrgOSVers=$($SED -n 's/^VERSION=\(.*\)/\1/p' $1)prodver=$Product"_"$TrgOSVersfi}# Description:# Actually install patch packages which apply to the system# Parameters:# $1 - patch database directory# $2 - patch number# $3 - patch directory# $4 - package add relocation argument# $5 - package database directory# Globals Used:# ADMINTFILE# ADMINFILE# pkglist#function install_patch_pkgs{typeset -i pkgadderr=0typeset -i real_pkgadderr_2=0i=ij=pkginst=pkginfofile=patchpkg=basedir=pkgDispList=""## Write out the contents of the logfile if there were any# messages. Do this now, because the $1/$2 directory may not# exist before this point.#if [ -f $LOGFILE ]thencat $LOGFILE >> $1/$2/log$RM -f $LOGFILEfimove_libraries/usr/bin/gettext "Installing patch packages...\n"for ij in $pkglistdoi=`expr $ij : '\(.*\),.*'`pkginst=`expr $ij : '.*,\(.*\)'`pkginfofile="$5/$pkginst/pkginfo"basedir=$($GREP '^BASEDIR' $pkginfofile | $SED -e 's@.*=\ *@@' -e 's@/a/@/@' -e 's@/a$@/@')if [ ! -d $1/$2/$i ]then$MD -m 750 $1/$2/$ifi$CP $i/pkgmap $1/$2/$i/pkgmap$CP $i/pkginfo $1/$2/$i/pkginfo$CP $ADMINTFILE $ADMINFILEecho basedir=$basedir >>$ADMINFILE/usr/bin/gettext "\nDoing pkgadd of $i package:\n"if [[ $PatchType = "caPatch" ]]then$CP $RESPONSE_FILE $RESPONSE_FILE.1pkgadd $4 -S -a $ADMINFILE -r $RESPONSE_FILE.1 -n -d $3 $i >>$LOGFILE </dev/null 2>&1elsepkgadd $4 -S -a $ADMINFILE -n -d $3 $i >>$LOGFILE </dev/null 2>&1fipkgadderr=$?exit_code=$pkgadderrif [[ $PatchType = "caPatch" ]]then$RM -f $RESPONSE_FILE.1fireal_pkgadderr_2=0if (( pkgadderr == 2 ))thenif $GREP '^ERROR' $LOGFILE >/dev/null 2>&1thenreal_pkgadderr_2=1fifi# reboot after installation of all packagesif (( pkgadderr == 10 || pkgadderr == 20 ))then/usr/bin/gettext "Reboot after patchadd has installed the patch.\n"ficat $LOGFILE >> $1/$2/logcat $LOGFILE | $GREP -v "^$"$RM -f $LOGFILEif (( pkgadderr != 0 && real_pkgadderr_2 != 0 && \pkgadderr != 10 && pkgadderr != 20 ))then/usr/bin/gettext "Pkgadd of $i package failed with error code $pkgadderr.\n" |tee -a $1/$2/logif [ "$isapplied" = "no" ]then/usr/bin/gettext "See /tmp/log.$2 for reason for failure.\n"$CP $1/$2/log /tmp/log.$2/usr/bin/gettext "Backing out patch:\n"cd $3if [ "$ROOTDIR" != "/" ]then/usr/sbin/patchrm $PKGDBARG $2else/usr/sbin/patchrm $2fielse/usr/bin/gettext "See $1/$2/log for reason for failure.\nWill not backout patch...patch re-installation.\nWarning: The system may be in an unstable state!\n"fipatch_quit 5 "no"return 0fipkgDispList="$pkgDispList $i"doneremove_librariesreturn 1}# Description:# Make internal variables available to child processes# of patchadd. This is done by writing them to a# file and by exporting them.# Parameters:# none# Environment Variables Set:# none#function make_params_available{echo "saveold=$saveold" > $PARAMS_FILEecho "validate=$validate" >> $PARAMS_FILEecho "patchdir=$patchdir" >> $PARAMS_FILEecho "patchnum=$PatchNum" >> $PARAMS_FILEecho "patchbase=$PatchBase" >> $PARAMS_FILEecho "patchrev=$PatchVers" >> $PARAMS_FILEecho "ROOTDIR=$ROOTDIR" >> $PARAMS_FILEecho "PATCHDB=$PATCHDB" >> $PARAMS_FILEecho "PKGDB=$PKGDB" >> $PARAMS_FILEecho "PKGDBARG=$PKGDBARG" >> $PARAMS_FILEecho "PATCHMETHOD=PatchMethod" >> $PARAMS_FILEecho "UNINST_REQS=\"$UninstReqs\"" >> $PARAMS_FILEecho "PATCH_UNDO_ARCHIVE=$PATCH_UNDO_ARCHIVE" >> $PARAMS_FILEecho "PATCH_BUILD_DIR=$PATCH_BUILD_DIR" >> $PARAMS_FILEecho "INTERRUPTION=$INTERRUPTION" >> $PARAMS_FILEecho "INSTALL_PATCHDIR=$INSTALL_PATCHDIR" >> $PARAMS_FILEexport saveold validate patchdir PatchNum PatchBase PatchVersexport PARAMS_FILE ROOTDIR PATCHDB PKGDB PKGDBARG}# 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 Rev=0Rev=$(echo $TrgOSVers | $SED -e 's/[0-9]\.//' -e 's/_.*$//')if (( Rev >= 5 ))thenif [ ! -d $TMP_LIB_DIR ]then$MD -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_PRELOADlibs_are_moved="yes"fi}# 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" || "$netImage" = "product" ]]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" < "5.6" ]]then/usr/bin/gettext "WARNING: patchadd must be executed from a 2.6 or later system.\n\n"exit 32fi}# Description:# Parse the arguments and set all affected global variables# Parameters:# Argument list passed into patchadd# Globals Set:# validate# saveold# force# printpatches# patchdir# ROOTDIR# PATCHDB# PKGDB# PKGDBARG# Globals Used:# Mgrprodver# MGRSOFTINO# TRGSOFTINFO# PKGDB# PATCHDB#function parse_args{# Inserted for readability reasonsecho ""service_specified="n"rootdir_specified="n"orig_dir=$(pwd)while [ "$1" != "" ]docase $1 in-i) interactive=1; shift ;;-u) validate="no"; PATCH_UNCONDITIONAL="true"; shift;;-d) saveold="no"; PATCH_NO_UNDO="true";if [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]then/usr/bin/gettext "The -d option and the -B option are mutually exclusive.\n"patch_quit 1 "yes"fishift ;;-B) shiftif [[ "$PATCH_NO_UNDO" = "true" ]]then/usr/bin/gettext "The -d option and the -B option are mutually exclusive.\n"patch_quit 1 "yes"fiif [[ -d $1 ]]thendetermine_directory $1if [[ $ret = 0 ]]thenPATCH_BUILD_DIR=$1PATCH_UNDO_ARCHIVE=$1elsePATCH_BUILD_DIR=$curdirPATCH_UNDO_ARCHIVE=$curdirfielse/usr/bin/gettext "Specified backout directory $1 cannot be found.\n"patch_quit 26 "yes"fishift;;-p) printpatches="yes"; shift;;-S) shiftif [ "$rootdir_specified" = "y" ]then/usr/bin/gettext "The -S and -R arguments are mutually exclusive.\n"print_usagepatch_quit 1 "yes"fifind_softinfos /export/$1get_OS_version "$TRGSOFTINFO" "$MGRSOFTINFO" "$1"if [ "$1" != "$Mgrprodver" ]thenif [ -d "/export/$1$PKGDB" ]thenROOTDIR=/export/$1PATCHDB=$ROOTDIR$PATCHDBPKGDB=$ROOTDIR$PKGDBPKGDBARG="-R $ROOTDIR"else/usr/bin/gettext "The $1 service cannot be found on this system.\n"print_usagepatch_quit 1 "yes"fifiservice_specified="y"shift;;-V) echo "@(#) patchadd.ksh 2.5 99/04/06"patch_quit 0 "yes";;-R) shiftif [ "$service_specified" = "y" ]then/usr/bin/gettext "The -S and -R arguments are mutually exclusive.\n"print_usagepatch_quit 1 "yes"fiif [ ! -d "$1" ]then/usr/bin/gettext "The Package Install Root directory $1 cannot be found on this system.\n"print_usagepatch_quit 1 "yes"elsedetermine_directory $1if [[ $ret = 0 ]]thenROOTDIR=$1elseROOTDIR=$curdirfiPATCHDB=$ROOTDIR$PATCHDBPKGDB=$ROOTDIR$PKGDBPKGDBARG="-R $ROOTDIR"rootdir_specified="y"fishift;;-M) shiftif [ ! -d "$1" ]then/usr/bin/gettext "The patch directory $1 cannot be found on this system.\n"print_usagepatch_quit 1 "yes"elsedetermine_directory $1if [[ $ret = 0 ]]thenmultiPtchDir=$1elsemultiPtchDir=$curdirfimultiPtchInstall="yes"fishift;;-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 1 "yes"fiif [ ! -d "$1" ]then/usr/bin/gettext "The path to the net install image $1 cannot be found.\n"print_usagepatch_quit 1 "yes"elsedetermine_Product_Boot $1determine_directory $1if [[ $ret = 0 ]]thenROOTDIR=$1elseROOTDIR=$curdirfiPATCHDB=$ROOTDIR$PATCHDBPKGDB=$ROOTDIR$PKGDBPKGDBARG="-C $ROOTDIR"PatchMethod="direct"fishift;;-*) print_usage; patch_quit 1 "yes";;*) if [[ "$multiPtchInstall" = "yes" ]]thenif [[ -d "$multiPtchDir/$1" ]]thenmultiPtchList="$multiPtchList $1"lastPtchInList=$1elif [[ -f "$multiPtchDir/$1" ]]thenprocess_multi_patch_file "$multiPtchDir/$1"multiPtchList=$($NAWK ' { print $1 } ' $multiPtchDir/$1)lastPtchInList=$($TAIL -1 $multiPtchDir/$1)else/usr/bin/gettext "The patch or patch_list $1 cannot be found in\n$multiPtchDir.\n"patch_quit 33 "yes"fielsebreakfishift;;esacdonePATCHDBFILE=$ROOTDIR/var/sadm/patch/.patchDBif [[ "$printpatches" = "yes" ]]thencheck_PatchDBseval_inst_patches $PKGDBif [[ -f "$INSTPATCHES_FILE" ]]; then$RM -f $INSTPATCHES_FILEfiexit 0fiif [[ "$1" = "" && "$multiPtchInstall" = "no" ]]then/usr/bin/gettext "No patch directory specified.\n"print_usagepatch_quit 1 "yes"fiif [[ ! -d "$1" && "$multiPtchInstall" = "no" ]]then/usr/bin/gettext "Patch directory $1 does not exist.\n"print_usagepatch_quit 1 "yes"fiif [[ "$multiPtchInstall" = "no" ]]thendetermine_directory $1if [[ $ret = 0 ]]thenpatchdir=$1elsepatchdir=$curdirfimultiPtchList=$(basename $patchdir)fiRECOVERDIR=$ROOTDIR/var/sadm/.patchRecINSTALL_PATCHDIR=$patchdir}# Description:# Determine if this patch is being applied to the net install# images boot or product area.# Parameters:# $1 - The file containing the patches to install.# Locals Used:# file_errorsfunction process_multi_patch_file{file_errors=file_errors=$($NAWK ' { print $2 } ' $1)if [[ -n $file_errors ]]then/usr/bin/gettext "Only one patch per line is allowed in the file\n$1.\n"patch_quit 33 "yes"fi}# Description:# Determine if this patch is being applied to the net install# images boot or product area.# Parameters:# $1 - command line argument# Locals Used:# result# Globals Used:# netImagefunction determine_Product_Boot{result=$(basename $1)if [[ "$result" = "Boot" ]]thenif [[ -d $1/.tmp_proto ]]thennetImage="boot"else/usr/bin/gettext "Although this appears to be a valid Net Install Image,\nit doesn't have the neccessary directories."patch_quit 31 "yes"fielif [[ "$result" = "Product" ]]thennetImage="product"else/usr/bin/gettext "Argument to the -C command line option is not a valid net install image path."patch_quit 31 "yes"fi}# Description:# Derive the full path name from a (possibly) relative path name.# Parameters:# $1 - command line argument## Globals Used:# olddir# patchdir# retfunction determine_directory{$($VALPATH -a $1)ret=$?if [[ $ret != 0 ]]thencd $1 3>/dev/nullif [[ $? = 0 ]]thencurdir=$(pwd)cd $orig_direlse/usr/bin/gettext "Can not determine relative directory.\n"patch_quit 27 "yes"fielsereturnfi}# Description:# Print the patch obsolecensce message# Parameters:# $1 - number of patch which obsoleted this patch#function print_obsolete_msg{if [[ $1 = "none" ]]then/usr/bin/gettext "This patch is obsoleted by the following which has already\nbeen applied to this system.\n"else/usr/bin/gettext "This patch is obsoleted by patch $1 which has already\nbeen applied to this system.\n"fi}# Description:# Print the list of patch packages which were applied, and those# which were not.# Parameters:# none# Globals Used:# pkglist#function print_results{i=p=/usr/bin/gettext "\nPatch packages installed:\n"if [[ -n "$pkgDispList" ]]thenif [[ "$exit_code" = 0 || "$exit_code" = 20 || \"$exit_code" = 10 ]]thenfor i in $pkgDispListdoecho " ${i%,*}"donefielse/usr/bin/gettext " none\n\n"fiecho ""}# 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_DIRlibs_are_moved="no"}# Description:# Check space requirements for the backout# data for both direct instance and progressive instance patches.# Parameters:# $1 - database directory (PKGDB or PATCHDB)# $2 - patch number# $3 - patch directory# $4 - save old files [ "yes" or "no" ]# Environment Variables Set:#function check_backout_space{typeset -i kbytes_avail=0typeset -i buffer=10if [[ "$DRYRUN" = "yes" || "$PATCH_NO_UNDO" = "true" ]]thenreturn 1elif [[ ! -s $EXISTFILES && $1 = "$PATCHDB" ]]then$TOUCH $1/$2/.nofilestosaveelif [[ $4 = "yes" ]]thenif [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]thenbackout_dir=$PATCH_UNDO_ARCHIVEelif [[ "$netImage" = "boot" ]]thenbackout_dir=$ROOTDIRelsebackout_dir=$1fi# Is there enough space? Use sed to extract the fourth field of# df output (can't use awk because it may not be installed).kbytes_avail=$($DF -b $backout_dir | tail -1 | \$SED 's/^[^ ]*[ ]*\([^ ]*\).*/\1/')# To build and compress the backout packages in the archive directory# takes about 3x as much space then there really needs to be# to save just the archive.Kbytes_Required=Kbytes_Required*3+bufferif (( Kbytes_Required > kbytes_avail ))then/usr/bin/gettext "Insufficient space in $backout_dir to save old files.\nSpace required in kilobytes: $Kbytes_Required\nSpace available in kilobytes: $kbytes_avail\n"if [ "$isapplied" = no ]thencd $3if [ "$ROOTDIR" != "/" ]then/usr/sbin/patchrm $PKGDBARG $2else/usr/sbin/patchrm $2fi$RM -fr $backout_dir/$2fipatch_quit 4 "no"return 0fifireturn 1}# Description:# Archive files which will be overwritten by the patch application,# if the patch actually affects any existing files.# Parameters:# $1 - patch database directory# $2 - patch number# $3 - patch directory# $4 - save old files [ "yes" or "no" ]# Globals Used:# EXISTFILES#function save_overwritten_files{typeset -i exit_code=0archive_path=if [[ -f $1/$2/.nofilestosave || "$PATCH_NO_UNDO" = "true" ]]thenreturn 1elif [ "$4" = "yes" ]then/usr/bin/gettext "Saving a copy of existing files to be patched...\n"cd $ROOTDIRif [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]thenarchive_path=$PATCH_UNDO_ARCHIVE/$2elsearchive_path=$1/$2/savefiif [ "$isapplied" = "no" ]thencpio -oL -O $archive_path/archive.cpio < $EXISTFILESexit_code=$?elseif [ ! -d $TMP_ARCHIVE ]then$MD $TMP_ARCHIVEficd $TMP_ARCHIVEif [ -f $archive_path/archive.cpio.Z ]thenzcat $archive_path/archive.cpio.Z | cpio -idumelsecpio -idum -I $archive_path/archive.cpiofi$FIND . -print > $TMP_FILELISTcd $ROOTDIRcpio -oL -O /tmp/archive.cpio < $EXISTFILES >/dev/null 2>&1exit_code=$?cd $TMP_ARCHIVEcpio -oAL -O /tmp/archive.cpio < $TMP_FILELIST >/dev/null 2>&1exit_code=exit_code+$?cd $ROOTDIR$RM -rf $TMP_ARCHIVE/* $TMP_FILELISTrmdir $TMP_ARCHIVEfiif (( exit_code != 0 ))then/usr/bin/gettext "Save of old files failed.\nSee Install.info file for instructions.\n"if [ "$isapplied" = "no" ]thencd $3if [ "$ROOTDIR" != "/" ]then/usr/sbin/patchrm $PKGDBARG $2else/usr/sbin/patchrm $2fi$RM -fr "$1/$2"fipatch_quit 4 "no"return 0fiif [ -x /usr/bin/compress ]thenif [ "$isapplied" = "no" ]thencompress $archive_path/archive.cpioelsecompress /tmp/archive.cpiofiif [ $? = 0 ]then/usr/bin/gettext " File compression used.\n"else/usr/bin/gettext " No file compression used.\n"fielse/usr/bin/gettext " No file compression used.\n"fiif [ "$isapplied" = "yes" ]then$CP /tmp/archive.cpio* $1/$2/savefichmod 600 $archive_path/archive.cpio*$TOUCH $1/$2/.oldfilessavedsyncficd $3return 1}# Description:# Finish up the patch# Parameters:# $1 - patch database directory# $2 - patch number#function set_patch_status{if [[ ! -d $1/$2 ]]then$MD -m 750 -p $1/$2fi$MV -f /tmp/ACTION.$PatchNum $1/$2 >/dev/null 2>&1$CP -p README.$2 $1/$2 >/dev/null 2>&1# Note the following line should be removed for 2.7.# Since 2.6 is a transitional release we keep backoutpatch# around.$CP -p backoutpatch $1/$2 >/dev/null 2>&1$CP -p prebackout postbackout $1/$2 > /dev/null 2>&1}# Description:# Parameters:# $1 - patch database directory# $2 - patch number# $3 - patch directory#function trap_backoutsaved{/usr/bin/gettext "Interrupt signal detected.\n"if [[ "$isapplied" = "no" ]]then/usr/bin/gettext "Backing out patch:\n"cd $3if [[ "$ROOTDIR" != "/" ]]then/usr/sbin/patchrm $PKGDBARG $2else/usr/sbin/patchrm $2fi$RM -fr "$1/$2"elseif [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]then$CP /tmp/archive.cpio* $PATCH_UNDO_ARCHIVE/$2else$CP /tmp/archive.cpio* $1/$2/savefi$RM -f /tmp/archive.cpio*/usr/bin/gettext "Patchadd Interrupted.\n" >> $1/$2/logfipatch_quit 12 "yes"}# Description:# Parameters:# $1 - patch directory# $2 - patch number#function trap_backout{/usr/bin/gettext "Interrupt signal detected.\nBacking out Patch:\n"cd $1if [[ "$ROOTDIR" != "/" ]]then/usr/sbin/patchrm $PKGDBARG $2else/usr/sbin/patchrm $2fiif [[ "$isapplied" = "yes" ]]then$RM -f /tmp/archive.cpio*fipatch_quit 12 "yes"}# Description:# Parameters:# $1 - patch database directory# $2 - patch number#function trap_notinstalled{/usr/bin/gettext "Interrupt signal detected. Patch not installed.\n"$RM -fr /tmp/*.$$$RM -f $INSTPATCHES_FILEif [[ "$isapplied" = "no" ]]then$RM -fr "$1/$2"else/usr/bin/gettext "Install Interrupted.\n" >> $1/$2/logfipatch_quit 12 "yes"}# Description:# Make sure effective UID is '0'# Parameters:# none#function 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"patch_quit 3 "yes"fi}# Description:# Assume that any system on which the SUNWcsu package is NOT# installed is a client. It is a safe bet that this criterion# will remain valid through Solaris 2.3. Later releases may require# that this test be changed. Make sure pkgadd is executable too.# Parameters:# none# Globals Set:# client#function verify_client{pkginfo -q SUNWcsuif [[ $? != 0 ]]thenclient=yessum /usr/sbin/pkgadd > /dev/null 2>&1if [[ $? != 0 ]]then/usr/bin/gettext "The /usr/sbin/pkgadd command is not executable.\nSee pkgadd(1M) for instructions\nfor making this command executable.\n"patch_quit 9 "yes"fifi}# Description:# Get key parameters relating to this patch# Parameters:# none# Globals Set:# Obsoletes those patches that this one obsoletes# Incompat those patches with which this one is incompatible# Requires those patches that this one requires# ReqArrElem[] an ordered mapping of "yes" or "no" attributes# associated with each entry in Requires. If it# is "yes", that package has been found on the# system. If "no", it has not been found.# ReqArrCount The count of elements in the above array## Locals Used:# list# tmp# tmpInstalled#function collect_data{tmp=list=tmpInstalled=cd $patchdirfor pkg in *doif [[ -f $pkg/pkginfo ]]then# Collect the data from a pkginfo filetmp=$($GREP OBSOLETES $pkg/pkginfo)if [[ $tmp = "" ]]thenObsoletes=""elseObsoletes=$(pkgparam -f $pkg/pkginfo ${tmp:%=*})fitmp=$($GREP INCOMPAT $pkg/pkginfo)if [[ $tmp = "" ]]thenIncompat=""elseIncompat=$(pkgparam -f $pkg/pkginfo ${tmp:%=*})fitmp=$($GREP REQUIRES $pkg/pkginfo)if [[ $tmp = "" ]]thenRequires=""elseRequires=$(pkgparam -f $pkg/pkginfo ${tmp:%=*})fifor req in $RequiresdoReqArrElem[$ReqArrCount]="no"ReqArrCount=ReqArrCount+1;donebreakfidone}# 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:# Check to see if any pkginfo files have changed since the last# patchadd or patchrm. If so, recreate the database.# NOTE: There will be times when the database is considered out# of sync due to a pkg command.#function check_PatchDBs{if [[ -f $PATCHDBFILE ]]; thenpkginfoParamSumpdbSum=$($NAWK ' $1 ~ /Version/ { print $3} ' $PATCHDBFILE)if (( dbSum != pdbSum )); thenrecreatePatchDB="yes"$RM -f $PATCHDBFILEfielsepkginfoParamSumrecreatePatchDB="yes"fi}# 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:# Find installing compatibility issues.## Parameters# $1 - installed 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 patchesif [[ $ReqArrCount -gt 0 && $validate = "yes" ]]thenreq_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+1donefifor 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:# Find previously installed patches that the applying patch is# incompatible with.# Parameters:# none## Locals Used:# list# obsPatch# incPat# obsVer# obsBase# incVer# incBase# tmpStr#function eval_compats{typeset -i reqMet=0typeset -i ctr=0typeset -i insPs=0patchFile=""patchFileStripped=/tmp/patchDBstripped.$$if [[ "$validate" = "no" ]]thenReqdPatchCnt=0returnfiif [[ "$PatchMethod" = "progressive" ]]thenreturnfiif [[ -s "$PATCHDBFILE" ]]; thenpatchFile=$PATCHDBFILEelif [[ ! -s $INSTPATCHES_FILE ]]; thenreturnelsepatchFile=$INSTPATCHES_FILEfi$SED 's/,//g' $patchFile > $patchFileStrippedwhile read linedoLoadPtchArrays $lineinsPs=insPs+1done < $patchFileStrippedobsPatch=""ctr=1while (( ctr < insPs ))do# If this is a reinstallation of an already installed# patch get out. This stuff doesn't apply.if [[ ${installedPtch[$ctr]} = "$PatchNum" ]]thencd $patchdirreturnfi# If an earlier rev of a patch is already installed then# the stuff below doesn't apply.get_base_code ${installedPtch[$ctr]}instBase=$cur_base_codeget_vers_no ${installedPtch[$ctr]} $instBaseinstVers=$cur_vers_noif [[ "$instBase" = "$PatchBase" ]]thenif [[ "$instVers" -ge "$PatchVers" ]]thencd $patchdirreturnfifiobsoletes=${installedObs[$ctr]}if [[ "$compatsAlreadyChecked" == "no" ]]; thenCheckInstallingCompats ${installedPtch[$ctr]} $instBase $instVersfictr=ctr+1doneif [[ "$unReqAlreadyChecked" == "no" ]]; thenCheckUninstalledReqsfitmpUninstReqs="$UninstReqs"# At this point we know if all the installing patches requirements# have been met. Now we need to check to see if any required or# incompatible patches have been obsoleted.ctr=1tmpObsdUninstReqs=""while (( ctr < insPs ))do# Check all the installed patches for obsoletions.if [[ -n ${installedObs[$ctr]} ]]thenfor ob in ${installedObs[$ctr]}doget_base_code $obobBase=$cur_base_codeget_vers_no $ob $obBaseobVers=$cur_vers_no# Check the obsoleted patches to see if they# obsolete a patch that is required to be# installed. If that is true then a# requirement has been met.for obReq in $Requiresdo# A counter is needed to determine if# all req's have been met.get_base_code $obReqobPatchBase=$cur_base_codeif [[ "$obBase" = "$obPatchBase" ]]then# At this point we know the# the installing patch requires# a patch that has been obsoleted# by an already installed patch.# This may even be a patch that hasn't# been installed. (sigh)# We need to check to see if this# is truely valid.for un in $UninstReqsdoif [[ "$un" != "$obReq" ]]then# Reconstruct# theuninstalled# req's list.tmpObsdUninstReqs="$tmpObsUninstReqs $un"fidoneReqdPatchCnt=ReqdPatchCnt-1fidone# Check the installing patch to see if# it is incompatible with a patch that# has been installed and has been obsoleted.for inc in $Incompatdoget_base_code $incobPatchBase=$cur_base_codeif [[ "$obBase" = "$obPatchBase" ]]thenInstIncompat=${installedPtch[$ctr]}#InstIncompat=$patchcheck_patch_compatibilityfidonedonefi# Handle previously installed patches with# requirements.if [[ -n ${installedReq[$ctr]} ]]thenfor req in ${installedReq[$ctr]}doget_base_code $reqreqBase=$cur_base_codeget_vers_no $req $reqBasereqVers=$cur_vers_noincReqObFlag="req"check_INC_REQ_OBS "$reqBase" "$reqVers" \${installedPtch[$ctr]} "${installedPkgs[$ctr]}" \"$incReqObFlag"donefi# Handle previously installed patches with# incompatibilities.if [[ -n ${installedInc[$ctr]} ]]thenfor inc in ${installedInc[$ctr]}doget_base_code $incincBase=$cur_base_codeget_vers_no $inc $incBaseincVers=$cur_vers_noincReqObFlag="inc"check_INC_REQ_OBS "$incBase" "$incVers" \${installedPtch[$ctr]} "${installedPkgs[$ctr]}" \"$incReqObFlag"donefictr=ctr+1doneif [[ -n "$tmpUninstReqs" || -n "$tmpObsdUninstReqs" ]]thenUninstReqs="$tmpUninstReqs $tmpObsdUninstReqs"ficd $patchdir}# Description:# Check the REQUIREd or INCOMPATs installed patch to determine# if it has been obsoleted.# Parameters:# none# Locals Set:# obsByPatch# obsPatch# Globals Set:# none# Parameters:# $1 Base code of either INCOMPAT or REQUIRE patch.# $2 Version of either INCOMPAT or REQUIRE patch.# $3 The patch associated with the INCOMPAT or REQUIRE requirement.# $4 The pkg associated with the patch.# $5 A flag determining either INCOMPAT or REQ.#function check_INC_REQ_OBS{obsByPatch=""obsPatch=""# Check to see if the incompatible/required patch has# been explicitly obsoleted.for instPkg in $4doif [[ -f $instPkg/save/$3/obsoleted_by ]]thenobsByPatch=$(/usr/bin/cat \$instPkg/save/$3/obsoleted_by)breakfidone# Check to see if this is an implicit/requires patch# that obsoletes the installing patch.if [[ -z "$obsByPatch" ]]then# We need to check to see if the obsoleted patch# is obsoleted by an already installed patch.for ob in $instPkg/save/$ObsArrEntrydoif [[ -f $ob/obsoleted_by ]]thenobsPatch=$($NAWK ' { print $1 } ' \$ob/obsoleted_by)fiif [[ -n "$obsPatch" ]]thenbreakfidonefiif [[ "$PatchBase" = "$1" ]]thenif [[ "$5" = "inc" && "$PatchVers" -ge "$2" ]]thenif [[ -n "$obsByPatch" ]]thenInstIncompat=$obsByPatchelseInstIncompat=$3fielif [[ "$5" = "req" && "$PatchVers" -le "$2" ]]thenif [[ -n "$obsByPatch" ]]thenReqdPatchCnt=1UninstReqs=$obsByPatchelseReqdPatchCnt=1UninstReqs=$3fificheck_patch_compatibilityfi# Check to see if this patch explicitly obsoletes# a patch that is INCOMPAT.if [[ "$5" = "inc" ]]thenfor ob in $Obsoletesdoget_base_code $obobsBase=$cur_base_codeget_vers_no $ob $cur_base_codeobsVers=$cur_vers_no#if [[ "$obsBase" = "$1" && "$obsVers" -ge "$2" ]]if [[ "$obsBase" = "$1" ]]thenif [[ -n "$obsByPatch" ]]thenInstIncompat=$obsByPatchelseInstIncompat=$3ficheck_patch_compatibilityfidonefi}# Description:# Construct the files needed to backout the patch for dryrun mode.# Parameters:# none# Globals Set:# none# Parameters:# $1 Dryrun directory#function construct_backout_files {$NAWK ' { print $2 } ' $1/dryrun.ipo.asc > $PATCHFILES}# Description:# Check to see if there will be enough space for the backout pkg(s).# There is no 100% sure way to calculate the size of the FS needed# to produce the backout pkg and to save the backout pkg.# Parameters:# none# Globals Set:# none# Locals Used:# spaceRequired# Parameters:# $1 Dryrun Directory#function check_dryrun_backoutSpace {typeset -i totalDRBytesNeeded=0typeset -i totalDRKBytesNeeded=0typeset -i DRBytesNeeded=0typeset -i DRBytesAvail=0typeset -i DRKbytesAvail=0# NOTE: This function makes it best guess at how big the backout# staging area needs to be to save the backout pkg(s). It does a# good job except for hard links. If a hard link is being installed# but already exists pkgadd -D will determine that it does not need# to be installed which is correct. Although the preinstall script# will still insert the target link in the staging area and since# this function relies on the output of pkgadd -D, the target link# isn't accounted for during the space calculations.cat $PATCHFILES | while read linedoDRBytesNeeded=0if [[ "$ROOTDIR" != "/" ]]; thenline="$ROOTDIR$line"fiDRBytesNeeded=$($WC -c $line 2>/dev/null | $NAWK ' { print $1 } ' )if (( DRBytesNeeded == 0 )); then# Add 512 bytes for directoriesDRBytesNeeded=DRBytesNeeded+512fitotalDRBytesNeeded=DRBytesNeeded+totalDRBytesNeededdone# To build and compress the backout packages in the archive directory# takes about 3x as much space then there really needs to be# to save just the archive. This is due to the proto directory,# the make of the pkg and the translation of the pkg.totalDRBytesNeeded=totalDRBytesNeeded*3+100if [[ "$PATCH_UNDO_ARCHIVE" != "none" ]]thenbackout_dir=$PATCH_UNDO_ARCHIVEelseif [[ "$netImage" = "boot" ]]thenbackout_dir=$ROOTDIR/tmpelsebackout_dir=$PKGDBfifi# Is there enough space? Use sed to extract the fourth field of df.DRKbytesAvail=$($DF -b $backout_dir | tail -1 | \$SED 's/^[^ ]*[ ]*\([^ ]*\).*/\1/')DRBytesAvail=DRKbytesAvail*1024if (( totalDRBytesNeeded > DRBytesAvail ))thentotalDRKBytesNeeded=totalDRBytesNeeded/1024/usr/bin/gettext "Insufficient space in $backout_dir to save old files.\nSpace required in kilobytes: $totalKbytesNeeded\nSpace available in kilobytes: $DRKbytesAvail\n"$RM -fr $backout_dir/$2patch_quit 4 "no"return 0fireturn 1}# Description:# Check the applicable files systems for writability.# Parameters:function checkFS {fileSys=""fileSys=$($NAWK ' $3 ~ /FALSE/ { print $1 } ' $dryrunDir/dryrun.fs.asc)if [[ -n "$fileSys" ]]; then/usr/bin/gettext "\nThe $fileSys file system is not writable.\n" \>> $LOGFILE/usr/bin/gettext "Patch $PatchNum can not be installed until $fileSys\n" \>> $LOGFILE/usr/bin/gettext "is made writable.\n\n" >> $LOGFILEreturn 0fireturn 1}# Description:# Evaluate the dry run data# Parameters:# $1 - exit code from pkgadd -D.# Globals Set:# none# Locals Used:# dryrunExit# dryrunDir#function eval_dryrun {dryrunExit=dryrunDir=dryrunDir="/tmp/$PatchNum.$$"if [[ ! -d "$dryrunDir" || "$1" != "0" ]]; thendryrunFailure="yes"returnfidryrunExit=$($NAWK -F= ' $1 ~ /^EXITCODE$/ { print $2 } ' $dryrunDir/dryrun.isum.asc )# Check the FS's for writability. bug 4155609if [[ "$dryrunExit" != "0" ]]theneval_dryrun_failures "$dryrunDir"dryrunFailure="yes"fiif [[ "$saveold" = "yes" ]]thenconstruct_backout_files "$dryrunDir"if check_dryrun_backoutSpace "$dryrunDir"thendryrunFailure="yes"fifiif checkFS; thendryrunFailure="yes"fi}# Description:# Evaluate the dry run failures.# Parameters:# $1 Dryrun directory# Globals Set:# none# Locals Used:# dryrunFailures# failed# exitCheck#function eval_dryrun_failures {failed=dryrunFailures=""spaceNeeded=""/usr/bin/gettext "The following errors were reported by pkgadd dryrun...\n\n"exitCheck=$($NAWK -F= ' $2 ~ /!0/ { print $1 } ' $1/dryrun.isum.asc )for code in $exitCheckdocase $code inCHECKINSTALLEXITCODE) /usr/bin/gettext " The checkinstall script failed.\n" ;;REQUESTEXITCODE) /usr/bin/gettext " The request script failed.\n" ;;esacdonedryrunFailures=$($NAWK -F= ' $2 ~ /NOT_OK/ { print $1 } ' \$1/dryrun.isum.asc )failed=" Installation failed due to"for param in $dryrunFailuresdocase $param inSPACE) /usr/bin/gettext "$failed lack of space reported by pkgadd dryrun\n\n" ;;PARTIAL) /usr/bin/gettext "$failed partial install reported by pkgadd dryrun\n\n" ;;RUNLEVEL) /usr/bin/gettext "$failed incorrect run level\n\n" ;;PKGFILES) /usr/bin/gettext "$failed bad pkg reported by pkgadd dryrun\n\n" ;;DEPEND) /usr/bin/gettext "$failed incorrect depend file\n\n" ;;CONFLICT) /usr/bin/gettext "$failed conflicts reported by pkgadd dryrun\n\n" ;;SETUID) /usr/bin/gettext "$failed incorrect uid\n\n" ;;PKGDIRS) /usr/bin/gettext "$failed package directories not found\n\n" ;;esacdonedoLogfilepatch_quit 30 "no"}# 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 patchadd 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" ]]thenreturnfi$UMOUNT $ROOTDIR/tmp/root/var$UMOUNT $ROOTDIR/tmp$UMOUNT $ROOTDIR/mnt}# Description:# Patch the product Database on the netinstall image.# Parameters:# none# Globals Set:# none#function patch_product {# This routine was the beginning of the Fresh bits function.# It is not functional and therefore is not called.if [[ "$netImage" != "product" ]]thenreturnfieval_utilitiesactivate_patch "$patchdir"cd $patchdircollect_data# If this is the first patch to the product area create the patch repository.if [[ ! -d "$PATCHDB" ]]then$MD -p -m 750 $PATCHDBfi# Check to see if the pkg to patch is in the product area# and all VERSION and ARCH are the right instance.eval_inst_patches $PKGDBcheck_patch_compatibilitycheck_if_applied "$PATCHDB" "$PatchNum"check_if_obsolete "$PATCHDB" # see if this package is already obsoleteif [[ "$isapplied" = "yes" ]]theneval_applied_patch $PATCHDB $PKGDB $PatchMethod $saveold $PatchNumfigen_patchpkg_listcheck_pkgs_installed "$PKGDB" "$patchdir"#### Make sure what PKGDBARG is !!!gen_install_filelist "$PKGDB" "$PKGDBARG"gen_patch_filelistcheck_reloc_dirmerge_pkgmaps}# Description:# Merge the PATCHLIST with each pkgmap called out by the pkg.# Parameters:# none# Globals Set:# none#function merge_pkgmaps {for pkg in $pkglistdoecho "test"cd $ROOTDIR/$pkg$NAWK '$1 ~ /[:]/ { # size lineif (NF == 3) { # if uncompresseduncompress="yes" }} ' pkgmapif [[ "$uncompress" != "yes" ]]thenzcat reloc.cpio.Z | cpio -idumfi$DIFF pkgmap $patchDir/$pkg/pkgmap | $NAWK ' $1 ~ /[>]/ {if ($3 == "i") { next; }if ($3 == "v" || $3 == "e") { next; }{ print $2 $3 $4 $5 $6 $7 $8 } } ' > tmpPkgmapcat tmpPkgmap |while read linedo$GREP $line pkgmapif [[ $? = 0 ]]then$SED 's/$line/'fi########## Continue with merging the maps########donedone}# Description:# Ceck to see if the reloc directory is compressed, if it is# decompress it and poke in the objects being replaced by the patch.# Parameters:# none# Globals Set:# none#function check_reloc_dir {for pkg in $pkglistdocd $ROOTDIR/$pkgif [[ -d reloc ]]thencd relocfiif [[ -f reloc.cpio.Z ]]thenzcat reloc.cpio.Z | cpio -idumelsecpio -idum -l reloc.cpiofidone}# Description:# Check exit code from pkgadd# Parameters:# $1 exitcode from pkgadd# Globals Set:# none#function check_pkgadd_exitcode {pkgadd_code=$1# If it's a suspend (exit code 4), then the# message type is the appropriate patchadd# exit code and the appropriate message follows.# A suspend means, nothing has been installed.if [[ $pkgadd_code == 4 ]] # suspendthenMessage=$($EGREP PaTcH_MsG $LOGFILE | $SED s/PaTcH_MsG\ //)if [[ $Message = "" ]]thenpkgadd_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"if [[ "$lastPtchInList" != "$PatchNum" ]]then# If there are more pkgs in the list skip them since this patch# will not be installed./usr/bin/gettext "Skipping patch $PatchNum"/usr/sbin/patchrm -R $ROOTDIR $PatchNumSomething_Installed=0pkg=return 1elsepatch_quit $Msg_Type "no"return 0fififi# reboot after installation of all packagesif [[ $pkgadd_code == 10 || $pkgadd_code == 20 ]]then/usr/bin/gettext "Reboot after patchadd has installed the patch.\n"fiif [[ $pkgadd_code == 5 ]] # administrationthencat $LOGFILEif [[ "$lastPtchInList" != "$PatchNum" ]]then# If there are more pkgs in the list skip them since this patch# will not be installed./usr/bin/gettext "Skipping patch $PatchNum"/usr/sbin/patchrm -R $ROOTDIR $PatchNumSomething_Installed=0pkg=return 1else/usr/sbin/patchrm -R $ROOTDIR $PatchNumSomething_Installed=0fielif [[ $pkgadd_code != 0 ]]then$EGREP ERROR $LOGFILEif [[ "$lastPtchInList" != "$PatchNum" ]]then# If there are more pkgs in the list skip them since this patch# will not be installed./usr/bin/gettext "Skipping patch $PatchNum"/usr/sbin/patchrm -R $ROOTDIR $PatchNumSomething_Installed=0pkg=return 1else/usr/sbin/patchrm -R $ROOTDIR $PatchNumSomething_Installed=0patch_quit 5 "no"return 0fielseSomething_Installed=1fireturn 1}# Description:# If installing 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:# Apply a direct instance patch# Parameters:# none# Globals Set:# pkgDispList#function apply_diPatch {exit_code=0pkgInst=""pkgDispList=""dryrunFailure=""ReqArrCount=0firstTimeThru="yes"cd $patchdircurdir=$(pwd)# strip the installed instance out of the package list# and the pkgabbrev.for pkg in $pkglistdonewpkglist="$newpkglist ${pkg:%,*}"pkgInst="$pkgInst ${pkg:#*,}"donepkglist=$newpkglist/usr/bin/gettext "Installing patch packages...\n"# actually install the packages#for pkg in $pkglistdoif [[ -f $pkg/pkginfo ]] # If this is a packagethen$CP $RESPONSE_FILE $RESPONSE_FILE.1if [[ "$DRYRUN" = "no" ]]thenpkgadd $MOPTION -S -n -a $ADMINTFILE -r $RESPONSE_FILE.1 \-R $ROOTDIR -d . $pkg 1>>$LOGFILE </dev/null 2>&1exit_code=$?elseif [[ "$firstTimeThru" = "yes" ]]thenpkgadd -D /tmp/$PatchNum.$$ -S -n -a $ADMINTFILE \$MOPTION -r $RESPONSE_FILE.1 \-R $ROOTDIR -d . $pkglist 1>>$LOGFILE </dev/null 2>&1exit_code=$?firstTimeThru="no"eval_dryrun "$exit_code"if [[ "$dryrunFailure" = "yes" ]]then/usr/bin/gettext "\nPatch $PatchNum failed to install due to a failure produced by pkgadd.\n\n"doLogfilereturn 0fifipkgadd -S -n -a $ADMINTFILE -r $RESPONSE_FILE.1 \$MOPTION -R $ROOTDIR -d . $pkg 1>>$LOGFILE </dev/null 2>&1exit_code=$?fiif check_pkgadd_exitcode "$exit_code"thenreturn 0fifi$RM -f $RESPONSE_FILE.1if [[ "$exit_code" = "0" || "$exit_code" = "10" \|| "$exit_code" = "20" ]]then# We want to populate the PATCHDBFILE with the# instance of the pkg if it exists,# not just the pkgabbrev.if [[ -n "$pkgInst" ]]; thentmppkgList=""pkgCtr=0for inst in $pkgInst; doinstalled="${inst:%\.*}"pkg="${pkg:%\.*}"if [[ "$installed" == "$pkg" && \"$pkgCtr" == 0 ]]; thenpkgDispList="$pkgDispList $inst"pkgCtr=1else# Reconstruct the pkgInst list.# This needs to be done in case# there are multiple ARCH's# being installed and the pkgs# in the patch may contain# SUNWxx, SUNWxx.u SUNWxx.mtmppkgList="$tmppkgList $inst"fidoneelsepkgDispList="$pkgDispList $pkg"fipkgInst="$tmppkgList"fidoneif (( Something_Installed == 1 ))thencd $ROOTDIRcd var/sadm/pkgInstPkgs=$(pkginfo -R $ROOTDIR | $NAWK '{ printf ("%s ", $2) }END { printf("\n") } ')## With that done successfully, obsolete explicitly# listed prior patches.#for patch in $Obsoletesdoget_base_code $patchpatch_base=$cur_base_codeget_vers_no $patch $patch_basepatch_vers=$cur_vers_nofor pkg in $InstPkgsdo## Locate all applicable obsoleted patches# by searching for entries with identical# base codes and versions greater than or# equal to the one specified.#cd $pkg/savepatch_list=$($LS -db $patch_base* 2>/dev/null)for cur_patch in $patch_listdoget_vers_no $cur_patch $patch_baseif [[ $cur_vers_no -gt $patch_vers ]]then/usr/bin/gettext "WARNING: Later version of obsolete patch $patch was found.\nLeaving $cur_patch as is.\n"continue;fiif [[ -f $cur_patch/undo ]]then$MV $cur_patch/undo $cur_patch/obsoleteecho $PatchNum >> $cur_patch/obsoleted_byelif [[ -f $cur_patch/undo.Z ]]then$MV $cur_patch/undo.Z $cur_patch/obsolete.Zecho $PatchNum >> $cur_patch/obsoleted_byelif [[ -f $cur_patch/remote ]]thenset_remote_state $pkg $cur_patchcheck_remote_file $pkg $cur_patchecho $PatchNum >> $cur_patch/obsoleted_byelif [[ -f $cur_patch/obsolete || -f $cur_patch/obsolete.Z ]]then$GREP $PatchNum $cur_patch/obsoleted_by >/dev/nullif [[ $? -ne 0 ]]thenecho $PatchNum >> $cur_patch/obsoleted_byfifidonecd $ROOTDIRcd var/sadm/pkgdonedone/usr/bin/gettext "\nPatch number $PatchNum has been successfully installed.\n"else/usr/bin/gettext "Installation of patch number $PatchNum has been suspended.\n"fidoLogfile$RM -f $RESPONSE_FILEcd $curdirreturn 1}# Description:# Copy the temporary log file.#function doLogfile{if [ -f $LOGFILE ]thenif [[ ! -d $PATCHDB/$PatchNum ]]then$MD -p -m 750 $PATCHDB/$PatchNumfi/usr/bin/gettext "See $PATCHDB/$PatchNum/log for details\n"$CP -p $LOGFILE $PATCHDB/$PatchNum/log$RM -f $LOGFILEfi}# Description:# Determine which patch is required for this OS release to work.# Parameters:# $1 Solaris release of the managing host# $2 The patch method to use# Globals Set:# ReqdOSPatch patch number that this OS requires# ReqdOSPatchBase base number of the above patch# ReqdOSPatchVers version number of the above patch#function ident_reqd_patch {if [[ ! -d $PATCHDB ]]then$MD -p -m 750 $PATCHDBficd $PATCHDBif [[ "$PatchMethod" = "direct" ]]thencase $1 in"2.0")/usr/bin/gettext "ERROR: Solaris 2.0 is not capable of installing patches\nto a 2.5 or later client.\n";patch_quit 21 "yes";;"2.1")/usr/bin/gettext "ERROR: Solaris 2.1 is not capable of installing patches\nto a 2.5 or later client.\n";patch_quit 21 "yes";;"2.2")ReqdOSPatch="101122-07";;"2.3")ReqdOSPatch="101331-06";;"2.4")MgrPlatform=$(uname -p);case $MgrPlatform in"sparc")ReqdOSPatch="102039-04";;"i386")ReqdOSPatch="102041-04";;esac;;esacif [[ "$ReqdOSPatch" != "none" ]]thenget_base_code $ReqdOSPatchReqdOSPatchBase=$cur_base_code;get_vers_no $ReqdOSPatch $cur_base_codeReqdOSPatchVers=$cur_vers_no;for apatch in *doget_base_code $apatchif [[ "$ReqdOSPatchBase" = "$cur_base_code" ]]thenget_vers_no $apatch $cur_base_codeif [[ "$ReqdOSPatchVers" -le "$cur_vers_no" ]]thenReqdOSPatchFnd="true"fifidonefificd $patchdir}# Description:# Evaluate the patch provided and return the patch type.# Parameters:# $1 - patch directory# Globals Set:# PatchType one of:# diPatch direct instance patch# caPatch cross architecture patch# piPatch progressive instance patch#function eval_patch {if [[ -f ${1}/.diPatch ]]thenif [[ -d ${1}/old_style_patch ]]thenPatchType="caPatch"elsePatchType="diPatch"fielsePatchType="piPatch"fi}# Description:# Evaluate the patch methodology to be used based upon the# Solaris version of the manager and target hosts.# Parameters:# $1 Managing host OS version# $2 Target host OS version# $3 patch type# Globals Set:# PatchMethod one of:# direct direct instance method# progressive progressive instance method# PATCH_PROGRESSIVE#function eval_OS_version {if [[ "$1" > "2.5" ]]thenif [[ "$2" < "2.5" ]]thenPatchMethod="progressive"PATCH_PROGRESSIVE="true"elseif [[ $3 = "diPatch" || $3 = "caPatch" ]]thenPatchMethod="direct"PATCH_PROGRESSIVE="false"if [[ "$1" > "2.5.1" ]]thenDRYRUN="yes"fielsePatchMethod="progressive"PATCH_PROGRESSIVE="true"fifielif [[ "$1" < "2.5" ]]thenif [[ "$2" < "2.5" ]]thenPatchMethod="progressive"PATCH_PROGRESSIVE="true"elseif [[ $3 = "diPatch" || $3 = "caPatch" ]]thenPatchMethod="direct"PATCH_PROGRESSIVE="false"elsePatchMethod="progressive"PATCH_PROGRESSIVE="true"fifielseif [[ "$2" < "2.5" ]]thenif [[ $PatchType = "diPatch" ]]then/usr/bin/gettext "ERROR: This direct instance patch cannot be installed\nonto a Solaris $TrgOSVers host.\n"patch_quit 21 "yes"elsePatchMethod="progressive"PATCH_PROGRESSIVE="true"fielseif [[ $3 = "diPatch" || $3 = "caPatch" ]]thenPatchMethod="direct"PATCH_PROGRESSIVE="false"if [[ "$2" > "2.5.1" ]]thenDRYRUN="yes"fielsePatchMethod="progressive"PATCH_PROGRESSIVE="true"fififi}# Description:# Evaluate the applied patch to be sure we aren't going to hose up# any existing backout data.## If this is a progressive instance patch, here's how it is evaluated:# prev | curr | .nofilestosave | OK to | How to verify previous# save | save | exist? | continue? | save/no_save state#-------+------+----------------+-----------+--------------------------# | | yes | | a. empty save directory# 1 yes | yes |----------------| continue +--------------------------# | | no | | b. ! empty save directory#-------+------+----------------+-----------+--------------------------# | | yes | continue | a. empty save directory# 2 yes | no |----------------+-----------+--------------------------# | | no | terminate | b. ! empty save directory#-------+------+----------------+-----------+--------------------------# 3 no | no | no | continue | empty save directory#-------+------+----------------+-----------+--------------------------# 4 no | yes | no | terminate | empty save directory#-------+------+----------------+-----------+--------------------------## And the direct instance patch is evaluated as follows:# prev | curr | OK to | How to verify previous# save | save | continue? | save/no_save state# -------+------+-----------+------------------------------------------# A. no | yes | terminate | ! -d /var/sadm/pkg/<pkg>/save/<patch_id># -------+------+-----------+------------------------------------------# B. no | no | continue | ! -f /var/sadm/pkg/<pkg>/save/<patch_id># -------+------+-----------+------------------------------------------# C. yes | -- | continue | -f /var/sadm/pkg/<pkg>/save/<patch_id># -------+------+-----------+------------------------------------------## Parameters:# $1 patch database directory# $2 package database directory# $3 the patch method# $4 the saveold parameter value# $5 the patch number# Globals Set:#function eval_applied_patch {if [[ "$3" = "progressive" ]]thenif [[ "${4}" = "no" ]]thenif [ ! -f "${1}/${5}/.nofilestosave" -a \\( -f "${1}/${5}/save/archive.cpio" -o \-f "${1}/${5}/save/archive.cpio.Z" \) ]then# condition #2b - terminate/usr/bin/gettext "A previous installation of patch ${5} was invoked which saved\nfiles that were to be patched.\nSince files have already been saved, you must apply this patch\nWITHOUT the -d option.\n"patch_quit 17 "no"return 0elif [ -f "${1}/${5}/.nofilestosave" -a \! -f "${1}/${5}/save/archive.cpio" -a \! -f "${1}/${5}/save/archive.cpio.Z" -a \! -f "${1}/${5}/save/remote" ]then# condition #2a - $RM .nofilestosave$RM ${1}/${5}/.nofilestosavefielse # ${4} = "yes"if [ ! -f "${1}/${5}/.nofilestosave" -a \! -f "${1}/${5}/save/archive.cpio" -a \! -f "${1}/${5}/save/archive.cpio.Z" -a \! -f "${1}/${5}/save/remote" ]then# condition #4 - terminate/usr/bin/gettext "A previous installation of patch ${5} was invoked with the -d option.\ni.e. Do not save files that would be patched\nTherefore, this invocation of patchadd\nmust also be run with the -d option.\n"patch_quit 17 "no"return 0fifielse # $3 != "progressive"$FIND ${2}/. -name "${5}" -print >/dev/null 2>&1prev_save=$?if [[ $prev_save != 0 && "${4}" = "yes" ]]then# condition A./usr/bin/gettext "A previous installation of patch ${5} was invoked\nwith the -d option. i.e. Do not save files that would be patched\nTherefore, this invocation of patchadd\nmust also be run with the -d option.\n"patch_quit 17 "no"return 0fifireturn 1}function eval_utilities {for command in $REQD_CMDS; doif [[ ! -f $command ]]then/usr/bin/gettext "ERROR: Cannot find $command which is required for proper execution of patchadd.\n"patch_quit 1 "yes"fidone}# Description:# Check the remote file to see if the remotely stored backout data# location needs to be changed.# Parameters:# $1 - package associated with the patch# $2 - the patch number## Environment Variable Set:#function check_remote_file{if [[ "$PatchMethod" = "direct" ]]thenif [[ -f $PKGDB/$1/save/$2/remote && -s $PKGDB/$1/save/$2/remote ]]thenPATCH_UNDO_ARCHIVE=$($GREP "FIND_AT" $PKGDB/$1/save/$2/remote \| $AWK -F= '{print $2}')PATCH_UNDO_ARCHIVE=$(dirname $PATCH_UNDO_ARCHIVE)fielse# Add logic for pi patchesecho $PATCH_UNDO_ARCHIVE > /dev/nullfi}# Description:# Change the STATE parameter to an obsolete state# Parameters:# $1 - package associated with the patch# $2 - the patch number## Environment Variable Set:# nonefunction set_remote_state{$($GREP . $PKGDB/$1/save/$2/remote | $SED 's/STATE=.*/STATE=obsolete/' > $TEMP_REMOTE)$RM -f $PKGDB/$1/save/$2/remote$MV $TEMP_REMOTE $PKGDB/$1/save/$2/remote$RM -f $TEMP_REMOTE}# Description:# Determine if the patch is a progressive instance patch# Parameters:# none## Environment Variable Set:# nonefunction is_progressive{if [[ "$PatchMethod" = "progressive" ]]thenecho $PatchNum | $GREP $PatchIdFormat >/dev/nullif [[ $? -ne 0 ]]then/usr/bin/gettext "Invalid patch id format: $PatchNum.\n"patch_quit 29 "no"return 0fiif [[ "$PatchType" = "diPatch" ]]then/usr/bin/gettext "ERROR: A progressive instance patch is required\nbut patch number $PatchNum is direct instance only\nand can only be installed onto a host running Solaris 2.5 or later.\n"patch_quit 22 "no"return 0elif [[ "$PatchType" = "caPatch" ]]thencd old_style_patchpatchdir=$(pwd)fifireturn 1}# Description:# Display error messages if the patch being applied conflicts with incompatible,# required or obsolete patches.# Parameters:# none## Environment Variable Set:# nonefunction check_patch_compatibility{if [[ "$InstIncompat" != "" ]]then/usr/bin/gettext "ERROR: This patch is incompatible with patch $InstIncompat\nwhich has already been applied to the system.\n"patch_quit 24 "no"return 0fiif (( ReqdPatchCnt == 1 ))then/usr/bin/gettext "ERROR: This patch requires patch $UninstReqs\nwhich has not been applied to the system.\n"patch_quit 25 "no"return 0elif (( ReqdPatchCnt > 1 ))then/usr/bin/gettext "ERROR: This patch requires the following patches\nwhich have not been applied to the system:\n"echo " $UninstReqs"patch_quit 25 "no"return 0fiif [[ "$ObsoletePast" != "" ]]then/usr/bin/gettext "WARNING: This patch appears to have been produced after the\nbase code $ObsoletePast was obsoleted. This patch will be treated\nas though it were also obsoleted.\n"fiif [[ "$ReqdOSPatch" != "none" && "$ReqdOSPatchFnd" != "true" ]]then/usr/bin/gettext "ERROR: This Solaris $MgrOSVers server requires the following patch before it\ncan apply a patch to a Solaris $TrgOSVers client.\n patch base number : $ReqdOSPatchBase\n patch version number : $ReqdOSPatchVers or higher.\n"patch_quit 21 "yes"fireturn 1}############################################# Main Routine ############################################### - Get the product version <name>_<version> of local Solaris# installation (sets the prodver global variable)# - Parse the argument list and set globals accordingly# - Make sure the user is running as 'root'#CmdArgs=$*set_globalsvalidate_uid # the caller must be "root"parse_args $CmdArgscheck_for_2_6 # Needed in case usr/sbin is nfs mountedsetup_net_imagecheck_PatchDBs# determine the OS versions involvedfind_softinfos $ROOTDIRget_OS_version $TRGSOFTINFO $MGRSOFTINFO $ROOTDIReval_utilities # make sure the required utilities are available# If we're in the mini-root, invoke pkgadd with -M# or if the managing host is 2.6 or later.check_pkgadd_M_optionfor ptch in $multiPtchListdoset_globalsif [[ "$multiPtchInstall" = "yes" ]]thenpatchdir="$multiPtchDir/$ptch"fieval_patch $patchdir # determine what type of patch it is# Establish the patching options based on the versions involvedeval_OS_version $MgrOSVers $TrgOSVers $PatchType# Clear the list of installed patches, if it's there$RM -f $INSTPATCHES_FILEif activate_patch "$patchdir"thencontinuefi# Hopefully there won't be many patches that contain this script.# This could have dier consequences.if execute_prePatch "$patchdir" "$ROOTDIR" # do itthencontinuefi## Change to the patch directory and set globals according to the patchID# found in the pkginfo files of the patch packages.#collect_data# Check to see if there are any remains from a previous installation.check_file_recovery_dirif is_progressivethencontinuefiident_reqd_patch $MgrOSVers # determine if this host needs a patch# Check the output from the pkginfo command.# See if there are any corrupt pkginfo files...#chk_pkginfo_cmdif [[ "$PatchMethod" = "direct" ]]then/usr/bin/gettext "Checking installed patches...\n"fieval_inst_patches $PKGDB > /dev/null 2>&1 # Scan installed patches & analyze.check_if_applied "$PATCHDB" "$PatchNum"if [[ "$isapplied" = "yes" ]]thenif eval_applied_patch $PATCHDB $PKGDB $PatchMethod $saveold $PatchNumthencontinuefifi# Evaluate the compatibility of REQUIRES INCOMPATS and# OBSOLETES.eval_compatsif check_if_obsolete "$PATCHDB" # see if this package is already obsoletethencontinuefi# For the old-style patch, there were sometimes problems running on a# client and also symbolic links were not allowed. We check for those next.if [[ "$PatchMethod" = "progressive" ]]thenverify_clientif check_for_symbolic_link "$patchdir"thencontinuefifitrap 'trap_notinstalled "$PATCHDB" "$PatchNum"' 1 2 3 15 # set the trapbuild_admin_filegen_patchpkg_list# If this is a re-installation of the patch, remove the already# installed packages from the package list. If all packages in# the patch have already been applied, then exit.#if [[ "$isapplied" = "yes" ]]; thenif gen_uninstalled_pkgs $PKGDB $PATCHDB $PatchNumthencontinuefificheck_pkgs_installed "$PKGDB" "$patchdir"if check_for_action "$client" "$is_a_root_pkg"thencontinuefiif check_patch_compatibilitythencontinuefi# Set flag in case of power outagefile_recovery# Construct the required response filebuild_response_file $PatchType $PatchMethodmake_params_available # export parameters for use by patch scripts# If there is a prepatch file in the $patchdir directory,# execute it. If the return code is not 0, exit patchadd# with an error. Lord knows what this does. We just have to hope# it's benign.#if [[ "$isapplied" = "no" ]] # if this isn't a reinstallationthenif execute_prepatch "$patchdir" # do itthencontinuefifigen_install_filelist "$PKGDB" "$PKGDBARG"## OK, which patch method are we using?#if [[ "$PatchMethod" = "direct" ]]then## This is how we install a direct instance patch#gen_patch_filelistcompute_fs_space_requirementsif check_fs_spacethencontinuefiif check_backout_space "$PKGDB" "$PatchNum" "$patchdir" "$saveold"thencontinuefiif apply_diPatchthencontinuefielseif check_validation "$validate"thencontinuefigen_patch_filelistcompute_fs_space_requirementsif check_fs_spacethencontinueficreate_archive_area "$PATCHDB" "$PatchNum"if check_backout_space "$PATCHDB" "$PatchNum" "$patchdir" "$saveold"thencontinuefitrap 'trap_backoutsaved "$PATCHDB" "$PatchNum" "$patchdir"' 1 2 3 15# - Save current versions of files to be patched# - On servers, spool the patch into /export/root/templates for# future clients (CURRENTLY DISABLED)# - Build admin file for later use by pkgaddif save_overwritten_files "$PATCHDB" "$PatchNum" "$patchdir" "$saveold"thencontinuefitrap 'trap_backout "$patchdir" "$PatchNum"' 1 2 3 15# - Install the patch packages# - Print results of install# - Save ACTION file if exists and README file.if install_patch_pkgs "$PATCHDB" "$PatchNum" "$patchdir" \"$PKGDBARG" "$PKGDB"thencontinuefifiif execute_postpatch "$PATCHDB" "$PatchNum" "$patchdir"thencontinuefiupdate_patchDB "$PatchNum"print_resultsif [[ "$PatchMethod" = "progressive" ]]then/usr/bin/gettext "\nPatch installation completed.\n"/usr/bin/gettext "See $PATCHDB/$PatchNum/log for more details.\n\n"fiset_patch_status "$PATCHDB" "$PatchNum"remove_filesdonepatch_quit 0 "yes"