#!/bin/sh -h # @(#) installpatch 4.15 95/08/09 SMI # is_server feature is disabled for now.... # # 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 # # Set the path for use with these scripts. PATH=/usr/sbin:/usr/bin:$PATH export PATH umask 022 # Global Files EXISTFILES=/tmp/existfiles.$$ PATCHFILES=/tmp/patchfiles.$$ PKGCOFILE=/tmp/pkgchk.out.$$ VALERRFILE=/tmp/valerr.$$ VALWARNFILE=/tmp/valwarn.$$ ADMINTFILE=/tmp/admin.tmp.$$ ADMINFILE=/tmp/admin.$$ KBYTESFILE=/tmp/kbytes_required.$$ LOGFILE=/tmp/pkgaddlog.$$ TMP_ARCHIVE=/tmp/TmpArchive.$$ TMP_FILELIST=/tmp/FileList.$$ TMP_LIB_DIR=/tmp/TmpLibDir.$$ MYSHOWREV_FILE=/tmp/MyShowrevFile.$$ PARAMS_FILE=/tmp/ParamsFile.$$ Root_Equation_File=/tmp/Root_Equation_File.$$ Var_Equation_File=/tmp/Var_Equation_File.$$ Opt_Equation_File=/tmp/Opt_Equation_File.$$ Usr_Equation_File=/tmp/Usr_Equation_File.$$ Openwin_Equation_File=/tmp/Openwin_Equation_File.$$ client=no is_a_root_pkg=no patchdir= patchnum= patchbase= patchrev= pkglist= printpatches="no" rootlist= saveold="yes" validate="yes" isapplied="no" OpenwinFS= Openwin_Equation= OptFS= Opt_Equation= Root_Equation= UsrFS= Usr_Equation= VarFS= Var_Equation= ROOTDIR="/" PATCHDB="/var/sadm/patch" PKGDB="/var/sadm/pkg" SOFTINFO="/var/sadm/softinfo" PKGDBARG="" # Description: # Usage message # Parameters: # none # print_usage() { cat << EOF Usage: installpatch [-u -d -p -V] [-S | -R ] Options: -u Turn off file validation. Allows the patch to be applied even if some of the files to be patched have been modified since original installation. -d Don't back up the files to be patched. This means that the patch can't be backed out. -p Print a list of the patches currently applied -V Print script version number -S Specify an alternate service (e.g. Solaris_2.3) for patch package processing references. Cannot be specified with the -R option. -R Define the full path name of a subdirectory to use as the root_path. All package system information files are assumed to be located in a directory tree starting in the specified root_path. All patch files generated from the installpatch will be located in the same directory tree. Cannot be specified with the -S option. EOF } # # 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 # execute_prepatch() { retcode= if [ -x "$1/prepatch" ]; then echo "Executing prepatch script..." $1/prepatch retcode=$? if [ "$retcode" != "0" ]; then echo "The prepatch script exited with return code $retcode." echo "Installpatch is terminating." rm -fr /tmp/*.$$ exit 15 fi fi } # # 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 # backoutpatch 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 # execute_postpatch() { retcode= if [ -x "$3/postpatch" ]; then echo "Executing postpatch script..." $3/postpatch retcode=$? if [ "$retcode" != "0" ]; then echo "The postpatch script exited with return code $retcode." if [ "$isapplied" = "no" ]; then cp $1/$2/log /tmp/log.$2 echo "Backing out patch:" cd $3 if [ "$ROOTDIR" != "/" ]; then ./backoutpatch $PKGDBARG $2 else ./backoutpatch $2 fi echo "Installpatch is terminating." echo "See /tmp/log.$2 for more details." else echo "Not backing out patch because this is a re-installation." |tee -a $1/$2/log echo "The system may be in an unstable state!" |tee -a $1/$2/log echo "Installpatch is terminating." echo "See $1/$2/log for more details." fi rm -fr /tmp/*.$$ exit 16 fi fi } # # # Description: # Give a list of applied patches similar in format to the showrev -p # command. Had to write my own because the showrev command won't take # a -R option. # # Parameters: # $1 - package database directory # Globals Set: # none # myshowrev() { if [ -f $MYSHOWREV_FILE ] then cat $MYSHOWREV_FILE return fi olddir=`pwd` cd $1 patches= patches=`grep -l SUNW_PATCHID ./*/pkginfo | \ xargs sed -n 's/^SUNW_PATCHID=//p' | sort -u` #patches=`sed -n 's/^SUNW_PATCHID=//p' ./*/pkginfo | sort -u` if [ "$patches" != "" ]; then for apatch in $patches; do outstr="Patch: $apatch Obsoletes: " patchvers=`grep -l "SUNW_PATCHID=$apatch" ./*/pkginfo | \ sed 's,^./\(.*\)/pkginfo$,\1,'` obsoletes_printed="n" for vers in $patchvers; do if [ "$obsoletes_printed" = "n" ]; then outstr="$outstr`sed -n 's/SUNW_OBSOLETES=//p' ./$vers/pkginfo` Packages: " outstr="$outstr$vers `sed -n 's/VERSION=//p' ./$vers/pkginfo`" obsoletes_printed="y" else outstr="$outstr, $vers `sed -n 's/VERSION=//p' ./$vers/pkginfo`" fi done echo $outstr | tee -a $MYSHOWREV_FILE done else echo "No patches are installed" fi cd $olddir } # # 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 # patchrev activate_patch() { cd $1 for i in */pkginfo; do # # 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. # patchnum=`grep '^SUNW_PATCHID' $i 2>/dev/null | sed 's/.*=[ ]*\([^ ]*\).*/\1/'` break; done if [ "$patchnum" = "" ]; then echo "$1 packages are not proper patch packages." echo 'See "Instructions for applying the patch" in the README file.' exit 7 else # # Get the patch base number (the patch number up to the -) # and the patch revision number (the patch number after the -). # patchbase=`expr $patchnum : '\(.*\)-.*'` patchrev=`expr $patchnum : '.*-\(.*\)'` fi } # Description: # Build the admin file for later use by non-interactive pkgadd # Parameters: # none # Globals Used: # ADMINTFILE build_admin_file() { cat > $ADMINTFILE << EOF mail= instance=unique partial=nocheck runlevel=nocheck idepend=nocheck rdepend=nocheck space=quit setuid=nocheck conflict=nocheck action=nocheck EOF } # 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 # patchdir check_for_action() { if [ "$pkglist" = "" -a "$rootlist" = "" ]; then # # 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 -o $2 = yes ] ; then echo "None of the packages to patch are installed on this system." echo "Installpatch is terminating." exit 8 else # # 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. # Installpatch will exit if the machine is a client, and # there are no root packages to be patched. # echo "This patch is not applicable to client systems." echo "Installpatch is terminating." exit 0 fi fi } # 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. # check_if_applied() { if myshowrev $PKGDB | grep -s "^Patch:[ ]*$2" > /dev/null 2>&1 ; then isapplied="yes" else rm -fr $1/$2 fi } # Description: # Print space error message # space_error_msg() { echo "Not enough space in $1 to apply patch" echo "\t $1 has $2 Kbytes available" echo "\t $1 needs $3 Kbytes free" } # Description: # Check space needed against space available # # Parameters: # None # # Globals Used: # ROOTDIR # VarFS # OptFS # UsrFS # OpenwinFS # Root_Kbytes_Needed # Var_Kbytes_Needed # Opt_Kbytes_Needed # Usr_Kbytes_Needed # Openwin_Kbytes_Needed # # Globals Set: # None # check_fs_space() { exit_status=0 Root_Available=`df -b $ROOTDIR | sed -e '1d' | \ sed -e 's/^\/dev\/dsk\/c[0-9][t]*[0-9]*d[0-9]s[0-9][ ]*//'` # # The root file system must have at least 1Mb of free # space or there will be problems after rebooting # Root_Available=`expr $Root_Available - 1000` if [ "$Root_Kbytes_Needed" -gt "$Root_Available" ] then space_error_msg $ROOTDIR $Root_Available $Root_Kbytes_Needed exit_status=18 fi if [ -n "$UsrFS" ] then Usr_Available=`df -b $ROOTDIR/usr | sed -e '1d' | \ sed -e 's/^\/dev\/dsk\/c[0-9][t]*[0-9]*d[0-9]s[0-9][ ]*//'` if [ "$Usr_Kbytes_Needed" -gt "$Usr_Available" ] then space_error_msg $ROOTDIR/usr $Usr_Available $Usr_Kbytes_Needed exit_status=18 fi fi if [ -n "$OptFS" ] then Opt_Available=`df -b $ROOTDIR/opt | sed -e '1d' | \ sed -e 's/^\/dev\/dsk\/c[0-9][t]*[0-9]*d[0-9]s[0-9][ ]*//'` if [ "$Opt_Kbytes_Needed" -gt "$Opt_Available" ] then space_error_msg $ROOTDIR/opt $Opt_Available $Opt_Kbytes_Needed exit_status=18 fi fi if [ -n "$VarFS" ] then Var_Available=`df -b $ROOTDIR/var | sed -e '1d' | \ sed -e 's/^\/dev\/dsk\/c[0-9][t]*[0-9]*d[0-9]s[0-9][ ]*//'` if [ "$Var_Kbytes_Needed" -gt "$Var_Available" ] then space_error_msg $ROOTDIR/var $Var_Available $Var_Kbytes_Needed exit_status=18 fi fi if [ -n "$OpenwinFS" ] then Openwin_Available=`df -b $ROOTDIR/usr/openwin | sed -e '1d' | \ sed -e 's/^\/dev\/dsk\/c[0-9][t]*[0-9]*d[0-9]s[0-9][ ]*//'` if [ "$Openwin_Kbytes_Needed" -gt "$Openwin_Available" ] then space_error_msg $ROOTDIR/usr/openwin $Openwin_Available $Openwin_Kbytes_Needed exit_status=18 fi fi if [ "$exit_status" != 0 ] then exit $exit_status fi } # 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: # compute_fs_space_requirements() { VarFS=`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` if [ -z "$OpenwinFS" ] then echo "" >> $Usr_Equation_File cat $Openwin_Equation_File | sed -e 's/^s=0/s=s/' >> $Usr_Equation_File echo "s=0" > $Openwin_Equation_File fi echo "" >> $Root_Equation_File if [ -z "$UsrFS" ] then cat $Usr_Equation_File | sed -e 's/^s=0/s=s/' >> $Root_Equation_File echo "s=0" > $Usr_Equation_File fi if [ -z "$OptFS" ] then cat $Opt_Equation_File | sed -e 's/^s=0/s=s/' >> $Root_Equation_File echo "s=0" > $Opt_Equation_File fi # # bytes required in /var/sadm/... to save old, overwritten, files # echo "+`cat $KBYTESFILE`" >> $Var_Equation_File if [ -z "$VarFS" ] then cat $Var_Equation_File | sed -e 's/^s=0/s=s/' >> $Root_Equation_File echo "s=0" > $Var_Equation_File fi for Equ in $Root_Equation_File $Var_Equation_File $Opt_Equation_File $Usr_Equation_File $Openwin_Equation_File do echo "\ns/1000" >> $Equ done Root_Kbytes_Needed=`bc < $Root_Equation_File` Var_Kbytes_Needed=`bc < $Var_Equation_File` Opt_Kbytes_Needed=`bc < $Opt_Equation_File` Usr_Kbytes_Needed=`bc < $Usr_Equation_File` Openwin_Kbytes_Needed=`bc < $Openwin_Equation_File` rm -f $Root_Equation_File $Var_Equation_File $Opt_Equation_File rm -f $Usr_Equation_File $Openwin_Equation_File } # 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: # pkglist gen_uninstalled_pkgs() { pkg= for i in $pkglist; do if myshowrev $1 | grep "^Patch:[ ]*$3" | \ grep -s $i > /dev/null 2>&1 ; then continue else pkg="$pkg $i" fi done if [ "$pkg" = "" ]; then echo "Patch $3 has already been applied. See README file for\\c" echo " instructions.\nInstallpatch is terminating." rm -f /tmp/*.$$ exit 2 else echo "Re-installing patch $3..." echo "" >> $2/$3/log echo "Re-installing Patch." >> $2/$3/log fi pkglist="$pkg" } # Description: # Check to see if the patch is obsoleted by an earlier patch # Parameters: # none # Globals used: # PKGDB # patchbase # patchrev # Globals set: # isapplied check_if_obsolete() { currentdir=`pwd` # # 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 $PKGDB oldRevs=`grep "SUNW_PATCHID=$patchbase" ./*/pkginfo | \ sed 's/^.*-\([0-9][0-9]\).*$/\1/' | sort -u` if [ "$oldRevs" != "" ]; then oldRevs=`echo $oldRevs | sort -u` for ii in $oldRevs X; do if [ "$ii" = "X" ]; then break; fi if [ "$ii" = "$patchrev" ]; then isapplied="yes" continue elif [ "$ii" -gt "$patchrev" ]; then print_obsolete_msg "$patchbase-$ii" exit 6 fi done fi # # Now search for patches that specifically obsolete the current # patch. Ignore if the patchpase of the obsoletor is the same # as the obsoletee. # if myshowrev $PKGDB | grep -v "Patch: $patchbase" | \ grep -s "Obsoletes:.*$patchbase.*Packages:" > /dev/null 2>&1; then print_obsolete_msg myshowrev $PKGDB | \ grep -v "Patch: $patchbase" | \ grep "Obsoletes:.*$patchbase.*Packages:" exit 6 fi cd $currentdir } # Description: # CURRENTLY DISABLED # Parameters: # none check_if_server() { echo > /dev/null # if grep -s "SPOOLED_ROOT" $SOFTINFO/$prodver > /dev/null 2>&1 # then # is_server="yes" # fi } # 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 # check_for_symbolic_link() { rm -f /tmp/symlink.$$ > /dev/null 2>&1 olddir=`pwd` cd $patchdir for ii in * X; do if [ "$ii" = X ]; then break fi if [ ! -d "$ii" ]; then continue fi # # Comment out ignoring symbolic links for packages with no current # instance. New packages will not be added using installpatch. # # grep -s "VERSION=.*PATCH=" $1/$2/$ii/pkginfo # if [ $? != 0 ]; then # continue # fi symlinks= symlinks=`sed -n '/^[^ ]*[ ]*s[ ]/p' $1/$2/$ii/pkgmap` if [ "$symlinks" != "" ]; then echo "Symbolic link in package $ii" >> /tmp/symlink.$$ fi done if [ -s /tmp/symlink.$$ ]; then echo cat /tmp/symlink.$$ echo echo "Symbolic links can't be part of a patch." echo "Installpatch is terminating." rm -f /tmp/*.$$ exit 13 fi cd $olddir } # 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 Use: # pkglist check_pkgs_installed() { i= j= pkginst= finalpkglist= minver= Pkgpatchver= Pkgarch= Pkgabbrev= Pkgver= Pkgtype= OrigPkgver= # # 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; do # # Get the package abbreviation from the pkginfo file. # Pkgabbrev=`sed -n 's/^[ ]*PKG[ ]*=[ ]*\([^ ]*\)[ ]*$/\1/p' $i/pkginfo` # # Get the package architecture from the pkginfo file. # Pkgarch=`sed -n 's/^[ ]*ARCH[ ]*=[ ]*\([^ ]*\)[ ]*$/\1/p' $i/pkginfo` # # Get the package version number. # Pkgver=`sed -n \ -e 's/^[ ]*VERSION[ ]*=[ ]*\([^ ]*\)\.[0-9][0-9]*[ ]*$/\1/p' \ -e 's/^[ ]*VERSION[ ]*=[ ]*\([^ ]*\),PATCH=.*$/\1/p' $i/pkginfo ` minver=`expr $Pkgver : '\(.*\)\.0$'` while [ "$minver" != "" ] ; do Pkgver=$minver minver=`expr $Pkgver : '\(.*\)\.0$'` done Pkgpatchver=`sed -n 's/^[ ]*VERSION[ ]*=[ ]*\([^ ]*\)[^ ]*$/\1/p' $i/pkginfo` Pkgtype=`sed -n 's/^[ ]*SUNW_PKGTYPE[ ]*=[ ]*\([^ ]*\)[ ]*$/\1/p' $i/pkginfo` if [ "$Pkgtype" = "root" ] ; then is_a_root_pkg=yes fi # # Determine if this is a new package to be installed. If so, # add the package to the final package list and force it to # be pkgadd`ed even if there is no current instance. # # This capability is commented out. New packages are not to # be installed by installpatch. # # newpkg="yes" # if grep -s "VERSION=.*PATCH=" $2/$i/pkginfo > /dev/null 2>&1 # then # newpkg="no" # fi # if [ "$newpkg" = "yes" ]; then # finalpkglist="$finalpkglist $i,NO_CURRENT_INSTANCE" # continue; # fi # echo "" for j in $1/$Pkgabbrev X; do if [ "$j" = "X" ]; then break fi if [ ! -d "$j" ] && \ [ ! -d "$j.*" ]; then echo "Package not patched:" >> $LOGFILE echo "PKG=$Pkgabbrev" >> $LOGFILE echo "Original package not installed" >> $LOGFILE fi done for j in $1/$Pkgabbrev $1/$Pkgabbrev.* X; do if [ "$j" = "X" ] ; then break fi if [ ! -d $j ] ; then continue; fi OrigPkgver=`sed -n 's/^VERSION=\(.*\)$/\1/p' $j/pkginfo` minver=`expr $OrigPkgver : '\(.*\)\.0$'` while [ "$minver" != "" ] ; do OrigPkgver=$minver minver=`expr $OrigPkgver : '\(.*\)\.0$'` done if grep -s "^PKG=$Pkgabbrev$" $j/pkginfo >/dev/null 2>&1 \ && grep -s "^ARCH=$Pkgarch$" $j/pkginfo >/dev/null 2>&1 \ && [ "$OrigPkgver" = "$Pkgver" ] ; then pkginst=`basename $j` finalpkglist="$finalpkglist $i,$pkginst" break; else echo "Package not patched:" >> $LOGFILE echo "PKG=$Pkgabbrev" >> $LOGFILE echo "ARCH=$Pkgarch" >> $LOGFILE echo "VERSION=$OrigPkgver" >> $LOGFILE tmp="" tmp=`grep "^ARCH=$Pkgarch$" $j/pkginfo 2>/dev/null` if [ "$tmp" = "" ]; then echo "Architecture mismatch" >> $LOGFILE fi if [ "$OrigPkgver" != "$Pkgver" ] ; then echo "Version mismatch" >> $LOGFILE fi echo "" >> $LOGFILE fi done # # If j is X, matching package instance was never found. If # in force mode, add package to list anyway. # if [ "$j" = "X"]; then # if [ "$force" = "yes" ] ; then # finalpkglist="$finalpkglist $i,NO_CURRENT_INSTANCE" # fi # fi # if [ "$is_server" = "yes" ]; then # if [ "$Pkgarch" = "sparc" ]; then # Pkgarch="sparc.all" # fi # org_template=$Pkgabbrev"_"$Pkgver"_"$Pkgarch # if grep "SPOOLED_ROOT=$Pkgarch:/export/root/templates/$prodver/$org_template" $SOFTINFO/$prodver >/dev/null 2>&1 # then # spoolsize=`/usr/bin/du -ks $i | sed 's/ .*//'` # rootlist="$rootlist $i,$Pkgabbrev"_"$Pkgpatchver"_"$Pkgarch",$spoolsize # fi # fi done pkglist=$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 # VALERRFILE check_validation() { if [ "$1" = "yes" -a -s $PKGCOFILE ]; then if grep -s ERROR $PKGCOFILE >/dev/null 2>&1 ; then echo "The following validation error was found: \n" cat $PKGCOFILE echo echo "See the README file for instructions regarding" echo "patch validation errors." echo "Installpatch is terminating." rm -f /tmp/*.$$ exit 10 fi fi if [ -s $VALWARNFILE ]; then cp $VALWARNFILE $VALERRFILE fi } # Description: # Create a spooling area in the sadm/patch/ 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: # VALERRFILE create_archive_area() { if [ ! -d $1/$2/save ] ; then echo "Creating patch archive area..." mkdir -p -m 750 $1/$2/save chown -h -f -R root $1/$2 chgrp -h -f -R sys $1/$2 fi if [ -s $VALERRFILE ] ; then cp $VALERRFILE $1/$2/.validation.errors fi } # Description: # Scan the patch package maps for a list of affected files. # Parameters: # $1 - package database directory # $2 - package relocation argument # Globals Used: # PKGCOFILE # PATCHFILES # pkglist gen_install_filelist() { pkgfiles=/tmp/pkgfiles.$$ resfiles=/tmp/resolvedfiles.$$ macrofiles=/tmp/pkgmacros.$$ pkginst= pkginfofile= patchpkg= basedir= i= rm -f $PATCHFILES echo "Generating list of files to be patched..." for i in $pkglist; do patchpkg=`expr $i : '\(.*\),.*'` pkginst=`expr $i : '.*,\(.*\)'` if [ "$pkginst" = "NO_CURRENT_INSTANCE" ] ; then # # Install a package to be patched if it isn't # currently installed???? # pkginfofile="$patchpkg/pkginfo" pkgmapfile="$patchpkg/pkgmap" else pkginfofile="$1/$pkginst/pkginfo" pkgmapfile="$1/$pkginst/pkgmap" fi # # parse out the base directory from the pkginfo file. First, # remove the BASEDIR keyword together with the = and any # whitespace. Then remove any / at the end of the line. # Finally, replace any /a partitions with / # basedir=`grep '^BASEDIR' $pkginfofile | \ sed -e 's@.*=\ *@@' -e 's@/$@@' -e 's@/a$@/@'` # # 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 (rm -f $macrofiles $resfiles cat $pkginfofile | while read i do echo `echo $i| sed -e 's/^\(.*\)=.*/\1/'`=\"`echo $i|sed -e 's/^\(.*\=\)//'`\" | grep -v '^PATH' >> $macrofiles done . $macrofiles cat $pkgfiles | while read i do eval /usr/bin/echo $i >> $resfiles done) # # Prepend the basedir to the file name if the file is # relocatable, then add it to the pkgfile list. # mv $resfiles $pkgfiles cat $pkgfiles | parse_sizes $patchpkg sed "s,^\([^/]\),$basedir/&," $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 ]; then cat $resfiles | while read j ; do jfile=`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" != "" ]; then if [ "$class" != "" -a "$class" != "preserve" -a ! -f $patchdir/$patchpkg/install/i.$class ]; then pkgchk $2 -p $jfile\ $patchpkg >> $PKGCOFILE 2>&1 fi echo $jfile >> $VALWARNFILE fi done fi sed 's/^\([^ ]*\).*/\1/' $resfiles >> $PATCHFILES fi done } # 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_Equation_File # Usr_Equation_File # Opt_Equation_File # Var_Equation_File # Root_Equation_File parse_sizes() { while read Filename junk do grep " $Filename " $1/pkgmap | while read part ftype f3 f4 f5 f6 f7 f8 Junk do case $ftype in f|e|v) pathname=$f4 size=$f8 case $pathname in usr\/openwin\/*|\/usr\/openwin\/*) echo "+${size}\\c" >> $Openwin_Equation_File ;; usr\/*|\/usr\/*) echo "+${size}\\c" >> $Usr_Equation_File ;; var\/*|\/var\/*) echo "+${size}\\c" >> $Var_Equation_File ;; opt\/*|\/opt\/*) echo "+${size}\\c" >> $Opt_Equation_File ;; *) echo "+${size}\\c" >> $Root_Equation_File ;; esac ;; i) echo "+${f4}\\c" >> $Var_Equation_File ;; d|l|s|p|b|c|x) pathname=$f4 case $pathname in usr\/openwin\/*|\/usr\/openwin\/*) echo "+512\\c" >> $Openwin_Equation_File ;; usr\/*|\/usr\/*) echo "+512\\c" >> $Usr_Equation_File ;; var\/*|\/var\/*) echo "+512\\c" >> $Var_Equation_File ;; opt\/*|\/opt\/*) echo "+512\\c" >> $Opt_Equation_File ;; *) echo "+512\\c" >> $Root_Equation_File ;; esac ;; *) ;; esac done 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 # KBYTESFILE gen_patch_filelist() { tmp_total=0 size= kbytes_total=0 kb=0 if [ -s $PATCHFILES ] ; then cat $PATCHFILES | (while read j do if ls -d $ROOTDIR$j >/dev/null 2>&1 then echo "."$j >> $EXISTFILES size=`wc -c $ROOTDIR$j` size=`echo $size | sed 's/\ .*//'` if [ "$size" != "" ]; then tmp_total=`expr $tmp_total + $size` fi if [ $tmp_total -ge 1024 ]; then kb=`expr $tmp_total / 1024` tmp_total=`expr $tmp_total - $kb \* 1024 ` kbytes_total=`expr $kbytes_total + $kb` fi fi done; if [ "$tmp_total" != "" ]; then kbytes_total=`expr $kbytes_total + 1` fi echo $kbytes_total > $KBYTESFILE) else rm -f $EXISTFILES fi } # Description: # Assemble a list of the package package IDs contained in the patch # (at least one diretory with a pkginfo file must exist due to checks # in activate_patch) # Parameters: # none # Globals Set: # pkglist gen_patchpkg_list() { pkg= for i in */pkginfo X; do if [ "$i" = "X" ]; then break fi pkg=`expr $i : '\(.*\)/pkginfo'` pkglist="$pkglist $pkg" done } # Description: # Get the product version _ of local Solaris installation # Parameters: # $1 - softinfo directory path # Globals Set: # prodver get_os_version() { if [ ! -f ${1}/INST_RELEASE ] then echo "$0 is unable to find the INST_RELEASE file. This file" echo "must be present for $0 to function correctly." exit 11 fi Product= Instver= Product=`sed -n 's/^OS=\(.*\)/\1/p' $1/INST_RELEASE` Instver=`sed -n 's/^VERSION=\(.*\)/\1/p' $1/INST_RELEASE` prodver=$Product"_"$Instver } # 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 install_patch_pkgs() { i= ij= pkginst= pkginfofile= pkgadderr= patchpkg= basedir= # # 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 ]; then cat $LOGFILE >> $1/$2/log rm -f $LOGFILE fi move_libraries echo "Installing patch packages..." for ij in $pkglist; do i=`expr $ij : '\(.*\),.*'` pkginst=`expr $ij : '.*,\(.*\)'` if [ "$pkginst" = "NO_CURRENT_INSTANCE" ] ; then pkginfofile="$3/$i/pkginfo" else pkginfofile="$5/$pkginst/pkginfo" fi basedir=`grep '^BASEDIR' $pkginfofile | sed -e 's@.*=\ *@@' -e 's@/a/@/@' -e 's@/a$@/@'` if [ ! -d $1/$2/$i ] then mkdir -m 750 $1/$2/$i fi cp $i/pkgmap $1/$2/$i/pkgmap cp $i/pkginfo $1/$2/$i/pkginfo cp $ADMINTFILE $ADMINFILE echo basedir=$basedir >>$ADMINFILE echo "\nDoing pkgadd of $i package:" pkgadd $4 -S -a $ADMINFILE -n -d $3 $i >$LOGFILE 2>&1 pkgadderr=$? real_pkgadderr_2=0 if [ $pkgadderr = 2 ] then if grep '^ERROR' $LOGFILE >/dev/null 2>&1 then real_pkgadderr_2=1 fi fi cat $LOGFILE >> $1/$2/log cat $LOGFILE | grep -v "^$" rm -f $LOGFILE if [ $pkgadderr != 0 -a $real_pkgadderr_2 != 0 -a \ $pkgadderr != 10 -a $pkgadderr != 20 ]; then echo "Pkgadd of $i package failed with error code $pkgadderr." |tee -a $1/$2/log if [ "$isapplied" = "no" ]; then echo "See /tmp/log.$2 for reason for failure." cp $1/$2/log /tmp/log.$2 echo "Backing out patch:" cd $3 if [ "$ROOTDIR" != "/" ]; then ./backoutpatch $PKGDBARG $2 else ./backoutpatch $2 fi else echo "See $1/$2/log for reason for failure." echo "Will not backout patch...patch re-installation." echo "Warning: The system may be in an unstable state!" fi echo "Installpatch is terminating." rm -fr /tmp/*.$$ remove_libraries exit 5 fi done remove_libraries } # Description: # Make internal variables available to child processes # of installpatch. This is done by writing them to a # file and by exporting them. # Parameters: # none # Environment Variables Set: # none # make_params_available() { echo "saveold=$saveold" > $PARAMS_FILE echo "validate=$validate" >> $PARAMS_FILE echo "patchdir=$patchdir" >> $PARAMS_FILE echo "patchnum=$patchnum" >> $PARAMS_FILE echo "patchbase=$patchbase" >> $PARAMS_FILE echo "patchrev=$patchrev" >> $PARAMS_FILE echo "ROOTDIR=$ROOTDIR" >> $PARAMS_FILE echo "PATCHDB=$PATCHDB" >> $PARAMS_FILE echo "PKGDB=$PKGDB" >> $PARAMS_FILE echo "SOFTINFO=$SOFTINFO" >> $PARAMS_FILE echo "PKGDBARG=$PKGDBARG" >> $PARAMS_FILE export saveold validate patchdir patchnum patchbase patchrev export PARAMS_FILE ROOTDIR PATCHDB PKGDB SOFTINFO PKGDBARG } # Description: # Copy required libraries to TMP_LIB_DIR, set and # export LD_PRELOAD. # Parameters: # none # Environment Variables Set: # LD_PRELOAD # move_libraries() { Rev=`echo $Instver | sed -e 's/[0-9]\.//'` if [ "$Rev" -ge "5" ] then if [ ! -d $TMP_LIB_DIR ] then mkdir -p -m755 $TMP_LIB_DIR fi LD_PRELOAD= for Lib in libc libdl libelf libintl libw libadm do cp /usr/lib/${Lib}.so.1 ${TMP_LIB_DIR}/${Lib}.so.1 chown bin ${TMP_LIB_DIR}/${Lib}.so.1 chgrp bin ${TMP_LIB_DIR}/${Lib}.so.1 chmod 755 ${TMP_LIB_DIR}/${Lib}.so.1 LD_PRELOAD="${LD_PRELOAD} ${TMP_LIB_DIR}/${Lib}.so.1" done export LD_PRELOAD fi } # Description: # Parse the arguments and set all affected global variables # Parameters: # Argument list passed into installpatch # Globals Set: # validate # saveold # force # printpatches # patchdir # ROOTDIR # PATCHDB # PKGDB # SOFTINFO # PKGDBARG # Globals Used: # prodver # SOFTINFO # PKGDB # PATCHDB parse_args() { service_specified="n" rootdir_specified="n" while [ "$1" != "" ] do case $1 in -u) validate="no"; shift;; -d) saveold="no"; shift;; -p) printpatches="yes"; shift;; -S) shift if [ "$rootdir_specified" = "y" ]; then echo "The -S and -R arguments are mutually exclusive." print_usage exit 1 fi get_os_version $SOFTINFO if [ "$1" != "$prodver" ]; then if [ -d "/export/$1$PKGDB" ]; then ROOTDIR=/export/$1 PATCHDB=$ROOTDIR$PATCHDB PKGDB=$ROOTDIR$PKGDB SOFTINFO=$ROOTDIR$SOFTINFO PKGDBARG="-R $ROOTDIR" service_specified="y" else echo "The $1 service cannot be found on this system." print_usage exit 1 fi fi shift;; -V) echo "@(#) installpatch 4.15 95/08/09" exit 0;; -R) shift if [ "$service_specified" = "y" ]; then echo "The -S and -R arguments are mutually exclusive." print_usage exit 1 fi if [ ! -d "$1" ]; then echo "The Package Install Root directory $1 cannot be found on this system." print_usage exit 1 else ROOTDIR=$1 PATCHDB=$ROOTDIR$PATCHDB PKGDB=$ROOTDIR$PKGDB SOFTINFO=$ROOTDIR$SOFTINFO PKGDBARG="-R $ROOTDIR" rootdir_specified="y" fi shift;; -*) print_usage; exit 1;; *) break;; esac done if [ "$printpatches" = "yes" ]; then myshowrev $PKGDB exit 0 fi if [ "$1" = "" ]; then echo "No patch directory specified." print_usage exit 1 fi if [ ! -d $1 ]; then echo "Patch directory '$1' does not exist." print_usage exit 1 fi # # Derive the full path name from a (possibly) relative path name. # olddir=`pwd` cd $1 patchdir=`pwd` cd $olddir echo "@(#) installpatch 4.15 95/08/09 SMI" } # Description: # Scan all pkginfo files for installed packages for a PATCH # identifier string and print out the associated package info # Parameters: # $1 - patch database directory # Description: # Print the patch obsolecensce message # Parameters: # $1 - number of patch which obsoleted this patch print_obsolete_msg() { echo "This patch is obsoleted by patch $1 which has already" echo "been applied to this system. Patch installation is aborted." } # Description: # Print the list of patch packages which were applied, and those # which were not. # Parameters: # none # Globals Used: # pkglist print_results() { i= p= echo "\nPatch packages installed:" if [ -s "$pkglist" ]; then echo " none" else for i in $pkglist; do p=`expr $i : '\(.*\),.*'` echo " $p" done fi } # Description: # remove the TMP_LIB_DIR directory # Parameters: # none # Environment Variables Set: # LD_PRELOAD # remove_libraries() { LD_PRELOAD= export LD_PRELOAD rm -rf $TMP_LIB_DIR } # 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 # KBYTESFILE save_overwritten_files() { olddir= kbytes_avail= kbytes_required= bytes= if [ ! -s $EXISTFILES ] ; then touch $1/$2/.nofilestosave elif [ "$4" = "yes" ]; then echo "Saving a copy of existing files to be patched..." # 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 -k $1 | tail -1 | \ sed 's/^[^ ]*[ ]*[^ ]*[ ]*[^ ]*[ ]*\([^ ]*\).*/\1/'` bytes=`cat $KBYTESFILE` kbytes_required=`expr $bytes` if [ $kbytes_required -gt $kbytes_avail ]; then echo "Insufficient space in $1 to save old files." echo "Space required in kilobytes: $kbytes_required" echo "Space available in kilobytes: $kbytes_avail" if [ "$isapplied" = no ]; then cd $3 if [ "$ROOTDIR" != "/" ]; then ./backoutpatch $PKGDBARG $2 else ./backoutpatch $2 fi rm -fr $1/$2 fi rm -f /tmp/*.$$ exit 4 fi cd $ROOTDIR if [ "$isapplied" = "no" ]; then cpio -oL -O $1/$2/save/archive.cpio <$EXISTFILES exit_code=$? else if [ ! -d $TMP_ARCHIVE ] then mkdir $TMP_ARCHIVE fi cd $TMP_ARCHIVE if [ -f $1/$2/save/archive.cpio.Z ] then zcat $1/$2/save/archive.cpio.Z | cpio -idum else cpio -idum -I $1/$2/save/archive.cpio fi find . -print > $TMP_FILELIST cd $ROOTDIR cpio -oL -O /tmp/archive.cpio < $EXISTFILES >/dev/null 2>&1 exit_code=$? cd $TMP_ARCHIVE cpio -oAL -O /tmp/archive.cpio < $TMP_FILELIST >/dev/null 2>&1 exit_code=`expr $exit_code + $?` cd $ROOTDIR rm -rf $TMP_ARCHIVE/* $TMP_FILELIST rmdir $TMP_ARCHIVE fi if [ $exit_code != 0 ]; then echo "Save of old files failed. \c" echo "See README file for instructions." if [ "$isapplied" = "no" ]; then cd $3 if [ "$ROOTDIR" != "/" ]; then ./backoutpatch $PKGDBARG $2 else ./backoutpatch $2 fi rm -fr $1/$2 fi echo "Installpatch is terminating." rm -f /tmp/*.$$ exit 4 fi if [ -x /usr/bin/compress ]; then if [ "$isapplied" = "no" ]; then compress $1/$2/save/archive.cpio else compress /tmp/archive.cpio fi if [ $? = 0 ]; then echo " File compression used" else echo " No file compression used." fi else echo " No file compression used." fi if [ "$isapplied" = "yes" ]; then cp /tmp/archive.cpio* $1/$2/save fi chmod 600 $1/$2/save/archive.cpio* touch $1/$2/.oldfilessaved fi cd $3 } # Description: # Finish up the patch # Parameters: # $1 - patch database directory # $2 - patch number set_patch_status() { mv -f /tmp/ACTION.$patchnum $1/$2 >/dev/null 2>&1 cp -p README.$2 backoutpatch $1/$2 >/dev/null 2>&1 cp -p prebackout postbackout $1/$2 > /dev/null 2>&1 rm -f $MYSHOWREV_FILE rm -f /tmp/*.$$ rm -f /tmp/archive.cpio* } # Description: # Spool a copy of the patch into the client root template area # NOT IMPLEMENTED AT THIS TIME # Parameters: # none spool_client_patch() { echo > /dev/null # if [ "$is_server" = "yes" ] # then # echo "Spooling patch packages to root templates for future clients" # echo "[NOTE: existing clients will need patches applied individually]" # for i in $rootlist; do # patchpkg=`expr $i : '\([^,]*\),.*'` # spoolloc=`expr $i : '[^,]*,\([^,]*\),.*'` # spoolsize=`expr $i : '[^,]*,[^,]*,\(.*\)'` # arch=`expr $spoolloc : '[^_]*_[^_]*_\(.*\)'` # ver=`expr $spoolloc : '[^_]*_\([^_]*\)_.*'` # abbrev=`expr $spoolloc : '\([^_]*\)_.*'` # echo $patchpkg $spoolloc $spoolsize $arch $ver $abbrev # # if [ ! -d /export/root/templates/$prodver/$spoolloc ]; then # mkdir -m 750 -p /export/root/templates/$prodver/$spoolloc # fi # find $patchpkg -print | cpio -pd /export/root/templates/$prodver/$spoolloc # if [ $? != 0 ]; then # echo "Error while adding patch to root template." # echo "See README file for instructions." # rm -fr /export/root/templates/$prodver/$spoolloc # cd $patchdir # ./backoutpatch -s $patchnum # echo "Installpatch is terminating." # rm -fr $PATCHDB/$patchnum # rm -f /tmp/*.$$ # exit 11 # fi # # echo SPOOLED_ROOT=$arch":"/export/root/templates/$prodver/$spoolloc >> $SOFTINFO/$prodver # echo ROOT=$arch:$abbrev,$spoolsize,$ver >> $SOFTINFO/$prodver # echo /SPOOLED_ROOT=$arch":".export.root.templates.$prodver.$spoolloc/d >> $PATCHDB/$patchnum/softinfo_sed # echo /ROOT=$arch:$abbrev,$spoolsize,$ver/d >> $PATCHDB/$patchnum/softinfo_sed # echo "/export/root/templates/$prodver/$spoolloc" >> $PATCHDB/$patchnum/spooled_dirs # done # fi } # Description: # Parameters: # $1 - patch database directory # $2 - patch number # $3 - patch directory trap_backoutsaved() { echo "Interrupt signal detected." if [ "$isapplied" = "no" ]; then echo "Backing out patch:" cd $3 if [ "$ROOTDIR" != "/" ]; then ./backoutpatch $PKGDBARG $2 else ./backoutpatch $2 fi rm -fr $1/$2 else cp /tmp/archive.cpio* $1/$2/save rm -f /tmp/archive.cpio* echo "Installpatch Interrupted." >> $1/$2/log fi echo "Installpatch is terminating." rm -f /tmp/*.$$ rm -f $MYSHOWREV_FILE remove_libraries exit 12 } # Description: # Parameters: # $1 - patch directory # $2 - patch number trap_backout() { echo "Interrupt signal detected." echo "Backing out Patch:" cd $1 if [ "$ROOTDIR" != "/" ]; then ./backoutpatch $PKGDBARG $2 else ./backoutpatch $2 fi if [ "$isapplied" = "yes" ]; then rm -f /tmp/archive.cpio* fi echo "Installpatch is terminating." rm -f /tmp/*.$$ rm -f $MYSHOWREV_FILE remove_libraries exit 12 } # Description: # Parameters: # $1 - patch database directory # $2 - patch number trap_notinstalled() { echo "Interrupt signal detected. Patch not installed." echo "Installpatch is terminating." rm -f /tmp/*.$$ rm -f $MYSHOWREV_FILE if [ "$isapplied" = "no" ]; then rm -fr $1/$2 else echo "Install Interrupted." >> $1/$2/log fi exit 12 } # Description: # Make sure effective UID is '0' # Parameters: # none validate_uid() { uid=`id | sed 's/uid=\([0-9]*\)(.*/\1/'` if [ "$uid" != "0" ] ; then echo "You must be root to execute this script." exit 3 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 verify_client() { pkginfo -q SUNWcsu if [ $? != 0 ]; then client=yes sum /usr/sbin/pkgadd > /dev/null 2>&1 if [ $? != 0 ]; then echo "The /usr/sbin/pkgadd command is not executable." echo "See the README file for instructions for making this" echo "command executable." exit 9 fi fi } ############################################ # Main Routine # ############################################ # # - Get the product 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' # echo Cmd=$0 parse_args $* validate_uid get_os_version "$SOFTINFO" # # Change to the patch directory and set globals according to the patchID # found in the pkginfo files of the patch packages # rm -f $MYSHOWREV_FILE activate_patch "$patchdir" # # - Check to see if patch has already been applied, and exit if already # applied successfully # - Check whether patch has been obsoleted by a prior patch # - Determine if system being patch is a client, and make sure pkgadd # is usable servers must export to clients for read-only root access) # - Determine if system being patched is a server (CURRENTLY DISABLED) # # - Make sure the patch doesn`t contain any symbolic links. If it does, # print out an error. Sustaining engineering will need to re-engineer # the patch to replace a symbolic link in one of the pre or post install # scripts. # check_if_applied "$PATCHDB" "$patchnum" # # prev | curr | .nofilestosave | Is it 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. NON empty save directory # -------+------+----------------+-------------+----------------------------- # | | yes | continue | a. empty save directory # 2. yes | no |----------------+-------------+----------------------------- # | | no | terminate | b. NON empty save directory # -------+------+----------------+-------------+----------------------------- # 3. no | no | no | continue | empty save directory # -------+------+----------------+-------------+----------------------------- # 4. no | yes | no | terminate | empty save directory # -------+------+----------------+-------------+----------------------------- # if [ "$isapplied" = "yes" ] then if [ "$saveold" = "no" ] then if [ ! -f "${PATCHDB}/${patchnum}/.nofilestosave" -a \ \( -f "${PATCHDB}/${patchnum}/save/archive.cpio" -o \ -f "${PATCHDB}/${patchnum}/save/archive.cpio.Z" \) ] then # condition #2b - terminate echo "A previous installation of patch $patchnum was invoked" echo "that saved files that were to be patched. Since files" echo "were saved, you must run this instance of installpatch" echo "without the -d option." exit 17 elif [ -f "${PATCHDB}/${patchnum}/.nofilestosave" -a \ ! -f "${PATCHDB}/${patchnum}/save/archive.cpio" -a \ ! -f "${PATCHDB}/${patchnum}/save/archive.cpio.Z" ] then # condition #2a - rm .nofilestosave rm ${PATCHDB}/${patchnum}/.nofilestosave fi else if [ ! -f "${PATCHDB}/${patchnum}/.nofilestosave" -a \ ! -f "${PATCHDB}/${patchnum}/save/archive.cpio" -a \ ! -f "${PATCHDB}/${patchnum}/save/archive.cpio.Z" ] then # condition #4 - terminate echo "A previous installation of patch $patchnum was invoked" echo "with the -d option. (i.e. Do not save files that would" echo "be patched) Therefore, this invocation of installpatch" echo "must also be run with the -d option." exit 17 fi fi fi check_if_obsolete "$PATCHDB" verify_client check_if_server check_for_symbolic_link "$patchdir" trap 'trap_notinstalled "$PATCHDB" "$patchnum"' 1 2 3 15 make_params_available # # If there is a prepatch file in the $patchdir directory, # execute it. If the return code is not 0, exit installpatch # with an error. # Don't re-execute a prepatch script if this is a re-installation # if [ "$isapplied" = "no" ]; then execute_prepatch "$patchdir" fi # - Generate list of patch packages to be installed # - Find out those packages which are already installed on # the system # - Check to see if there is any work to do # - Generate list of files to be installed # - Check for validation errors # - Generate a list of files to be patched that already exist # - Create patch archive and save area gen_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" ]; then gen_uninstalled_pkgs $PKGDB $PATCHDB $patchnum fi check_pkgs_installed "$PKGDB" "$patchdir" check_for_action "$client" "$is_a_root_pkg" echo "s=0\\c" > $Root_Equation_File echo "s=0\\c" > $Var_Equation_File echo "s=0\\c" > $Opt_Equation_File echo "s=0\\c" > $Usr_Equation_File echo "s=0\\c" > $Openwin_Equation_File gen_install_filelist "$PKGDB" "$PKGDBARG" check_validation "$validate" gen_patch_filelist compute_fs_space_requirements check_fs_space create_archive_area "$PATCHDB" "$patchnum" trap '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 pkgadd save_overwritten_files "$PATCHDB" "$patchnum" "$patchdir" "$saveold" spool_client_patch build_admin_file trap 'trap_backout "$patchdir" "$patchnum"' 1 2 3 15 # - Install the patch packages # - Print results of install # - Save ACTION file if exists, README file and backoutpatch # script install_patch_pkgs "$PATCHDB" "$patchnum" "$patchdir" "$PKGDBARG" "$PKGDB" execute_postpatch "$PATCHDB" "$patchnum" "$patchdir" print_results set_patch_status "$PATCHDB" "$patchnum" echo "\nPatch installation completed." echo "See $PATCHDB/$patchnum/log for more details." exit 0