#!/usr/bin/ksh
#
# @(#) installpatchset 1.10@(#)
#
# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
#
# Script to install Solaris 10 patch sets
#
########################################################################


# patch set script exit codes :
# 0 application of patch set completed nominally
# 1 failure 
# 2 end of phase
# 3 terminated by interrupt signal


# Fix for BugDB 16202177 is to set PATH to exlcude /usr/ucb
# before running [typeset -r chtab=`echo "\t"`] line below.
#
# With /usr/ucb early in the PATH, this installer fails with:
# ERROR: Zone verification failed : unable to determine absolute path
#     of scratch zone for zone '<zonename>'.
PATH=/usr/sbin:/sbin:/usr/bin


# verify execution context
#  - interpreter is ksh
#  - script is being executed (ie. not sourced)
#  - get out ksh readonly variable jail if necessary
[ -x /usr/bin/pargs -a -x /usr/bin/egrep -a -x /usr/bin/env ] || {
    echo "ERROR: Unable verify execution context."
    return 1 2> /dev/null
    exit 1
}
/usr/bin/pargs -l $$ 2> /dev/null | /usr/bin/egrep "^/usr/bin/(k|pfk|rk)sh" > /dev/null || {
    echo "ERROR: Unrecognised script interpreter."
    return 1 2> /dev/null
    exit 1
}
( exit $(( LINENO % 256 )) )
[ $? = $(( LINENO % 256 )) ] && {
    echo "ERROR: This script cannot be sourced, it must be executed."
    return 1
}
/usr/bin/env | /usr/bin/egrep "^A__z=." > /dev/null && {
    unset MAILCHECK OPTIND PPID TMOUT
    exec /usr/bin/env A__z= "$0" "$@"
}

unset patchset_config_file abort_log_lock abort_forced_flag end_of_phase_lock single_instance_lock_base prereq_patch_order_file processed_patch_order_file fs_temp_mount_point chtab chnl
unset AWK CAT DATE DF DU EGREP GREP ID KSH MKDIR MOUNT PATCHADD PR PRINTF RM RMDIR SED SETPGRP SLEEP SORT SWAP TAIL TEE TOUCH TR UMOUNT UNAME ZONENAME REQCMDS
unset ZFS ZONEADM ZONECFG LUMOUNT LUSTATUS LUUMOUNT PSTAT_STD_fail PSTAT_STD_pass PSTAT_STD_skip PSTAT_VRB_fail PSTAT_VRB_pass PSTAT_VRB_skip orig_LC_ALL

# fixed parameters
typeset -r patchset_config_file=patchset.conf
typeset -r current_installed_version_file="/var/sadm/install_data/rec_patchset_version"
typeset -r current_installed_version_file_version="1.0"
typeset -r abort_log_lock=/var/run/.patchset.abort.log.lock.$$
typeset -r abort_forced_flag=/var/run/.patchset.abort.forced.flag.$$
typeset -r end_of_phase_lock=/var/run/.patchset.end.of.phase.lock
typeset -r single_instance_lock_base=/var/run/.patchset.single.instance.lock
typeset -r prereq_patch_order_file=/var/run/.patchset.prereq.patch.order.$$
typeset -r processed_patch_order_file=/var/run/.patchset.processed.patch.order.$$
typeset -r fs_temp_mount_point=/var/run/.patchset.fs.temp.mount.$$
typeset -r chtab=`echo "\t"`
typeset -r chnl="
"

# absolute command paths
typeset -r AWK=/usr/bin/awk
typeset -r CAT=/usr/bin/cat
typeset -r DATE=/usr/bin/date
typeset -r DF=/usr/bin/df
typeset -r DU=/usr/bin/du
typeset -r EGREP=/usr/bin/egrep
typeset -r GREP=/usr/bin/grep
typeset -r ID=/usr/bin/id
typeset -r KSH=/usr/bin/ksh
typeset -r MKDIR=/usr/bin/mkdir
typeset -r MOUNT=/usr/sbin/mount
typeset -r PATCHADD=/usr/sbin/patchadd
typeset -r PR=/usr/bin/pr
typeset -r PRINTF=/usr/bin/printf
typeset -r RM=/usr/bin/rm
typeset -r RMDIR=/usr/bin/rmdir
typeset -r SED=/usr/bin/sed
typeset -r SETPGRP=/usr/bin/setpgrp
typeset -r SLEEP=/usr/bin/sleep
typeset -r SORT=/usr/bin/sort
typeset -r SWAP=/usr/sbin/swap
typeset -r TAIL=/usr/bin/tail
typeset -r TEE=/usr/bin/tee
typeset -r TOUCH=/usr/bin/touch
typeset -r TR=/usr/bin/tr
typeset -r UMOUNT=/usr/sbin/umount
typeset -r UNAME=/usr/bin/uname
typeset -r ZONENAME=/sbin/zonename

# required commands
typeset -r REQCMDS="$AWK $CAT $DATE $DF $DU $EGREP $GREP $ID $KSH $MKDIR $MOUNT $PATCHADD $PR $PRINTF $RM $RMDIR $SED $SETPGRP $SLEEP $SORT $SWAP $TAIL $TEE $TOUCH $TR $UMOUNT $UNAME $ZONENAME"

# zfs commands - only required on systems using zfs
typeset -r ZFS=/usr/sbin/zfs

# zone commands - only required on systems with zones
typeset -r ZONEADM=/usr/sbin/zoneadm
typeset -r ZONECFG=/usr/sbin/zonecfg

# LU commands - only required when LU target is selected
typeset -r LUMOUNT=/usr/sbin/lumount
typeset -r LUSTATUS=/usr/sbin/lustatus
typeset -r LUUMOUNT=/usr/sbin/luumount

# messaging eval LUT
typeset -r PSTAT_STD_fail=failed
typeset -r PSTAT_STD_pass=success
typeset -r PSTAT_STD_skip=skipped
typeset -r PSTAT_VRB_fail=failed
typeset -r PSTAT_VRB_pass=successful
typeset -r PSTAT_VRB_skip=skipped

# s10 container kernel levels
sparc_dap_ku="142909-17 144500-19"
x86_dap_ku="142910-17 144501-19"

init_global_vars () {
    ROOTDIR=
    abort=
    abort_forced=
    abort_interrupt_count=
    alt_root_install=
    dots_pid=
    dummy_zone_name=
    exit_code=
    fs_install_list=
    fs_install_undo_list=
    global_status=
    ku_baseid=
    ku_rev=
    ku_vers=
    log_files_active=
    lu_be=
    lu_restore_state=
    next_reboot_ku=
    operative_patch_order_file=
    patch_source_dir=
    patchadd_default_opts=
    patchadd_opt_nosave=
    patchadd_subproc_tmp_log_file=
    patchadd_tmp_log_file=
    patches_applied_list=
    patches_failed_list=
    patches_skipped_list=
    patches_skipped_alreadyapplied_list=
    patches_skipped_missingreq_list=
    patches_skipped_notapplicable_list=
    patches_skipped_obsoleted_list=
    patches_skipped_prepatch_list=
    patchset_arch=
    patchset_patchutils_rev=
    passcode=
    prepatch_termination_filter=
    prereq_action=
    retain_patchadd_tmp_log_file=
    running_from_miniroot=
    script_dir=
    script_name=
    single_instance_lock=
    skip_space_check=
    system_patchutils_rev=
    system_arch=
    s10_container=
    target=
    target_arch=
    wait_interrupted=
    zone_list=
    zone_restore_state=
    zone_restore_state_list=
    zone_support_level=
    recpatchset=
    proposed_recpatchset=
}


log_all () {
    # targets : standard log file, verbose log file, stdout
    eval_msg_format=$1
    shift
    if [ "$log_files_active" = true ] ; then
        $PRINTF "$eval_msg_format" "$@" | $TEE -a "$short_log_file" "$verbose_log_file"
    else
        $PRINTF "$eval_msg_format" "$@"
    fi
}

log_standard () {
    # targets : standard log file, stdout
    eval_msg_format=$1
    shift
    if [ "$log_files_active" = true ] ; then
        $PRINTF "$eval_msg_format" "$@" | $TEE -a "$short_log_file"
    else
        $PRINTF "$eval_msg_format" "$@"
    fi
}

log_verbose () {
    # targets : verbose log file
    eval_msg_format=$1
    shift
    [ "$log_files_active" = true ] && $PRINTF "$eval_msg_format" "$@" >> "$verbose_log_file"
}

log_stdout () {
    # targets : stdout
    eval_msg_format=$1
    shift
    $PRINTF "$eval_msg_format" "$@"
}


trap_abort () {
    wait_interrupted=true
    [ -z "$abort" ] && {
        if [ "$trap_abort_state" = 0 ] ; then
            log_stdout "\nInterrupt signal received.\n"
        else
            exec 7>&1 8>&2 1>&5 2>&6
            log_stdout "\n\nInterrupt signal received, aborting after application of patch %s\n" "$patchid"
            log_stdout "completes. Immediate abort of this install script will occur on receipt of\n"
            log_stdout "five further interrupts - the pending patch application operation will not\n"
            log_stdout "abort, and will continue running on the system uninterrupted.\n\n"
            log_stdout "Applying %s (%s of %s) ... " "$patchid" "$count_patches" "$total_patches"
            exec 1>&7 2>&8
        fi
        abort=true
    }
}


trap_exit () {
    # stop dots if running
    stop_dots

    # cleanup dynamic files
    [ -f "$prereq_patch_order_file" ] && $RM -f "$prereq_patch_order_file"
    [ -f "$processed_patch_order_file" ] && $RM -f "$processed_patch_order_file"

    # remove dummy zone config file
    [ -n "$dummy_zone_name" ] && $RM -f "/etc/zones/${dummy_zone_name}.xml"

    # revert zone to halted state
    [ "$zone_restore_state" = soft ] && {
        if [ "$zone_support_level" = boot ] ; then
            $ZONEADM -z "$zone_name" halt 2> /dev/null
        else
            $ZONEADM -R "${ROOTDIR:-/}" -z "$zone_name" unmount 2> /dev/null
        fi
    }
    [ "$zone_restore_state" = hard ] && {
        if [ "$zone_support_level" = boot ] ; then
            $ZONEADM -z "$zone_name" halt || log_all "ERROR: Failed to halt zone '%s'.\n" "$zone_name"
        else
            $ZONEADM -R "${ROOTDIR:-/}" -z "$zone_name" unmount || log_all "ERROR: Failed to unmount zone '%s'.\n" "$zone_name"
        fi
    }

    # unmount and remove fs temporary mount point
    [ -d "$fs_temp_mount_point" ] && {
        $UMOUNT "$fs_temp_mount_point" 2> /dev/null
        $RMDIR "$fs_temp_mount_point" || log_all "ERROR: Failed to remove directory '%s'.\n" "$fs_temp_mount_point"
    }

    # don't do zones/LU cleanup if there is a pending patching operation (ie. abort was forced)
    [ -z "$abort_forced" ] && {
        # restore zone states
        restore_zone_states log_all

        # unmount target boot environment
        [ "$lu_restore_state" = soft ] && {
            $LUUMOUNT -f -n "$lu_be" > /dev/null 2>&1
        }
        [ "$lu_restore_state" = hard ] && {
            $LUUMOUNT -f -n "$lu_be" > /dev/null 2>&1 || log_all "ERROR: Failed to unmount boot environment '%s'.\n" "$lu_be"
        }
    }

    # remove tmp patchadd logfiles
    [ -z "$retain_patchadd_tmp_log_file" ] && {
        [ -n "$patchadd_tmp_log_file" ] && $RM -f "$patchadd_tmp_log_file"
        [ -n "$patchadd_subproc_tmp_log_file" ] && $RM -f "$patchadd_subproc_tmp_log_file"
    }

    # prepare verbose log file for messages from pending patching operation
    [ -n "$abort_forced" ] && log_verbose "\nDeferred log for patch %s :\n" $patchid

    # remove abort log lock 
    [ -f "$abort_log_lock" ] && $RM -f "$abort_log_lock"

    # remove instance lock if held by this instance
    [ -n "$single_instance_lock" ] && $RM -f "$single_instance_lock"
}


setup () {
    # environment setup
    typeset -r orig_LC_ALL="$LC_ALL"
    export LC_ALL=C

    # check necessary commands are available
    for cmd in $REQCMDS; do
        [ -f "$cmd" ] || {
            echo "ERROR: Cannot find '$cmd' which is required for correct"
            echo "       operation of this script."
            return 1
        }
        [ -x "$cmd" ] || {
            echo "ERROR: Cannot execute '$cmd' which is required for correct"
            echo "       operation of this script."
            return 1
        }
    done

    # initialise global variables
    init_global_vars

    # source configuration file
    config="${0%/*}"
    [ "$config" = "$0" ] && config=.
    config="$config/$patchset_config_file"
    [ -r "$config" ] || {
        log_stdout "ERROR: Failed to read patch set configuration file.\n"
        return 1
    }
    $KSH -cn ". \"$config\"" > /dev/null 2>&1 && $KSH -ce ". \"$config\"" > /dev/null 2>&1 || {
        log_stdout "ERROR: Failed to parse patch set configuration file.\n"
        return 1
    }
    . "$config"
    export LC_ALL=C

    # turn on exit handling
    trap trap_exit 0

    # determine name of install script
    script_name="${0##*/}"

    # determine absolute path of directory where install script is
    script_dir="${0%/*}"
    script_dir=${script_dir:-/}
    [ "$script_dir" = "$0" ] && script_dir=.
    ( cd -P "$script_dir" 2> /dev/null ) || {
        log_stdout "ERROR: Failed to cd to install script directory.\n"
        return 1
    }
    script_dir=`cd -P "$script_dir" ; echo "$PWD"`

    # check required configuration file parameters are defined
    [[ "$patchset_config_vers" == 2.* ]] || {
        log_stdout "ERROR: Configuration file incompatible with this version of the patch set\n"
        log_stdout "       install script.\n"
        return 1    
    }

    [ -n "$patch_order_file" ] || {
        log_stdout "ERROR: Required parameter 'patch_order_file' undefined or improperly defined\n"
        log_stdout "       in patch set configuration file.\n"
        return 1    
    }
    [[ "$patchutils_baseid_sparc" == [0-9][0-9][0-9][0-9][0-9][0-9] ]] || {
        log_stdout "ERROR: Required parameter 'patchutils_baseid_sparc' undefined or improperly\n"
        log_stdout "       defined in patch set configuration file.\n"
        return 1    
    }
    [[ "$patchutils_baseid_i386" == [0-9][0-9][0-9][0-9][0-9][0-9] ]] || {
        log_stdout "ERROR: Required parameter 'patchutils_baseid_i386' undefined or improperly\n"
        log_stdout "       defined in patch set configuration file.\n"
        return 1    
    }

    # check user is root
    uid=`$ID | $SED 's/uid=\([0-9]*\).*/\1/'`
    [ "$uid" = 0 ] || {
        log_stdout "ERROR: You must be root to execute this script.\n"
        return 1
    }

    # set umask
    umask 022  || {
        log_stdout "ERROR: Failed to set umask.\n"
        return 1
    }

    # check running system is 5.10
    system_os_rel=`$UNAME -r`
    [ "$system_os_rel" = "5.10" ] || {
        log_stdout "ERROR: System OS release must be 5.10 to execute this script.\n"
        return 1
    }

    # check system architecture is sparc or i386
    system_arch=`$UNAME -p`
    [ "$system_arch" = "sparc" -o "$system_arch" = "i386" ] || {
        log_stdout "ERROR: System architecture must be sparc or i386 to execute this script.\n"
        return 1
    }

    # check if we have a Solaris10  Container
    if [ -d /.SUNWnative  -a  "$system_os_rel" = "5.10" ]; then
	s10_container=true
    fi
	
    # check script is run from global zone or from an s10 container
    [ "`$ZONENAME`" = global -o "$s10_container" = "true" ] || {
		log_stdout "ERROR: This script can only be run from the global zone.\n"
       		return 1
    }

    # check kernel version
    ku_vers=`$UNAME -v`
    if [ "$ku_vers" = "Generic" ] ; then
            # kernel is fcs
            ku_baseid=
            ku_rev=
    elif [ "$s10_container" = "true" ] ; then
# for an s10 container the minimum KU must be update 9 142909-17 or x86
# equivalent
# this is enforced by zoneadm install of an s10 container
	if [ "$system_arch" = "sparc" ] ; then
		for dap_patch in $sparc_dap_ku
		do
			$PATCHADD -p |grep "Patch: $dap_patch" > /dev/null 2>&1 && {
				ku_vers=$dap_patch
				ku_baseid=${ku_vers%-*}
				ku_rev=${ku_vers#*-}
			}
		done
	else
                for dap_patch in $x86_dap_ku
                do
                        $PATCHADD -p |grep "Patch: $dap_patch" > /dev/null 2>&1 && {
                                ku_vers=$dap_patch
                                ku_baseid=${ku_vers%-*}
                                ku_rev=${ku_vers#*-}
                        }
                done

	fi
    else
        echo "$ku_vers" | $GREP "^Generic_[0-9]\{6\}-[0-9]\{2\}$" > /dev/null  || {
            log_stdout "ERROR: Unrecognised kernel version returned by uname.\n"
            return 1
        }
        
        ku_vers=${ku_vers#Generic_}
        ku_baseid=${ku_vers%-*}
        ku_rev=${ku_vers#*-}
    fi
    
    # create empty directory for fs temporary mount point
    $MKDIR "$fs_temp_mount_point" 2> /dev/null || {
        log_stdout "ERROR: Failed to create directory for filesystem temporary mount point.\n"
        return 1
    }

    # check this is not a reinvocation at the end of phase
    [ -f "$end_of_phase_lock" ] && {
        if $GREP "^partial$" "$end_of_phase_lock" > /dev/null ; then
            log_stdout "System has not been rebooted after previous installation phase.\n"
            log_stdout "Please reboot the system before rerunning this script.\n"
        else
            log_stdout "Installation of this patch set has completed. Please reboot the system.\n"
        fi
        return 1
    }
    
    # verify presence of patch set order file
    operative_patch_order_file="$script_dir/$patch_order_file"
    [ -r "$operative_patch_order_file" ] || {
        log_stdout "ERROR: Failed to read patch set order file %s.\n" "$patch_order_file"
        return 1
    }

    # prerequisite order processing
    prereq_action=
    [ -n "$prereq_order" ] && {
        # extract prerequisite patchids from patch set order file to a prereq patch order file
        $CAT /dev/null 2> /dev/null > "$prereq_patch_order_file" || {
            log_stdout "ERROR: Failed to create prerequisite patch order file.\n"
            return 1
        }
        fail=true
        for patchid_pattern in $prereq_order ; do
            [[ "$patchid_pattern" == [0-9][0-9][0-9][0-9][0-9][0-9] || "$patchid_pattern" == [0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9] ]] || {
                log_stdout "ERROR: Illegal pattern '%s' in prereq_order parameter of patch set\n" "$patchid_pattern"
                log_stdout "       configuration file.\n"
                return 1
            }
            curpatchid=`$GREP "^$patchid_pattern" "$operative_patch_order_file" 2> /dev/null`
            [[ "$curpatchid" == [0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9] ]] || {
                log_stdout "ERROR: Pattern '%s' from prereq_order parameter does not match unique\n" "$patchid_pattern"
                log_stdout "       entry in patch set order file.\n"
                return 1
            }
            echo "$curpatchid" 2> /dev/null >> "$prereq_patch_order_file" || {
                log_stdout "ERROR: Failed to create prerequisite patch order file.\n"
                return 1
            }
            fail=
        done
        [ -n "$fail" ] && {
            log_stdout "ERROR: Improperly defined prereq_order parameter in patch set configuration\n"
            log_stdout "       file.\n"
            return 1
        }
        operative_patch_order_file="$prereq_patch_order_file"
        prereq_action=merge
    }

    # build filter for prepatch termination processing
    [ -n "$ignore_prepatch_termination" ] && {
        for patchid_pattern in $ignore_prepatch_termination ; do
            [[ "$patchid_pattern" == [0-9][0-9][0-9][0-9][0-9][0-9] || "$patchid_pattern" == [0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9] ]] || {
                log_stdout "ERROR: Illegal pattern '%s' in ignore_prepatch_termination parameter of\n" "$patchid_pattern"
                log_stdout "       patch set configuration file.\n"
                return 1
            }
            prepatch_termination_filter="$prepatch_termination_filter$patchid_pattern|"
        done
        [ -z "$prepatch_termination_filter" ] && {
            log_stdout "ERROR: Improperly defined ignore_prepatch_termination parameter in patch set\n"
            log_stdout "       configuration file.\n"
            return 1
        }
        prepatch_termination_filter="^(${prepatch_termination_filter%\|})"
    }

    # identify patch set architecture and rev of the bundled patchutils patch
    patchset_patchutils_rev_sparc=`$SED -n "s/^$patchutils_baseid_sparc-\([0-9][0-9]\)$/\1/p" "$operative_patch_order_file" 2> /dev/null | $SORT | $TAIL -1`
    patchset_patchutils_rev_i386=`$SED -n "s/^$patchutils_baseid_i386-\([0-9][0-9]\)$/\1/p" "$operative_patch_order_file" 2> /dev/null | $SORT | $TAIL -1`

    [ -n "$patchset_patchutils_rev_sparc" -a -n "$patchset_patchutils_rev_i386" ] && {
        log_stdout "ERROR: Unable to resolve patch set architecture. Conflicting sparc and i386\n"
        log_stdout "       patch utilities patches found in this patch set.\n"
        return 1
    }

    [ -z "$patchset_patchutils_rev_sparc" -a -z "$patchset_patchutils_rev_i386" ] && {
        log_stdout "ERROR: Unable to resolve patch set architecture. No patch utilities patch found\n"
        log_stdout "       in this patch set.\n"
        return 1
    }

    if [ -n "$patchset_patchutils_rev_sparc" ] ; then
            patchset_patchutils_rev="$patchset_patchutils_rev_sparc"
            patchset_arch=sparc
    else
            patchset_patchutils_rev="$patchset_patchutils_rev_i386"
            patchset_arch=i386
    fi

    patchset_patchutils_rev=${patchset_patchutils_rev#0}
    [ -z "$patchset_patchutils_rev" ] || [ "$patchset_patchutils_rev" = 0 ] && {
        log_stdout "ERROR: No valid revision of the patch utilities patch found in this patch set.\n"
        return 1
    }

    # readme file processing
    [ -n "$readme_file" ] && {
        # verify readme file is present
        [ -r "$script_dir/$readme_file" ] || {
            log_stdout "ERROR: Unable to read patch set %s file.\n" "$readme_file"
            return 1
        }
        # extract passcode if one is specified in readme file
        passcode=`$SED -n 's/^PASSCODE: *\([^ ]*\).*/\1/p' "$script_dir/$readme_file" 2> /dev/null`
        [ -n "$passcode" ] && {
            [ `echo "$passcode" | $GREP -c ".*"` = 1 ] || {
                log_stdout "ERROR: Non-unique passcode in patch set %s file.\n" "$readme_file"
                return 1
            }
        }
    }

    # set patch source directory
    patch_source_dir="$script_dir"
    [ -n "$patches_subdir" ] && patch_source_dir="$patch_source_dir/$patches_subdir"

    return 0
}


eval_live_system () {
    # determine if script is running from miniroot boot environment or system boot environment
    [ -d "/var" ] || {
        log_stdout "ERROR: /var is not a directory.\n"
        return 1
    }

    # in miniroot, /var is symlink to ./tmp/root/var
    [ -h "/var" ] && {
        var_dir=`cd -P /var ; echo "$PWD"`
        if [ "$var_dir" = "/tmp/root/var" ] ; then
            # no packaging information is available under /var in the miniroot, so spoof system_patchutils_rev
            system_patchutils_rev="$patchset_patchutils_rev"
            running_from_miniroot=true
            return 0
        else
            log_stdout "ERROR: /var is a symlink to an unrecognised destination.\n"
            return 1
        fi
    }

    # find rev of currently applied patchutils patch
    system_patchutils_rev=`$SED -n -e "s/^PATCH_INFO_$patchutils_baseid_sparc-\([0-9][0-9]\)=.*/\1/p" -e "s/^PATCH_INFO_$patchutils_baseid_i386-\([0-9][0-9]\)=.*/\1/p" /var/sadm/pkg/SUNWswmt/pkginfo 2> /dev/null | $SORT | $TAIL -1`
    system_patchutils_rev=${system_patchutils_rev#0}
    system_patchutils_rev=${system_patchutils_rev:-0}

    if [ -n "$alt_root_install" ] ; then
        # check live system at least matches the patch set on revision of patch utilities patch
        [ "$system_patchutils_rev" -lt "$patchset_patchutils_rev" ] && {
            log_stdout "Installing this patch set to an alternate boot environment first requires the\n"
            log_stdout "live boot environment to have patch utilities and other prerequisite patches\n"
            log_stdout "at the same (or higher) patch revisions as those delivered by this patch set.\n\n"

            if [ -n "$prereq_action" ] ; then
                log_stdout "The required prerequisite patches can be applied to the live boot environment\n"
                log_stdout "by invoking this script with the '--apply-prereq' option, ie.\n\n"
                log_stdout " %s --apply-prereq" ./$script_name
                [ -n "$passcode" ] && log_stdout " --%s" "$passcode"
                log_stdout "\n\n"
            else
                log_stdout "Please identify the required prerequisite patches by checking the 'Latest Patch\n"
                log_stdout "Update' dropdown menu on the 'Patches and Updates' page of sunsolve.sun.com,\n"
                log_stdout "and apply these patches to the live boot environment manually before rerunning\n"
                log_stdout "this script.\n"
            fi

            return 1
        }
    fi

    return 0
}


eval_target_system () {
    # check proposed patchset version (sourced above in patchset.conf file) is greater than or equal to the
    # version already installed (if any) in the file $ROOTDIR/var/sadm/install_data/rec_patchset_version
    proposed_recpatchset=$recpatchset
    recpatchset=0
    recpatchset=$($GREP "recpatchset=" $ROOTDIR/$current_installed_version_file 2> /dev/null | \
	$AWK '{FS="="; print $2}' 2> /dev/null)
    [[ $proposed_recpatchset == $recpatchset ]] && {
        log_all "ABORT: This Recommended Patchset version is already installed.\n"
        return 1    
    }

    # validate INST_RELEASE file
    softinfo_file="$ROOTDIR/var/sadm/system/admin/INST_RELEASE"
    [ -r "$softinfo_file" ] || {
        log_stdout "ERROR: Failed to read INST_RELEASE file from target boot environment. This file\n"
        log_stdout "       must be present for patch set installation.\n"
        return 1
    }

    ! $GREP "^OS=Solaris$" "$softinfo_file" > /dev/null ||
    ! $GREP "^VERSION=10$" "$softinfo_file" > /dev/null && {
        log_stdout "ERROR: Target boot environment not validated as Solaris 10 by INST_RELEASE file.\n"
        return 1
    }

    # validate os/arch of target by checking pkgs SUNWcsr/SUNWcsu
    arch_csr=`$SED -n 's/^ARCH=\(.*\)/\1/p' "$ROOTDIR/var/sadm/pkg/SUNWcsr/pkginfo" 2> /dev/null`
    vers_csr=`$SED -n 's/^VERSION=\(.*\)/\1/p' "$ROOTDIR/var/sadm/pkg/SUNWcsr/pkginfo" 2> /dev/null`
    arch_csu=`$SED -n 's/^ARCH=\(.*\)/\1/p' "$ROOTDIR/var/sadm/pkg/SUNWcsu/pkginfo" 2> /dev/null`
    vers_csu=`$SED -n 's/^VERSION=\(.*\)/\1/p' "$ROOTDIR/var/sadm/pkg/SUNWcsu/pkginfo" 2> /dev/null`

    if [ "$arch_csr-$vers_csr" = "sparc-11.10.0,REV=2005.01.21.15.53" ] &&
        [ "$arch_csu-$vers_csu" = "sparc-11.10.0,REV=2005.01.21.15.53" ] ; then
        # sparc s10
        target_arch=sparc
    elif [ "$arch_csr-$vers_csr" = "i386-11.10.0,REV=2005.01.21.16.34" ] &&
        [ "$arch_csu-$vers_csu" = "i386-11.10.0,REV=2005.01.21.16.34" ] ; then
        # i386 s10
        target_arch=i386
    else
        log_stdout "ERROR: Target boot environment not identified as being Solaris 10.\n"
        return 1
    fi


    # check target_arch matches patch set arch
    [ "$target_arch" = "$patchset_arch" ] || {
        log_stdout "ERROR: Target boot environment architecture does not match patch set\n"
        log_stdout "       architecture.\n"
        return 1
    } 

    
    # establish extent to which the live system supports zones, and gather zones information for target
    zone_support_level=
    if [ -x "$ZONEADM" -a -z "$s10_container" ] ; then
        [ -x "$ZONECFG" ] || {
            log_stdout "ERROR: Failed to locate zonecfg(1M) command.\n"
            return 1
        }
        # live system has zones support

        if [ -n "$alt_root_install" -a ! -f "$ROOTDIR/etc/zones/index" ] ; then
            # zoneadm fails unhelpfully if ABE does not have zones support, so we spoof this case
            zone_list="global:installed:${ROOTDIR:-/}"

        else
            if $ZONEADM -z global mount 2>&1 > /dev/null | $GREP -w mount > /dev/null ; then
                # zone subsystem supports scratch zones
                zone_support_level=mount
                zone_list=`$ZONEADM -R "${ROOTDIR:-/}" list -cp 2> /dev/null`
                [ $? = 0 ] || {
                    if [ -z "$alt_root_install" ] ; then
                        log_stdout "ERROR: Failed to determine zone configuration for live boot environment.\n"
                        log_stdout "       Please verify configuration with zoneadm(1M).\n"
                    else
                        log_stdout "ERROR: Failed to determine zone configuration for target boot environment.\n\n"
                        log_stdout "       Please ensure all LU boot environments are unmounted, and altroots other\n"
                        log_stdout "       than the target altroot are unmounted prior to executing this script.\n"
                    fi
                    return 1
                }

            else
                # no scratch zone support

                # in general case ROOTDIR can only be null in this code branch - having a current patchutils patch
                # applied on the live system is sufficient for scratch zone support, and eval_live_system() has
                # already verified that a current patchutils patch is applied on the live system if the patch set
                # is being installed in ABE context (ie. ROOTDIR being non-null)

                # miniroot is only exception - if we find ourselves here this means miniroot has not been patched
                # with a current revision of the patchutils, only safe thing to do is abort
                [ "$running_from_miniroot" = true ] && {
                    log_stdout "ERROR: Unsupported version of zoneadm(1M) in miniroot.\n"
                    return 1
                }
                zone_support_level=boot
                zone_list=`$ZONEADM list -cp 2> /dev/null`
                [ $? = 0 ] || {
                    log_stdout "ERROR: Failed to determine zone configuration for live boot environment.\n"
                    log_stdout "       Please verify configuration with zoneadm(1M).\n"
                    return 1
                }
            fi
            # following filter removes non-native zones and native zones in the configured state as both are
            # irrelevant to patching ; final output consists of zone name, zone state, and zone path fields
            zone_list=`echo "$zone_list" |
                       $SED '/^[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:native:/ b end
                       /^[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:/ d
                       :end
                       /^[^:]*:[^:]*:configured:/ d
                       s/^[^:]*:\([^:]*:[^:]*:[^:]*\).*/\1/'`

            # work around for 6826605 
            [ `echo "$zone_list" | $GREP -c ".*"` = `echo "$zone_list" | $SORT -u | $GREP -c ".*"` ] || {
                log_stdout "ERROR: Failed to determine zone configuration for target boot environment.\n\n"
                log_stdout "       Please ensure all LU boot environments are unmounted, and altroots other\n"
                log_stdout "       than the target altroot are unmounted prior to executing this script.\n"
                return 1
            }
        fi

    else
        # live system has no zones support
        if [ -n "$alt_root_install" ] ; then
            [ -f "$ROOTDIR/etc/zones/index" ] && {
		if [ "$s10_container" == "true" ] ; then 
			zone_list="global:installed:${ROOTDIR:-/}"
		else
			# unable to patch an ABE in which zones are supported
			log_stdout "ERROR: Patch set cannot be installed from a live boot environment without zones\n"
			log_stdout "       support, to a target boot environment that has zones support.\n"
			return 1
		fi
            }
            zone_list="global:installed:${ROOTDIR:-/}"
        else
            zone_list="global:running:/"
        fi
    fi


    # verify validity of global zone entry at top of zone_list
    echo "$zone_list" | $SED -n '1 p' | $EGREP "^global:(installed|running):/" > /dev/null || {
        log_stdout "ERROR: Failed to determine zone configuration for target boot environment.\n"
        log_stdout "       Please verify configuration with zoneadm(1M).\n"
        return 1
    }


    # verify all zones are in a patchable state
    if [ -n "$alt_root_install" ] ; then
        # valid zone states for an ABE are installed or mounted (lumount puts zones into mounted state)
        patchable_zone_states="installed|mounted"
    else
        # while patching mounted zones is possible in non DAP context, it is probably better to avoid
        # patching mounted zones in DAP context -- restrict valid zone states to installed or running
        patchable_zone_states="installed|running"
    fi
    echo "$zone_list" | $EGREP -v "^[^:]*:($patchable_zone_states):" > /dev/null && {
        log_stdout "ERROR: One or more non-global zones of the target boot environment is not in a\n"
        log_stdout "       patchable state. Please verify configuration with zoneadm(1M).\n"
        return 1
    }


    # setup for context specific free space calculation below
    max_patch_size_kb=${max_patch_size_kb:-0}
    contents_size_kb=`$DU -sk "$ROOTDIR/var/sadm/install/contents" 2> /dev/null | $SED 's/[^0-9].*//'`
    contents_size_kb=${contents_size_kb:-0}


    single_instance_lock_name="$single_instance_lock_base"
    if [ -n "$alt_root_install" ] ; then
        single_instance_lock_name="$single_instance_lock_name"`echo "$ROOTDIR" | $SED 's|/|.|g'`

        if [ "$target_arch" = "i386" -a -z "$running_from_miniroot" ] ; then
            [ "$ku_vers" = "Generic" -o "$ku_baseid" = "118844" -a "$ku_rev" -lt "21" ] && {
                log_stdout "ERROR: Newboot kernel 118855-36 must be applied to the live boot environment\n"
                log_stdout "       and the system rebooted prior to installing this patch set on an\n"
                log_stdout "       alternate boot environment. To patch the live boot environment up to\n"
                log_stdout "       the required level, please rerun this script against the live boot\n"
                log_stdout "       environment until messaging indicates 118855-36 has been applied.\n"
                return 1
            }
        fi

        # set low water mark on free space in accordance with ABE patching requirements
        req_kb_var_run=$(( 10000 + 2 * contents_size_kb ))
        req_kb_swap=$(( 10000 + max_patch_size_kb + req_kb_var_run ))

    else
        # sanity checks
        [ "$target_arch" = "$system_arch" ] || {
            log_stdout "ERROR: Target boot environment architecture does not match architecture\n"
            log_stdout "       reported by uname.\n"
            return 1
        }
        
        # identify if a KU requiring a reboot will be applied to the system
        next_reboot_ku=
        if [ "$target_arch" = "i386" ] ; then
            if [ "$ku_vers" = "Generic" -o "$ku_baseid" = "118844" -a "$ku_rev" -lt "19" ] ; then
                next_reboot_ku=118844-20
            elif [ "$ku_baseid" = "118844" -o "$ku_baseid" = "118855" -a "$ku_rev" -lt "36" ] ; then
                next_reboot_ku=118855-36
            fi
        else
            [ "$ku_vers" = "Generic" -o "$ku_baseid" = "118822" -o "$ku_baseid" = "118833" -a "$ku_rev" -lt "36" ] && next_reboot_ku=118833-36
        fi

        [ "$prereq_action" != prereqonly ] && {
            # check lofs mount working
            echo "aaaa" > /var/run/.lofs.check.$$.aaaa.$$
            echo "bbbb" > /var/run/.lofs.check.$$.bbbb.$$
            $MOUNT -F lofs /var/run/.lofs.check.$$.aaaa.$$ /var/run/.lofs.check.$$.bbbb.$$ > /dev/null 2>&1
            $GREP "^aaaa$" /var/run/.lofs.check.$$.bbbb.$$ > /dev/null
            ret=$?
            $UMOUNT /var/run/.lofs.check.$$.bbbb.$$ > /dev/null 2>&1
            $RM -f /var/run/.lofs.check.$$.aaaa.$$ /var/run/.lofs.check.$$.bbbb.$$
            [ "$ret" = 0 ] || {
                log_stdout "ERROR: Loopback filesystem (lofs) check failed. Successful installation of\n"
                log_stdout "       this patch set requires lofs functionality. Please ensure lofs is\n"
                log_stdout "       enabled before rerunning this script.\n"
                return 1
            }
            
            # determine if there are non-global zones in states which would be in contention with DAP patching 
            echo "$zone_list" | $EGREP -v "^(global|[^:]*:installed):" > /dev/null && {
                # the below check will work in the general case, where it will not work is incremental patching 
                # of KU-36 or one of the DAP KUs :
                # - incremental KU-36 will lock out system patching, so zone shutdown is not required
                # - incremental DAP KU will require DAP, so zone shutdown is required
                # it is beyond scope of this check to try and determine if incremental patching will occur
                echo "$dap_state_check" | while read dappatchid kupattern ; do
                    [ -z "$dappatchid" -o -z "$kupattern" ] && continue
                    ( eval "case \"$ku_vers\" in $kupattern) exit 0;; esac; exit 1" ) && $GREP "^$dappatchid" "$script_dir/$patch_order_file" > /dev/null && {
                        log_stdout "ERROR: Native non-global zones need to be in the halted state before installing\n"
                        log_stdout "       this patch set.\n"
                        return 1
                    }
                done
            }
        }
        
        # set low water mark on free space in accordance with DAP patching requirements
        req_kb_var_run=$(( 10000 + max_patch_size_kb + 2 * contents_size_kb ))
        req_kb_swap=$(( 10000 + max_patch_size_kb + req_kb_var_run ))
    fi

    # single instance lock
    [ -f "$single_instance_lock_name" ] && {
        log_stdout "ERROR: Another instance of an install script is already running for target boot\n"
        log_stdout "       environment '%s'.\n" "$target"
        return 1
    }
    single_instance_lock="$single_instance_lock_name"
    $TOUCH "$single_instance_lock" 2> /dev/null || {
        log_stdout "ERROR: Failed to create instance lock file.\n"
        return 1
    }

    log_stdout "\nSetup "
    $SLEEP 1 2> /dev/null
    log_stdout "."
    start_dots

    space_check_setup || return 1
    zone_verify || return 1
    stop_dots
    space_check_calculate || return 1

    return 0
}


start_dots () {
    [ -n "$dots_pid" ] && return
    ( while [ 1 ] ; do $SLEEP 3 ; log_stdout "." ; done ) 2> /dev/null &
    dots_pid=$!
}


stop_dots () {
    [ -n "$dots_pid" ] && {
        kill -9 "$dots_pid"
        dots_pid=
        log_stdout "\n\n"
    }
}


total_fs_list () {
    fskey=
    components=
    $SORT | $SED "s/+[ $chtab]*$//" | while read fsline ; do
        [ -z "$fsline" ] && continue
        next_fskey="${fsline%//*}"
        component="${fsline##*//}"
        [ -z "$fskey" ] && fskey="$next_fskey"
        [ "$next_fskey" != "$fskey" ] && {
            echo "$fskey// $(( $components 0 ))"
            components=
            fskey="$next_fskey"
        }
        components="$components $component +"
    done
    [ -n "$fskey" ] && echo "$fskey// $(( $components 0 ))"
}


max_per_fs_list () {
    fskey=
    max_component=0
    $SORT | $SED "s/+[ $chtab]*$//" | while read fsline ; do
        [ -z "$fsline" ] && continue
        next_fskey="${fsline%//*}"
        component="${fsline##*//}"
        component=$(( component ))
        [ -z "$fskey" ] && fskey="$next_fskey"
        [ "$next_fskey" != "$fskey" ] && {
            echo "$fskey// $max_component"
            max_component=0
            fskey="$next_fskey"
        }
        [ "$component" -gt "$max_component" ] && max_component="$component"
    done
    [ -n "$fskey" ] && echo "$fskey// $max_component"
}


evaluate_fs_undo_storage_list () {
    fskey=
    components=
    echo "$fs_undo_storage_list" | $SORT | $SED "$max_undo_storage_factor_sub" | while read fsline ; do
        [ -z "$fsline" ] && continue
        next_fskey="${fsline%//*}"
        component="${fsline##*//}"
        component=$(( $component 0 ))
        [ "$component" -gt 100 ] && component=100
        [ -z "$fskey" ] && fskey="$next_fskey"
        [ "$next_fskey" != "$fskey" ] && {
            echo "$fskey// $(( ( ( $components 0 ) * max_patch_undo_storage_kb ) / 100 ))"
            components=
            fskey="$next_fskey"
        }
        components="$components $component +"
    done
    [ -n "$fskey" ] && echo "$fskey// $(( ( ( $components 0 ) * max_patch_undo_storage_kb ) / 100 ))"
}


space_check_setup () {
    [ -n "$skip_space_check" ] && return 0

    fs_space_check_factors=`echo "$fs_space_check_factors" |
                            $SED -e "/^[ $chtab]*$/ d
                                     s/^[ $chtab]*//
                                     s/[ $chtab]*$//
                                     s/[ $chtab]*,[ $chtab]*/,/g"`

    echo "$fs_space_check_factors" | $EGREP -sv "^(/[^,]*|pkgmeta),[0-9]+,[0-9]+,[0-9]+(,|$)" && {
        stop_dots
        log_stdout "ERROR: Space check setup failed : unable to interpret 'fs_space_check_factors'\n"
        log_stdout "       parameter from patch set configuration file.\n"
        return 1
    }

    root_part_list=`echo "$fs_space_check_factors" |
                    $SED -e 's/^\([^,]*\).*/\1/'`

    max_install_storage_kb_sub=`echo "$fs_space_check_factors" |
                                $SED -e 's/^\([^,]*\),\([^,]*\),[^,]*,[^,]*.*/s# \1 # \2 #g/'`

    max_undo_build_kb_sub=`echo "$fs_space_check_factors" |
                           $SED -e 's/^\([^,]*\),[^,]*,\([^,]*\),[^,]*.*/s# \1 # \2 #g/'`
    
    max_undo_storage_factor_sub=`echo "$fs_space_check_factors" |
                                 $SED -e 's/^\([^,]*\),[^,]*,[^,]*,\([^,]*\).*/s# \1 # \2 #g/'`

    max_patch_undo_storage_kb=${max_patch_undo_storage_kb:-0}
    max_pkgdir_increase_kb=${max_pkgdir_increase_kb:-0}

    # identify inherited package directories of zones - this is made allot more complicated
    # than it should be by virtue of early versions of zonecfg not supporting the -R arg
    zone_ipds=
    zone_info=`echo "$zone_list" | $SED -n '2 p'`
    if [ -n "$zone_info" ] ; then
        # there are non-global zones
        use_zonecfg_directly=
        if [ -z "$alt_root_install" ] ; then
            # live system, execute zonecfg w/o -R argument
            zonecfg_R_arg=""
            use_zonecfg_directly=true
        else
            # determine usability of zonecfg -R for gathering information on altroot zones
            # zonecfg -R argument only supported after CR 6436841 in 120011-14/120012-14
            zone_name=${zone_info%%:*}
            $ZONECFG -R "${ROOTDIR:-/}" -z "$zone_name" info inherit-pkg-dir > /dev/null 2>&1 && {
                # zonecfg -R works
                zonecfg_R_arg="${ROOTDIR:-/}"                
                use_zonecfg_directly=true
            }
        fi

        if [ -n "$use_zonecfg_directly" ] ; then
            echo "$zone_list" | while read zone_info ; do
                zone_name=${zone_info%%:*}
                [ "$zone_name" = global ] && continue
                if [ -n "$zonecfg_R_arg" ] ; then
                    zone_cfg=`$ZONECFG -R "$zonecfg_R_arg" -z "$zone_name" info inherit-pkg-dir`
                else
                    zone_cfg=`$ZONECFG -z "$zone_name" info inherit-pkg-dir`
                fi
                [ $? = 0 ] || {
                    stop_dots
                    log_stdout "ERROR: Space check setup failed : unable to determine filesystem configuration\n"
                    log_stdout "       for zone '%s'.\n\n" "$zone_name"
                    log_stdout "       Please verify zone configuration with zonecfg(1M).\n"
                    return 1
                }
                zone_cfg=`echo "$zone_cfg" | $SED -n "s|.*dir: /|$zone_name:/|p"`
                [ -n "$zone_cfg" ] && zone_ipds="$zone_cfg$chnl$zone_ipds"
            done

        else
            # direct use of zonecfg -R won't work, try a couple of other strategies to get the info we need before giving up
            fail=
            while [ 1 ] ; do
                [ -d /etc/zones ] || {
                    fail=1
                    break
                }
                [ -d "$ROOTDIR/etc/zones" ] || {
                    fail=2
                    break
                }
                find_dummy_zone_name=$$.patchset.private.dummy.zone.name.$$
                while [ -f "/etc/zones/${find_dummy_zone_name}.xml" ] ; do
                    find_dummy_zone_name="$find_dummy_zone_name.$$"
                done
                dummy_zone_name="$find_dummy_zone_name"
                
                $TOUCH "/etc/zones/${dummy_zone_name}.xml" 2> /dev/null && {
                    # /etc/zones on live system is writable - try copying each altroot zone config to a
                    # dummy config on the live system, then processing each dummy config
                    echo "$zone_list" | while read zone_info ; do
                        zone_name=${zone_info%%:*}
                        [ "$zone_name" = global ] && continue
                        $CAT "$ROOTDIR/etc/zones/${zone_name}.xml" > "/etc/zones/${dummy_zone_name}.xml" || fail="${fail}3"
                        zone_cfg=`$ZONECFG -z "$dummy_zone_name" info inherit-pkg-dir`
                        [ $? = 0 ] || fail="${fail}4"
                        zone_cfg=`echo "$zone_cfg" | $SED -n "s|.*dir: /|$zone_name:/|p"`
                        [ -n "$zone_cfg" ] && zone_ipds="$zone_cfg$chnl$zone_ipds"
                    done
                    $RM -f "/etc/zones/${dummy_zone_name}.xml"
                    [ -z "$fail" ] && break
                }

                # /etc/zones on live system is not writable, probably in miniroot - try lofs mounting
                # altroot /etc/zones over live /etc/zones
                $MOUNT -F lofs -O "$ROOTDIR/etc/zones" /etc/zones || {
                    fail="${fail}5"
                    break
                }

                fail_save="$fail"
                fail=
                echo "$zone_list" | while read zone_info ; do
                    zone_name=${zone_info%%:*}
                    [ "$zone_name" = global ] && continue
                    zone_cfg=`$ZONECFG -z "$zone_name" info inherit-pkg-dir`
                    [ $? = 0 ] || fail="${fail}6"
                    zone_cfg=`echo "$zone_cfg" | $SED -n "s|.*dir: /|$zone_name:/|p"`
                    [ -n "$zone_cfg" ] && zone_ipds="$zone_cfg$chnl$zone_ipds"
                done
                $UMOUNT /etc/zones || fail="${fail}7"

                [ -n "$fail" ] && fail="$fail_save$fail"
                break
            done

            [ -n "$fail" ] && {
                stop_dots
                log_stdout "ERROR: Space check setup failed : unable to determine zone configuration data.\n"
                log_stdout "       Please report failure code : %s\n" "$fail"
                return 1
            }
        fi
    fi
    
    fs_install_storage_list=
    fs_install_overheads_list=
    fs_undo_build_list=
    fs_undo_storage_list=
    fs_undo_overheads_list=

    return 0
}

space_check_calculate () {
    [ -n "$skip_space_check" ] && return 0

    # evaluate numeric values for fs space requirements
    fs_install_storage_list=`echo "$fs_install_storage_list" | $SED "$max_install_storage_kb_sub"`
    fs_install_overheads_list=`echo "$fs_install_overheads_list" | max_per_fs_list`

    fs_undo_build_list=`echo "$fs_undo_build_list" | $SED "$max_undo_build_kb_sub" | max_per_fs_list`
    fs_undo_storage_list=`evaluate_fs_undo_storage_list`
    fs_undo_overheads_list=`echo "$fs_undo_overheads_list" | max_per_fs_list`

    # obtain final fs space requirements for both the undo pkg creation and no undo pkg creation cases
    fs_install_list=`echo "$fs_install_storage_list$chnl$fs_install_overheads_list" | total_fs_list`
    fs_install_undo_list=`echo "$fs_install_list$chnl$fs_undo_build_list$chnl$fs_undo_storage_list$chnl$fs_undo_overheads_list" | total_fs_list`

    return 0
}


zone_verify() {
    zone_restore_state_list=
    checked_zfs_command=

    echo "$zone_list" | while read zone_info ; do
        zone_name=${zone_info%%:*}
        zone_info=${zone_info#$zone_name:}
        zone_state=${zone_info%%:*}
        zone_path=${zone_info##*:}
        
        rootpath="$zone_path"
        [ "$rootpath" = / ] && rootpath=
        
        zone_restore_state=
        [ "$zone_name" != "global" ] && {
            # set rootpath for booted zone
            rootpath="$zone_path/root"

            [ "$zone_state" = installed -o "$zone_state" = mounted ] && {
                if [ "$zone_support_level" = boot ] ; then
                    [ "$zone_state" = installed ] && {
                        zone_restore_state=soft
                        $ZONEADM -z "$zone_name" boot || {
                            stop_dots
                            log_stdout "ERROR: Zone verification failed : unable to boot zone '%s'.\n" "$zone_name"
                            return 1
                        }
                        zone_restore_state=hard
                    }
                    rootpath="$zone_path/root"
                    vardevchkpath1="$rootpath"
                    vardevchkpath2="$rootpath/var"
                else
                    [ "$zone_state" = installed ] && {
                        zone_restore_state=soft
                        $ZONEADM -R "${ROOTDIR:-/}" -z "$zone_name" mount || {
                            stop_dots
                            log_stdout "ERROR: Zone verification failed : unable to mount zone '%s'.\n" "$zone_name"
                            return 1
                        }
                        zone_restore_state=hard
                    }

                    # the path on the running system where zoneadmd mounts an altroot zone can be arbitrary - it is
                    # necessary to dertemine the true path for space checking to work
                    if [ -z "$ROOTDIR" ] ; then
                        kern_zone_name="$zone_name"
                    else
                        uuid_zones=`$SED -n "s|^mnttab[ $chtab]\{1,\}\(.*\)/lu/etc/mnttab[ $chtab]\{1,\}mntfs[ $chtab]\{1,\}.*,*zone=SUNWlu[^-].*|\1|p" /etc/mnttab`
                        if [ -n "$uuid_zones" ] ; then
                            kern_zone_name=`$SED -n "s|^$zone_name \(SUNWlu[^ ]\{1,\}\) $ROOTDIR$|\1|p" /tmp/.alt.lu-zone-map 2> /dev/null`
                            [ -z "$kern_zone_name" ] && {
                                stop_dots
                                log_stdout "ERROR: Zone verification failed : unable to determine scratch zone name for\n"
                                log_stdout "       zone '%s'.\n" "$zone_name"
                                return 1
                            }
                        else
                            kern_zone_name="SUNWlu-$zone_name"
                        fi
                    fi
                    zone_path=`$SED -n "s|^mnttab[ $chtab]\{1,\}\(.*\)/lu/etc/mnttab[ $chtab]\{1,\}mntfs[ $chtab]\{1,\}.*,*zone=$kern_zone_name[, $chtab].*|\1|p" /etc/mnttab`
                    [ -n "$zone_path" ] && {
                        if [ -d "$zone_path" ] ; then
                            [ `$DF -k "$zone_path/lu" 2> /dev/null | $SED -n "2 s|^swap  *[0-9]\{1,\}  *[0-9]\{1,\}  *[0-9]\{1,\}  *[0-9]\{1,\}%  */.*|swap|p"` = swap ] || zone_path=
                        else
                            zone_path=
                        fi
                    }
                    [ -n "$zone_path" ] || {
                        stop_dots
                        log_stdout "ERROR: Zone verification failed : unable to determine absolute path of scratch\n"
                        log_stdout "       zone for zone '%s'.\n" "$zone_name"
                        return 1
                    }

                    rootpath="$zone_path/lu/a"
                    vardevchkpath1="$zone_path/lu/var"
                    vardevchkpath2="$rootpath/var"
                fi

                vardevchk1=`$DF -k "$vardevchkpath1" | $SED -n "2 s|^\([^ ]*\)  *[0-9]\{1,\}  *[0-9]\{1,\}  *[0-9]\{1,\}  *[0-9]\{1,\}%  */.*|\1|p"`
                [ -z "$vardevchk1" ] && {
                    stop_dots
                    log_stdout "ERROR: Zone verification failed : unexpected output from command\n"
                    log_stdout "        df -k %s\n\n" "$vardevchkpath1"
                    log_stdout "       Please assess cause of failure and verify system integrity before\n"
                    log_stdout "       proceeding.\n"
                    return 1
                }                   
                vardevchk2=`$DF -k "$vardevchkpath2" | $SED -n "2 s|^\([^ ]*\)  *[0-9]\{1,\}  *[0-9]\{1,\}  *[0-9]\{1,\}  *[0-9]\{1,\}%  */.*|\1|p"`
                [ -z "$vardevchk2" ] && {
                    stop_dots
                    log_stdout "ERROR: Zone verification failed : unexpected output from command\n"
                    log_stdout "        df -k %s\n\n" "$vardevchkpath2"
                    log_stdout "       Please assess cause of failure and verify system integrity before\n"
                    log_stdout "       proceeding.\n"
                    return 1
                }                   

                [ "$vardevchk1" != "$vardevchk2" ] && {
                    # zoneadmd prior to 122660-06/122661-04 suffers from 6463524 - zones with a separate /var filesystem are
                    # incorrectly mounted which causes patching to fail. If we are here, then the current zone is liable to
                    # suffer this problem. The workaround is to prevent pdo from autonomously mounting zones - if we have just
                    # booted a zone, we leave it booted ; if we have just mounted a zone, we leave it mounted and set up an
                    # additional lofs mount which bypasses the issue. Zone states need to be restored (this automatically
                    # tears down the supporting lofs mount) at the end of the patching session, or after applying
                    # 122660/122661 and prior to applying the first DAP patch.
                    
                    if [ "$zone_support_level" = boot ] ; then
                        [ -n "$zone_restore_state" ] && {
                            zone_restore_state_list="halt:$zone_name$chnl$zone_restore_state_list"
                            zone_restore_state=
                        }
                    else
                        [ -n "$zone_restore_state" ] && {
                            zone_restore_state_list="unmount:$zone_name$chnl$zone_restore_state_list"
                            zone_restore_state=
                        }
                        $MOUNT -F lofs -O "$vardevchkpath2" "$vardevchkpath1" || {
                            stop_dots
                            log_stdout "ERROR: Zone verification failed : lofs mount unsuccessful\n"
                            log_stdout "        mount -F lofs -O %s %sn\n" "$vardevchkpath2" "$vardevchkpath1"
                            log_stdout "       Please assess cause of failure and verify system integrity before\n"
                            log_stdout "       proceeding.\n"
                            return 1
                        }
                        zone_restore_state_list="lofs:$vardevchkpath1$chnl$zone_restore_state_list"
                    fi
                }
            }
        }
        
        [ -z "$skip_space_check" ] && {
            # map each root part directory to its filesystem - pkgmeta and /var/sadm/pkg are handled as special cases
            undo_parts=
            echo "$root_part_list${chnl}/var/sadm/pkg" | while read root_part ; do
                [ "$root_part" = "pkgmeta" ] && undo_parts="$undo_parts pkgmeta +" && continue
                [ -d "$rootpath$root_part" ] || continue
                [ "$root_part" != /var/sadm/pkg ] && echo "$zone_ipds" | $GREP "^$zone_name:$root_part$" > /dev/null && continue
                df_opt=k
                fs_mapped=`$DF -k "$rootpath$root_part" | $SED -n "2 s|^\([^ ]*\)  *[0-9]\{1,\}  *[0-9]\{1,\}  *[0-9]\{1,\}  *[0-9]\{1,\}%  *\(/.*\)|\1/\2//|p"`
                [ -n "$fs_mapped" ] && {
                    df_opt=n
                    fstype=`$DF -n "$rootpath$root_part" | $SED -n "1 s|.*: \([^ ]*\).*|\1|p"`
                    if [ -n "$fstype" ] ; then
                        fs_mapped="$fs_mapped$fstype//"
                    else
                        fs_mapped=
                    fi 
                }
                [ -z "$fs_mapped" ] && {
                    stop_dots
                    log_stdout "ERROR: Zone verification failed : unexpected output from command\n"
                    log_stdout "        df -%s %s\n\n" "$df_opt" "$rootpath$root_part"
                    log_stdout "       Please assess cause of failure and verify system integrity before\n"
                    log_stdout "       proceeding.\n"
                    return 1
                }
                [ "$fstype" = zfs -a -z "$checked_zfs_command" ] && {
                    [ -f "$ZFS" ] || {
                        stop_dots
                        log_stdout "ERROR: Cannot find '%s' which is required for correct\n" "$ZFS"
                        log_stdout "       operation of this script.\n"
                        return 1
                    }
                    [ -x "$ZFS" ] || {
                        stop_dots
                        log_stdout "ERROR: Cannot execute '%s' which is required for correct\n" "$ZFS"
                        log_stdout "       operation of this script.\n"
                        return 1
                    }
                    checked_zfs_command=true
                }

                if [ "$root_part" != /var/sadm/pkg ] ; then
                    fs_install_storage_list="$fs_install_storage_list$chnl$fs_mapped $root_part "
                    undo_parts="$undo_parts $root_part +"
                else
                    fs_undo_build_list="$fs_undo_build_list$chnl$fs_mapped $undo_parts"
                    
                    fs_undo_storage_list="$fs_undo_storage_list$chnl$fs_mapped $undo_parts"
                    # in global zone, an additional copy of the undo pkg is made in the pspool area, so we account for this
                    [ "$zone_name" = "global" ] && fs_undo_storage_list="$fs_undo_storage_list$chnl$fs_mapped $undo_parts"
                    
                    fs_undo_overheads_list="$fs_undo_overheads_list$chnl$fs_mapped $max_pkgdir_increase_kb"
                    
                    # obtain size of largest pkg directory
                    max_pkgdir_size_kb=`cd "$rootpath/var/sadm/pkg" ; $DU -sk * | $SORT -n | $SED -n "$ s/[^0-9].*//p"`
                    [ -z "$max_pkgdir_size_kb" ] && {
                        stop_dots
                        log_stdout "ERROR: Zone verification failed : unexpected output from command\n"
                        log_stdout "        cd \"%s\" ; du -sk *\n\n" "$rootpath/var/sadm/pkg"
                        log_stdout "       Please assess cause of failure and verify system integrity before\n"
                        log_stdout "       proceeding.\n"
                        return 1
                    }
                    fs_install_overheads_list="$fs_install_overheads_list$chnl$fs_mapped $max_pkgdir_size_kb"
                fi
            done
        }
            
        [ -n "$zone_restore_state" ] && {
            zone_restore_state=soft
            # revert zone to halted state
            if [ "$zone_support_level" = boot ] ; then
                $ZONEADM -z "$zone_name" halt || {
                    stop_dots
                    log_stdout "ERROR: Zone verification failed : unable to halt zone '%s'\n" "$zone_name"
                    return 1
                }
            else
                $ZONEADM -R "${ROOTDIR:-/}" -z "$zone_name" unmount || {
                    stop_dots
                    log_stdout "ERROR: Zone verification failed : unable to unmount zone '%s'\n" "$zone_name"
                    return 1
                }
            fi
            zone_restore_state=
        }
    done

    return 0
}


restore_zone_states () {
    fail=0
    echo "$zone_restore_state_list" | while read zone_action ; do
        [ -z "$zone_action" ] && continue
        action=${zone_action%%:*}
        object=${zone_action#*:}
        # lofs is a noop, additional lofs mounts set up to work around 6463524 are automatically torn down
        # when the zone is unmounted by zoneadm
        [ "$action" = lofs ] && continue
        if [ "$action" = halt ] ; then
            $ZONEADM -z "$object" "$action" || {
                [ -n "$1" ] && $1 "ERROR : Failed to %s zone '%s'.\n" "$action" "$object"
                fail=1
            }
        else
            $ZONEADM -R "${ROOTDIR:-/}" -z "$object" "$action" || {
                [ -n "$1" ] && $1 "ERROR : Failed to %s zone '%s'.\n" "$action" "$object"
                fail=1
            }
        fi 
    done
    zone_restore_state_list=
    return $fail
}


space_check () {
    if [ -z "$will_save_undo_pkgs" ] ; then
        fs_space_req_list="$fs_install_list"
    else
        fs_space_req_list="$fs_install_undo_list"
    fi
    fs_check_failed=

    echo "$fs_space_req_list" | while read fsline ; do
        [ -z "$fsline" ] && continue
        fskey="${fsline%//*}"
        fstype="${fskey##*//}"
        fskey="${fskey%//*}"
        fsdev="${fskey%//*}"
        fsmount="/${fskey#*//}"
        reqspace="${fsline##*//}"

        [ "$reqspace" -le 0 ] && continue
        
        avblspace=
        if [ -d "$fsmount" ] ; then
            dfline=`$DF -k "$fsmount" 2> /dev/null`
            [ $? = 0 ] && {
                echo "$dfline" | $SED -n '2 s|^\([^ ]*\)  *[0-9]\{1,\}  *[0-9]\{1,\}  *\([0-9]\{1,\}\)  *.*|\1 \2|p' | read curdev avblspace
                [ "$curdev" = "$fsdev" ] || avblspace=
            }
        fi

        [ -z "$avblspace" ] && {
            if [[ "$fsdev" == /dev/* ]] ; then
                fail_status=dffsfail
                while [ 1 ] ; do
                    $MOUNT -F "$fstype" "$fsdev" "$fs_temp_mount_point" || break
                    dfline=`$DF -k "$fs_temp_mount_point" 2> /dev/null`
                    ret=$?
                    $UMOUNT "$fs_temp_mount_point" || break
                    [ $ret = 0 ] || break
                    avblspace=`echo "$dfline" | $SED -n '2 s|^[^ ]*  *[0-9]\{1,\}  *[0-9]\{1,\}  *\([0-9]\{1,\}\)  *.*|\1|p'`
                    break
                done
            else
                fail_status=unsupportedfsdev
                if [ "$fstype" = zfs ] ; then
                    fail_status=zfsavblfail
                    zfs_avblspace=`$ZFS list -Ho available "$fsdev"`
                    [ $? = 0 ] || zfs_avblspace=
                    echo "$zfs_avblspace" | $SED -n '/^[0-9]\{1,\}$/ s/$/ 0 B/p; /^[0-9]\{1,\}[KMGTPE]$/ s/\(.\)$/ 0 \1/p
                    /^[0-9]\{1,\}\.[0-9]*\{1,\}[KMGTPE]$/ s/\.\([0-9]*\)/ \1 /p' | read space_whole space_frac space_unit
                    [ -n "$space_whole" -a -n "$space_frac" -a -n "$space_unit" ] && {
                        [ "$space_frac" != 0 ] && {
                            [ "$space_frac" -le 99 ] && space_frac="${space_frac}0"
                            [ "$space_frac" -le 99 ] && space_frac="${space_frac}0"
                        }
                        space_mult=
                        case "$space_unit" in
                            B) space_mult="0x0" ;;
                            K) space_mult="0x1" ;;
                            M) space_mult="0x400" ;;
                            G) space_mult="0x100000" ;;
                            T) space_mult="0x40000000" ;;
                            P) space_mult="0x10000000000" ;;
                            E) space_mult="0x4000000000000" ;;
                        esac
                        [ -n "$space_mult" ] && avblspace=$(( $space_whole * $space_mult + ( $space_frac * $space_mult ) / 1000 ))
                    }
                fi
            fi
        }

        [ -z "$avblspace" ] && global_status="$fail_status" && return
        [ "$avblspace" -le "$reqspace" ] && fs_check_failed="$fs_check_failed$chnl$reqspace $avblspace $fskey"

    done
    [ -n "$fs_check_failed" ] && global_status=fsexhausted
}


validate_patchset () {
    # if patch set prerequisite order file available, and script was not invoked with
    # the --apply-prereq  option, then merge prerequisite patch order file and patch
    # set order file into the processed patch order file
    if [ "$prereq_action" = merge ] ; then
        $CAT "$operative_patch_order_file" 2> /dev/null > "$processed_patch_order_file" || {
            log_stdout "ERROR: Failed to create processed patch order file.\n"
            return 1
        }
        $EGREP -v -f "$operative_patch_order_file" "$script_dir/$patch_order_file" 2> /dev/null >> "$processed_patch_order_file" || {
            log_stdout "ERROR: Failed to merge patch set order file into processed patch order file.\n"
            return 1
        }
        operative_patch_order_file="$processed_patch_order_file"
    fi
    
    # check syntax of patchids in patch order, and presence of direct instance patches in patch set
    bad_patchid=
    patches_missing=
    $CAT "$operative_patch_order_file" | while read curpatchid ; do
        [[ "$curpatchid" == [0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9] ]] || {
            [ -z "$bad_patchid" ] && {
                log_stdout "ERROR: Following entries from patch set order file are not valid patch IDs :\n"
                bad_patchid=true
            }
            log_stdout "'%s'\n" "$curpatchid"
        }

        [ -f "$patch_source_dir/$curpatchid/.diPatch" ] || patches_missing="$patches_missing$curpatchid "
    done
    [ -n "$bad_patchid" ] && {
        log_stdout "\n"
        return 1
    }

    [ -n "$patches_missing" ] && {
        if [ -n "$patches_subdir" ] ; then
            log_stdout "ERROR: Following patches missing from '%s' directory in patch set :\n" "$patches_subdir"
        else
            log_stdout "ERROR: Following patches missing from main patch set directory :\n"
        fi
        log_stdout "`echo $patches_missing | $TR ' ' '\012' | $PR -5 -t -o 1`"
        log_stdout "\n"
        return 1
    }

    return 0
}


passcode_usage () {
    log_stdout "This script will only execute when a specific passcode is provided as a command\n"
    log_stdout "line option. For further instructions regarding installation of this patch set,\n"
    log_stdout "please review the %s file.\n\n" $readme_file
}


usage () {
    alt_options=
    [ -n "$prereq_action" ] && alt_options="$alt_options [--apply-prereq]"
    [ -n "$passcode" ] && alt_options="$alt_options --<passcode>"
    script_name_spacer=`echo "$script_name" | $SED 's/./ /g'`

    log_stdout "usage: %s [-d] [-h] [-R alt-root-path|-B alt-boot-env]%s\n" "$script_name"
    [ -n "$alt_options" ] && log_stdout "       %s%s\n" "$script_name_spacer" "$alt_options"
    log_stdout "\n"
    log_stdout "       [-d]                  -  don't save undo packages\n"
    log_stdout "       [-h]                  -  display this usage message\n"
    log_stdout "       [-B alt-boot-env]     -  specify LU boot environment as target\n"
    log_stdout "       [-R alt-root-path]    -  specify alternate root as target\n"
    [ -n "$prereq_action" ] &&
        log_stdout "       [--apply-prereq]      -  apply prerequisite patches only\n"
    [ -n "$passcode" ] && {
        log_stdout "       --<passcode>          -  passcode required for script execution\n"
    }
    log_stdout "\n"
    [ -n "$1" ] && exit "$1"
}


lu_setup() {
    # check necessary commands are available
    for cmd in $LUMOUNT $LUSTATUS $LUUMOUNT ; do
        [ -f "$cmd" ] || {
            log_stdout "ERROR: Cannot find '%s' which is required for correct\n" "$cmd"
            log_stdout "       operation of this script.\n"
            return 1
        }
        [ -x "$cmd" ] || {
            log_stdout "ERROR: Cannot execute '%s' which is required for correct\n" "$cmd"
            log_stdout "       operation of this script.\n"
            return 1
        }
    done
    
    $LUSTATUS > /dev/null 2>&1
    [ $? = 0 ] || {
        log_stdout "ERROR: Unable to determine LU configuration for this system. Please verify\n"
        log_stdout "       configuration with lustatus(1M).\n"
        return 1
    }

    lu_stat=`$LUSTATUS "$lu_be" 2> /dev/null | $GREP "^$lu_be\>"`
    [ -z "$lu_stat" ] && {
        log_stdout "ERROR: Unable to determine status for boot environment '%s'.\n" "$lu_be"
        return 1
    }

    set -- $lu_stat
    # BE must be complete, not active, and with no operations in progress
    [ "$2" = "yes" -a "$3" = "no" -a "$6" = "-" ] || {
        log_stdout "ERROR: Boot environment '%s' is not currently in an patchable state.\n" "$lu_be"
        return 1
    }

    lu_be_mount=`$LUMOUNT 2> /dev/null`
    [ $? = 0 ] || {
        log_stdout "ERROR: Unable to determine mounted boot environments.\n"
        return 1
    }
    lu_be_mount=`echo "$lu_be_mount" | $GREP "^$lu_be\>"`

    lu_restore_state=
    [ -z "$lu_be_mount" ] && {
        lu_restore_state=soft
        $LUMOUNT "$lu_be" > /dev/null 2>&1
        [ $? = 0 ] || {
            log_stdout "ERROR: Failed to mount boot environment '%s'.\n" "$lu_be"
            return 1
        }
        lu_restore_state=hard

        lu_be_mount=`$LUMOUNT 2> /dev/null`
        [ $? = 0 ] || {
            log_stdout "ERROR: Unable to determine mounted boot environments.\n"
            return 1
        }
        lu_be_mount=`echo "$lu_be_mount" | $GREP "^$lu_be\>"`
    }

    ROOTDIR=`echo "$lu_be_mount" | $SED -n -e 's/ *$//' -e "s/^$lu_be on //p"`
    [ -z "$ROOTDIR" ] && {
        log_stdout "ERROR: Unable to determine root directory for boot environment.\n"
        return 1
    }
    
    return 0
}


get_patchadd_opts () {
    echo "$patchadd_opt_nosave"
}


parse_args () {
    err_msg=
    err_msg2=
    passcode_confirmed=
    while [ $# != 0 ] ; do
        arg="$1"
        shift
        case "$arg" in
            -B) # LU alt root install
                [ -n "$alt_root_install" ] && [ -z "$err_msg" ] && err_msg="Illegal command line options."
                [ -z "$1" ] && [ -z "$err_msg" ] && err_msg="Missing argument to '-B'."
                lu_be="$1"
                alt_root_install=lu
                shift
                ;;

            -h)
                usage 0
                ;;

            -R) # conventional alt root install
                [ -n "$alt_root_install" ] && [ -z "$err_msg" ] && err_msg="Illegal command line options."
                [ -z "$1" ] && [ -z "$err_msg" ] && err_msg="Missing argument to '-R'."
                ROOTDIR="$1"
                alt_root_install=conventional
                shift
                ;;

            -d) # don't save undo packages
                patchadd_opt_nosave=-d
                ;;

            --apply-prereq) # apply prerequisite patches only
                if [ -n "$prereq_action" ] ; then
                    prereq_action=prereqonly
                else
                    [ -z "$err_msg" ] && {
                        err_msg="Invocation option '--apply-prereq' only supported when a patch set prerequisite"
                        err_msg2="order file is available.\n"
                    }
                fi
                ;;

            --disable-space-check) # hidden option
                skip_space_check=true
                ;;

            *)
                if [ -n "$passcode" -a "$arg" = "--$passcode" ] ; then
                    passcode_confirmed=true
                else
                    [ -z "$err_msg" ] && err_msg="Illegal command line option."
                fi
                ;;
        esac
    done
    
    [ -n "$err_msg" ] && {
        log_stdout "%s\n" "$err_msg"
        [ -n "$err_msg2" ] && log_stdout "%s\n" "$err_msg2"
        log_stdout "\n"
        usage
        [ -n "$passcode" -a -z "$passcode_confirmed" ] && passcode_usage
        return 1
    }
    
    [ -n "$passcode" -a -z "$passcode_confirmed" ] && {
        log_stdout "Correct passcode not confirmed.\n\n"
        usage
        passcode_usage
        return 1
    }

    if [ "$alt_root_install" = lu ] ; then
        lu_setup || return 1
        target="$lu_be"
    else
        [ -n "$ROOTDIR" ] && {
            ( cd -P "$ROOTDIR" 2> /dev/null ) || {
                log_stdout "ERROR: Option '-R %s' does not specify a valid directory path.\n" "$ROOTDIR"
                return 1
            }
            ROOTDIR=`cd -P "$ROOTDIR" ; echo "$PWD"`
            [ "$ROOTDIR" = / ] && ROOTDIR= && alt_root_install=
        }
        target="${ROOTDIR:-/}"
    fi

    patchadd_default_opts=`get_patchadd_opts`
    return 0
}


pre_application_actions () {
    curpatchid=$1

    patchadd_opts="$patchadd_default_opts"

    # if the nosave option is selected as default patch application method, but context requires saving 
    # of the undo pkg for this particular patch, then enable undo package creation for patchadd
    #
    # generally this is required to work around specific issues when applying particular patches with
    # the patchadd -d option
    [ -n "$patchadd_opt_nosave" -a -n "$will_save_undo_pkgs" ] && {
        log_verbose "pre-application-action : enabling undo package creation for patch %s\n" "$curpatchid"
        tmp_opt="$patchadd_opt_nosave"
        patchadd_opt_nosave=
        patchadd_opts=`get_patchadd_opts`
        patchadd_opt_nosave="$tmp_opt"
    }
}


post_application_actions () {
    curpatchid=$1

    if [ -z "$alt_root_install" -a "$patchadd_status" = "pass" ] ; then
        # when patchutils patch applied to running system, update sys_patchutils_* variables
        [[ "$curpatchid" == $patchutils_baseid_sparc-[0-9][0-9] || "$curpatchid" == $patchutils_baseid_i386-[0-9][0-9] ]] && {
            system_patchutils_rev=${curpatchid#$patchutils_baseid_sparc-}
            system_patchutils_rev=${system_patchutils_rev#$patchutils_baseid_i386-}
            system_patchutils_rev=${system_patchutils_rev#0}
            system_patchutils_rev=${system_patchutils_rev:-0}
        }

        # Determine if end of installation phase reached
        [ "$curpatchid" = "118844-20" -a "$next_reboot_ku" = "118844-20" ] && global_status=endofphase
        [ "$curpatchid" = "118833-36" -o "$curpatchid" = "118855-36" ] && global_status=endofphase

        # revert zones to halted state after applying zoneadmd patches (necessary for DAP patching)
        [ -n "$zone_restore_state_list" ] && [ "$curpatchid" = "122660-10" -o "$curpatchid" = "122661-08" ] && {
            log_verbose "post-application-action : reverting zones to halted state\n"
            restore_zone_states log_verbose || global_status=restorezonestatesfail
        }
    fi
}


get_patchadd_status () {
    curpatchid=$1
    padd_exit=$2
    padd_log=$3

    patchadd_status=
    patchadd_status_aux=
    patchadd_status_desc=

    if [ ! -s "$padd_log" ] ; then
        patchadd_status=fail
        patchadd_status_aux=nonviablelogfile
        patchadd_status_desc="nonviable patchadd log file, subprocess exit status '$padd_exit'"
        retain_patchadd_tmp_log_file=true

    elif [ "$padd_exit" = 0 ]; then
        patchadd_status=pass
        
    elif [ "$padd_exit" = 1 ]; then
        # following clauses search patchadd log for cues to identify specific exit conditions in case
        # of patchadd returning non-unique exit code 1

        if $GREP "^The following requested patches are already installed on the system$" "$padd_log" > /dev/null ; then
            # case 1
            # patch already applied
            # cue string has been used since fcs
            patchadd_status=skip
            patchadd_status_aux=alreadyapplied
            patchadd_status_desc="patch already applied"
            patches_skipped_alreadyapplied_list="$patches_skipped_alreadyapplied_list$curpatchid "

        elif $GREP "^The following requested patches do not update any packages installed on the system$" "$padd_log" > /dev/null ; then
            # case 2
            # when all pkgs in a patch have the same PKG but different VERSION from those
            # pkgs installed on the system, patchadd should return exit code 8, however it
            # actually returns exit code 1
            # cue string has been used since rev -06 of the patchutils
            patchadd_status=skip
            patchadd_status_aux=noapplicablepkgs
            patchadd_status_desc="patch not applicable to installed packages"
            patches_skipped_notapplicable_list="$patches_skipped_notapplicable_list$curpatchid "

        elif $TAIL -3 "$padd_log" | $SED -n '1 p' | $GREP "^Version of package .* differs from the package installed on the system.$" > /dev/null ; then
            # same as case 2
            # workaround for truncated messaging after application of a DAP patch, 6651511
            # (regression introduced by 6617022 - reproduce by applying 120812-23 or 125952-04 to FCS)
            patchadd_status=skip
            patchadd_status_aux=noapplicablepkgs
            patchadd_status_desc="patch not applicable to installed packages"
            patches_skipped_notapplicable_list="$patches_skipped_notapplicable_list$curpatchid "

        elif $TAIL -3 "$padd_log" | $SED -n '1 p' | $EGREP "^No patches to (check dependency|dependency check).$" > /dev/null && (
             $TAIL -6 "$padd_log" | $SED -n '1 p' | $GREP "^Version of package .* differs from the package installed on the system.$" > /dev/null ||
             $TAIL -6 "$padd_log" | $SED -n '1,2 p' | $GREP "^Package .* is not installed on the system. Changes for package .* will not be applied to the system.$" > /dev/null ) ; then
            # same as case 1
            # workaround bug where pdo messaging differs depending on system architecture, 6685300
            # (reproduce by applying 118918-24 to u4 on sun4v)
            patchadd_status=skip
            patchadd_status_aux=alreadyapplied
            patchadd_status_desc="patch already applied"
            patches_skipped_alreadyapplied_list="$patches_skipped_alreadyapplied_list$curpatchid "

        elif $GREP "^Unable to install patch. Not enough space in /var/run to copy overlay objects." "$padd_log" > /dev/null ; then
            # /var/run becoming exhausted in DAP mode, best to advise immediate reboot
            patchadd_status=fail
            patchadd_status_aux=dapspace
            patchadd_status_desc="insufficient space available in /var/run"

        else
            # everything else for exit code 1 is a fail
            patchadd_status=fail
            patchadd_status_aux=unhandledexit1
            patchadd_status_desc="unhandled subprocess exit status '$padd_exit' (exit 1 branch)"
        fi

    else
        
        if [ "$system_patchutils_rev" -ge 36 ] ; then
            # patchutils has reliable exit codes
            case "$padd_exit" in 
                2)  # required patch missing
                    patchadd_status=skip
                    patchadd_status_aux=missingreq
                    patchadd_status_desc="required patches not applied"
                    patches_skipped_missingreq_list="$patches_skipped_missingreq_list$curpatchid "
                    ;;

                4)  # patch obsoleted
                    patchadd_status=skip
                    patchadd_status_aux=obsoleted
                    patchadd_status_desc="patch obsoleted by one or more patches already applied"
                    patches_skipped_obsoleted_list="$patches_skipped_obsoleted_list$curpatchid "
                    ;;

                8)  # patch not applicable to installed pkgs
                    patchadd_status=skip
                    patchadd_status_aux=noapplicablepkgs
                    patchadd_status_desc="patch not applicable to packages installed on target"
                    patches_skipped_notapplicable_list="$patches_skipped_notapplicable_list$curpatchid "
                    ;;

                15) # prePatch/prepatch aborted installation
                    if $GREP "^The prePatch script exited with return code " "$padd_log" > /dev/null ; then
                        patchadd_status=fail
                        patchadd_status_aux=prePatchabort
                        patchadd_status_desc="prePatch returned non-zero exit code"

                    elif $GREP "^The prepatch script exited with return code " "$padd_log" > /dev/null ; then
                        if echo "$curpatchid" | $EGREP -s "$prepatch_termination_filter" ; then
                            patchadd_status=skip
                            patches_skipped_prepatch_list="$patches_skipped_prepatch_list$curpatchid "
                        else
                            patchadd_status=fail
                        fi
                        patchadd_status_aux=prepatchabort
                        patchadd_status_desc="prepatch returned non-zero exit code"
                    else 
                        patchadd_status=fail
                        patchadd_status_aux=unhandledexit15
                        patchadd_status_desc="unhandled subprocess exit status '$padd_exit' (exit 15 branch)"
                        retain_patchadd_tmp_log_file=true
                    fi
                    ;;
                
                *)
                    patchadd_status=fail
                    patchadd_status_aux=unhandledexitn
                    patchadd_status_desc="unhandled subprocess exit status '$padd_exit' (exit n branch)"
                    retain_patchadd_tmp_log_file=true
                    ;;
            esac

        else
            # don't interpret patchadd exit code unless patchadd is of a revision with reliable exit codes
            patchadd_status=fail
            patchadd_status_aux=unhandledexitpre36
            patchadd_status_desc="unhandled subprocess exit status '$padd_exit' (pre rev 36 branch)"
            retain_patchadd_tmp_log_file=true
        fi
    fi

    # aggregate lists of patches which applied/skipped/failed
    case "$patchadd_status" in
        pass) patches_applied_list="$patches_applied_list$curpatchid " ;;
        skip) patches_skipped_list="$patches_skipped_list$curpatchid " ;;
        fail) patches_failed_list="$patches_failed_list$curpatchid " ;;
    esac
}



### start
setup || exit 1

parse_args "$@" || exit 1

eval_live_system || exit 1

eval_target_system || exit 1

validate_patchset || exit 1


log_timestamp=`LC_ALL=C $DATE "+%Y.%m.%d %H:%M:%S"`
timestamp=`echo $log_timestamp | $TR " :" "_."`

log_file_name_prefix="${log_file_name_prefix:-patchset}"
verbose_log_file="$ROOTDIR/var/sadm/install_data/${log_file_name_prefix}_verbose_$timestamp.log"
short_log_file="$ROOTDIR/var/sadm/install_data/${log_file_name_prefix}_short_$timestamp.log"
failed_log_file="$ROOTDIR/var/sadm/install_data/${log_file_name_prefix}_failed_$timestamp.log"
session_data_file="$ROOTDIR/var/sadm/install_data/${log_file_name_prefix}_session_$timestamp.dat"
patchadd_tmp_log_file="$ROOTDIR/var/sadm/install_data/_patchadd_$timestamp.log"
patchadd_subproc_tmp_log_file="$ROOTDIR/var/sadm/install_data/_patchadd_subproc_$timestamp.log"

abort=
trap_abort_state=0
abort_interrupt_count=0
exec 5>&1 6>&2
trap trap_abort 1 2 3 15

$RM -f "$verbose_log_file" "$short_log_file" "$failed_log_file" "$session_data_file"
echo "version=1.0
title=$title" > "$session_data_file" || {
    log_stdout "ERROR: Failed to create session data file.\n"
    exit 1
}
$TOUCH "$verbose_log_file" 2> /dev/null && $TOUCH "$short_log_file" 2> /dev/null || {
    $RM -f "$verbose_log_file" "$short_log_file" "$failed_log_file" "$session_data_file"
    log_stdout "ERROR: Failed to create log files.\n"
    exit 1
}
$RM -f "$abort_forced_flag"

log_files_active=true

log_verbose "*** INSTALLATION STARTED  : %s\n" "$log_timestamp"
log_all "\n"

[ -n "$title" ] && log_all "%s\n\n" "$title"

[ -z "$alt_root_install" -a "$prereq_action" != prereqonly ] && {
    if [ -n "$next_reboot_ku" ] ; then
        log_all "Patch %s will be applied shortly. Installation of the patch set will\n" "$next_reboot_ku"
        log_all "halt after this patch is applied, and it will be necessary to reboot before\n"
        log_all "installation of the patch set can continue.\n\n"
    else
        log_all "The patch set will complete installation in this session. No intermediate\n"
        log_all "reboots are required.\n\n"
    fi
}

[ -n "$running_from_miniroot" ] && {
        log_all "This patch set installation session is run from a miniroot boot environment.\n"
        log_all "This script is unable to verify the revision of the patch utilities applied to\n"
        log_all "the miniroot image. For optimal patching, please ensure the miniroot image has\n"
        log_all "been patched with the latest patch utilities and other prerequisite patches.\n\n"
}

log_standard "Application of patches started : %s\n\n" "$log_timestamp"

total_patches=`$GREP -c "[0-9]\{6\}-[0-9][0-9]" "$operative_patch_order_file"`

echo "numpatches=$total_patches
starttime=$log_timestamp" >> "$session_data_file"

total_patches_width=${#total_patches}
count_patches=0
patch_order_offset=0
global_status=continue
while [ 1 ] ; do
    patch_order_list=`$SED -n "$(( patch_order_offset + 1 )),$(( patch_order_offset + 50 )) p" "$operative_patch_order_file"`
    [ -z "$patch_order_list" ] && global_status=complete && break

    for patchid in $patch_order_list ; do

        [ -n "$abort" ] && global_status=abort && break

        [[ "$patchid" == [0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9] ]] || continue

        # undo pkgs will be saved if one or more of the following conditions is true
        # - nosave option not selected
        # - running patchutils below rev 6
        # - applying a patch on the enable undo list
        will_save_undo_pkgs=
        [ -z "$patchadd_opt_nosave" ] || 
        [ "$system_patchutils_rev" -lt 6 ] || 
        echo "$enable_undo" | $GREP "^$patchid" > /dev/null && will_save_undo_pkgs=true

        while [ 1 ] ; do
            # monitor free swap and free space in /var/run to avoid running into issues while in DAP context
            free_kb_var_run=`$DF -k /var/run 2> /dev/null | $SED -n '2 s|^[^ ]*  *[0-9]\{1,\}  *[0-9]\{1,\}  *\([0-9]\{1,\}\)  *.*|\1|p'`
            [ -z "$free_kb_var_run" ] && global_status=dfvarrunfail && break
            [ "$free_kb_var_run" -lt "$req_kb_var_run" ] && global_status=varrunexhausted && break
            free_kb_swap=`$SWAP -s 2> /dev/null | $SED -n '1 s/.*used, \([0-9]*\)k available$/\1/p'`
            [ -z "$free_kb_swap" ] && global_status=swapfail && break
            [ "$free_kb_swap" -lt "$req_kb_swap" ] && global_status=swapexhausted && break
            
            # general filesystem space checking for patch application
            [ -z "$skip_space_check" ] && space_check
            break
        done
        count_patches=`echo "          "$(( count_patches + 1 )) | $SED "s/.*\(.\{$total_patches_width\}\)$/\1/"`

        [ -n "$abort" ] && global_status=abort
        [ "$global_status" = continue ] || break

        log_standard "Applying %s (%s of %s) ... " "$patchid" "$count_patches" "$total_patches"
        trap_abort_state=1

        log_verbose "\nSTARTING : application of %s\n" "$patchid"
        log_verbose "start time : %s\n" "`LC_ALL=C $DATE '+%Y.%m.%d %H:%M:%S'`"
        
        pre_application_actions "$patchid"

        $PRINTF "patch=$patchid:$count_patches:" >> "$session_data_file"
        synopsis=`$SED -n "/^[ $chtab]*Synopsis[ $chtab]*:/ { s|^[ $chtab]*Synopsis[ $chtab]*:[ $chtab]*||p; q; }" "$patch_source_dir/$patchid/README.$patchid" 2> /dev/null`

        $RM -f "$patchadd_tmp_log_file" "$patchadd_subproc_tmp_log_file"
        exec 1> "$patchadd_subproc_tmp_log_file" 2>&1
        (
            cd "$patch_source_dir"
            exec 0<&-
            echo "----" > "$patchadd_tmp_log_file"

            if [ -z "$alt_root_install" ] ; then
                if [ -z "$patchadd_opts" ] ; then
                    echo "# $PATCHADD $patchid" >> "$patchadd_tmp_log_file"
                    $SETPGRP $PATCHADD $patchid >> "$patchadd_tmp_log_file" 2>&1
                    ret=$?
                else
                    echo "# $PATCHADD $patchadd_opts $patchid" >> "$patchadd_tmp_log_file"
                    $SETPGRP $PATCHADD $patchadd_opts $patchid >> "$patchadd_tmp_log_file" 2>&1
                    ret=$?
                fi
            elif [ "$alt_root_install" = conventional -o "$alt_root_install" = lu ] ; then
                if [ -z "$patchadd_opts" ] ; then
                    echo "# $PATCHADD -R \"$ROOTDIR\" $patchid" >> "$patchadd_tmp_log_file"
                    $SETPGRP $PATCHADD -R "$ROOTDIR" $patchid >> "$patchadd_tmp_log_file" 2>&1
                    ret=$?
                else
                    echo "# $PATCHADD $patchadd_opts -R \"$ROOTDIR\" $patchid" >> "$patchadd_tmp_log_file"
                    $SETPGRP $PATCHADD $patchadd_opts -R "$ROOTDIR" $patchid >> "$patchadd_tmp_log_file" 2>&1
                    ret=$?
                fi
            else
                echo >> "$patchadd_tmp_log_file"
                echo "ERROR: Unknown target context '$alt_root_install'" >> "$patchadd_tmp_log_file"
                echo >> "$patchadd_tmp_log_file"
                exit 1
            fi

            echo "----" >> "$patchadd_tmp_log_file"
            echo "patchadd exit code : $ret" >> "$patchadd_tmp_log_file"
            # spin until main process gives go-ahead to write to log file 
            while [ -f "$abort_log_lock" ] ; do $SLEEP 1 ; done
            $CAT "$patchadd_tmp_log_file" >> "$verbose_log_file"
            [ -f "$abort_forced_flag" ] && {
                # do zones/LU cleanup after patching completes
                echo >> "$verbose_log_file"
                # restore zone states
                echo "$zone_restore_state_list" | while read zone_action ; do
                    [ -z "$zone_action" ] && continue
                    action=${zone_action%%:*}
                    object=${zone_action#*:}
                    [ "$action" = lofs ] && continue
                    if [ "$action" = halt ] ; then
                        $ZONEADM -z "$object" "$action" >> "$verbose_log_file" 2>&1
                    else
                        $ZONEADM -R "${ROOTDIR:-/}" -z "$object" "$action" >> "$verbose_log_file" 2>&1
                    fi 
                    [ $? = 0 ] || log_verbose "ERROR : Failed to %s zone '%s'.\n" "$action" "$object"
                done
                # restore LU boot environment state
                [ -n "$lu_restore_state" ] && {
                    $LUUMOUNT -f -n "$lu_be" >> "$verbose_log_file" 2>&1 || log_verbose "ERROR: Failed to unmount boot environment '%s'.\n" "$lu_be"
                }
                $RM -f "$abort_forced_flag"
            }
            exit $ret
            ) &
        subshl_pid=$!
        exec 1>&5 2>&6

        while [ 1 ] ; do
            wait_interrupted=
            wait $subshl_pid
            patchadd_exit=$?
            [ "$wait_interrupted" = true ] && {
                abort_interrupt_count=$(( abort_interrupt_count + 1 ))
                [ "$abort_interrupt_count" -le 5 ] && continue
                $TOUCH "$abort_log_lock" "$abort_forced_flag"
                abort_forced=true
            }
            break
        done
        
        [ -n "$abort_forced" ] && {
            log_standard "pending\n"
            log_verbose "\napplication of %s pending : install script interrupted before\n" "$patchid"
            log_verbose "application of patch complete\n\n"
            log_verbose "PENDING  : application of %s\n\n" "$patchid"
            echo "pending:null::$synopsis" >> "$session_data_file"
            retain_patchadd_tmp_log_file=true
            global_status=abort
            break
        }
        
        get_patchadd_status "$patchid" "$patchadd_exit" "$patchadd_tmp_log_file"
        
        msg_var=PSTAT_STD_$patchadd_status
        log_standard "`eval echo \\$$msg_var`"
        log_standard "\n"
        trap_abort_state=0
        
        log_verbose "application of %s " "$patchid"
        msg_var=PSTAT_VRB_$patchadd_status
        log_verbose "`eval echo \\$$msg_var`"
        [ -n "$patchadd_status_desc" ] && {
            log_verbose " : "
            log_verbose "$patchadd_status_desc"
        }
        log_verbose "\n"

        echo "$patchadd_status:${patchadd_status_aux:-null}::$synopsis" >> "$session_data_file"

        post_application_actions "$patchid"

        log_verbose "finish time : %s\n" "`LC_ALL=C $DATE '+%Y.%m.%d %H:%M:%S'`"
        log_verbose "FINISHED : application of %s\n\n" "$patchid"       
        [ "$patchadd_status" = fail ] && $SED -n "/^STARTING : application of $patchid$/,$ p" "$verbose_log_file" >> "$failed_log_file"

        [ "$global_status" = continue ] && {
            [ "$patchadd_status" = "fail" ] && {
                global_status=patchfail
                [ "$patchadd_status_aux" = dapspace ] && global_status=varrunexhausted
            }
        }       
        [ "$global_status" = continue ] || break
        
    done

    [ "$global_status" = continue ] || break    
    patch_order_offset=$(( patch_order_offset + 50 ))

done


log_timestamp=`LC_ALL=C $DATE "+%Y.%m.%d %H:%M:%S"`
log_standard "\nApplication of patches finished : %s\n\n" "$log_timestamp"


[ -n "$patches_applied_list" ] && {
    log_all "\n"
    log_all "Following patches were applied :\n"
    log_all "`echo $patches_applied_list | $TR ' ' '\012' | $PR -5 -t -o 1`"
    log_all "\n"
}

[ -n "$patches_skipped_list" ] && {
    log_all "\n"
    log_all "Following patches were skipped :\n"

    [ -n "$patches_skipped_alreadyapplied_list" ] && {
        log_all " Patches already applied\n"
        log_all "`echo $patches_skipped_alreadyapplied_list | $TR ' ' '\012' | $PR -5 -t -o 1`"
        log_all "\n"
    }

    [ -n "$patches_skipped_obsoleted_list" ] && {
        log_all " Patches obsoleted by one or more patches already applied\n"
        log_all "`echo $patches_skipped_obsoleted_list | $TR ' ' '\012' | $PR -5 -t -o 1`"
        log_all "\n"
    }

    [ -n "$patches_skipped_notapplicable_list" ] && {
        log_all " Patches not applicable to packages on the system\n"
        log_all "`echo $patches_skipped_notapplicable_list | $TR ' ' '\012' | $PR -5 -t -o 1`"
        log_all "\n"
    }

    [ -n "$patches_skipped_missingreq_list" ] && {
        log_all " Patches missing one or more required patches\n"
        log_all "`echo $patches_skipped_missingreq_list | $TR ' ' '\012' | $PR -5 -t -o 1`"
        log_all "\n"
    }

    [ -n "$patches_skipped_prepatch_list" ] && {
        log_all " Patches canceled due to prepatch termination\n"
        log_all "`echo $patches_skipped_prepatch_list | $TR ' ' '\012' | $PR -5 -t -o 1`"
        log_all "\n"
    }
}

[ -n "$patches_failed_list" ] && {
    log_all "\n"
    log_all "Following patch failed to apply :\n"
    log_all "`echo $patches_failed_list | $TR ' ' '\012' | $PR -5 -t -o 1`"
    log_all "\n"
}

[ -n "$abort_forced" ] && {
    log_all "\n"
    log_all "Following patch application pending :\n"
    log_all " %s\n" "$patchid"
    log_all "\n"
}

log_all "\n"

case "$global_status" in
    abort)
        log_all "Installation of this patch set aborted on an interrupt signal.\n"
        [ -n "$abort_forced" ] && {
            log_all "\nThe pending application of %s will continue to run on the system, with\n" $patchid
            log_all "output being captured to files :\n"
            log_all "  %s\n" "$patchadd_tmp_log_file"
            log_all "  %s\n\n" "$patchadd_subproc_tmp_log_file"
            log_all "On nominal completion of this operation, captured output will be appended to\n"
            log_all "the verbose log file :\n"
            log_all "  %s\n" "$verbose_log_file"
        }
        exit_code=3
        ;;

    endofphase)
        [ -z "$alt_root_install" ] && echo "partial" > "$end_of_phase_lock"
        log_all "End of patch set installation phase. PLEASE REBOOT THE SYSTEM.\n\n"
        log_all "The installation of this patch set has halted after applying patch %s.\n" $patchid
        log_all "The machine must now be rebooted before further patches can be applied. Please\n" 
        log_all "reboot the machine and rerun this script. For further details, see patch set\n"
        log_all "%s file.\n" "$readme_file"
        exit_code=2
        ;;

    complete)
        if [ "$prereq_action" = prereqonly ] ; then
            if [ -z "$alt_root_install" ] ; then
                log_all "Installation of prerequisite patches complete.\n"
            else
                log_all "Installation of prerequisite patches to alternate boot environment complete.\n"
            fi
        else
	    echo "version=${current_installed_version_file_version}\nrecpatchset=${proposed_recpatchset}" > \
		$ROOTDIR/$current_installed_version_file
            if [ -z "$alt_root_install" ] ; then
                if [ -n "$patches_applied_list" ] ; then
                    echo "complete" > "$end_of_phase_lock"
                    log_all "Installation of patch set complete. PLEASE REBOOT THE SYSTEM.\n"
                else
                    log_all "No patches were applied.\n"
                fi
            else
                log_all "Installation of patch set to alternate boot environment complete.\n"
                [ "$alt_root_install" = lu ] && {
                    log_all "\nPlease remember to activate boot environment %s with luactivate(1M)\n" "$lu_be"
                    log_all "before rebooting.\n"
                }
            fi
        fi

        exit_code=0
        ;;

    swapexhausted)
        log_all "Insufficient free swap available to complete installation of this patch set.\n"
        log_all "Additional free swap is required to proceed applying further patches. To\n"
        log_all "increase the available free swap, either add new storage resources to swap\n"
        log_all "pool, or reboot the system. This script may then be rerun to continue\n"
        log_all "installation of the patch set.\n"
        exit_code=1
        ;;

    varrunexhausted)
        log_all "Insufficient space available in /var/run to complete installation of this patch\n"
        log_all "set. On supported configurations, /var/run is a tmpfs filesystem resident in\n"
        log_all "swap. Additional free swap is required to proceed applying further patches. To\n"
        log_all "increase the available free swap, either add new storage resources to swap\n"
        log_all "pool, or reboot the system. This script may then be rerun to continue\n"
        log_all "installation of the patch set.\n"
        exit_code=1
        ;;

    fsexhausted)
        log_all "The following filesystems have available space less than the recommended limit\n"
        log_all "to safely continue installation of this patch set :\n\n"
        echo "$fs_check_failed" | while read reqspace avblspace fskey ; do
            [ -z "$reqspace" ] && continue
            fsdev="${fskey%//*}"
            fsmount="/${fskey#*//}"
            log_all " $fsmount ($fsdev) : %skb available, %skb recommended\n" "$avblspace" "$reqspace"
        done
        log_all "\n"
        log_all "The recommended limit is an estimated upper bound on the amount of space an\n"
        log_all "individual patch application operation may require to complete successfully.\n"
        log_all "Due to the way the recommended limit is estimated, it will always be greater\n"
        log_all "than the actual amount of space required, sometimes by a significant margin.\n"
        log_all "Note the recommended limit is neither the exact amount of free space required\n"
        log_all "to apply a patch, or the amount of free space to completely install the\n"
        log_all "bundle, these interpretations are incorrect.\n"
        log_all "\n"
        log_all "If the operator wishes to continue installation of this patch set at their own\n"
        log_all "risk, space checking can be overridden by invoking this script with the\n"
        log_all "'--disable-space-check' option.\n"
        exit_code=1
        ;;

    patchfail)
        log_all "Aborting due to failure while applying patch %s.\n\n" $patchid
        log_all "Application of this patch should have succeeded - this failure is unexpected.\n"
        log_all "Please assess cause of failure and verify system integrity before proceeding.\n"
        exit_code=1
        ;;

    dfvarrunfail)
        log_all "Unexpected output from command 'df -k /var/run'.\n\n"
        log_all "Please assess cause of failure and verify system integrity before proceeding.\n"
        exit_code=1
        ;;

    dffsfail)
        log_all "Unable to determine free space on device %s (%s).\n\n" "$fsdev" "$fsmount"
        log_all "Please assess cause of failure and verify system integrity before proceeding.\n"
        exit_code=1
        ;;

    zfsavblfail)
        log_all "Unable to determine free space on dataset %s (%s).\n\n" "$fsdev" "$fsmount"
        log_all "Please assess cause of failure and verify system integrity before proceeding.\n"
        exit_code=1
        ;;

    unsupportedfsdev)
        log_all "Unable to perfrom space checking due to an unsupported filesystem device\n"
        log_all " %s (%s)\n\n" "$fsdev" "$fsmount"
        log_all "If the operator wishes to continue installation of this patch set at their own\n"
        log_all "risk, space checking can be overridden by invoking this script with the\n"
        log_all "'--disable-space-check' option.\n"
        exit_code=1
        ;;

    swapfail)
        log_all "Unexpected output from command 'swap -s'.\n\n"
        log_all "Please assess cause of failure and verify system integrity before proceeding.\n"
        exit_code=1
        ;;

    restorezonestatesfail)
        log_all "Failed to restore zone states after application of zoneadmd patch.\n\n"
        log_all "Please assess cause of failure and verify system integrity before proceeding.\n"
        exit_code=1
        ;;

    *)
        log_all ":: exiting on unknown status '%s'\n" "$global_status"
        exit_code=1
        ;;

esac

log_all "\nInstall log files written :\n"
log_all "  %s\n" "$short_log_file"
log_all "  %s\n" "$verbose_log_file"
[ -f "$failed_log_file" ] && log_all "  %s\n" "$failed_log_file"
[ -n "$retain_patchadd_tmp_log_file" ] && {
    [ -f "$patchadd_tmp_log_file" ] && log_all "  %s\n" "$patchadd_tmp_log_file"
    [ -f "$patchadd_subproc_tmp_log_file" ] && log_all "  %s\n" "$patchadd_subproc_tmp_log_file"
}

log_verbose "\n*** INSTALLATION FINISHED : %s\n" "$log_timestamp"

echo "endtime=$log_timestamp
exitcode=$exit_code" >> "$session_data_file"

exit $exit_code

