2N/A#
2N/A# CDDL HEADER START
2N/A#
2N/A# The contents of this file are subject to the terms of the
2N/A# Common Development and Distribution License (the "License").
2N/A# You may not use this file except in compliance with the License.
2N/A#
2N/A# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A# or http://www.opensolaris.org/os/licensing.
2N/A# See the License for the specific language governing permissions
2N/A# and limitations under the License.
2N/A#
2N/A# When distributing Covered Code, include this CDDL HEADER in each
2N/A# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A# If applicable, add the following below this CDDL HEADER, with the
2N/A# fields enclosed by brackets "[]" replaced with your own identifying
2N/A# information: Portions Copyright [yyyy] [name of copyright owner]
2N/A#
2N/A# CDDL HEADER END
2N/A#
2N/A
2N/A#
2N/A# Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A#
2N/A
2N/A#
2N/A# Only change PATH if you give full consideration to GNU or other variants
2N/A# of common commands having different arguments and output.
2N/A#
2N/Aexport PATH=/usr/bin:/usr/sbin
2N/Aunset LD_LIBRARY_PATH
2N/A
2N/A. /usr/lib/brand/shared/common.ksh
2N/A
2N/APROP_PARENT="org.opensolaris.libbe:parentbe"
2N/APROP_ACTIVE="org.opensolaris.libbe:active"
2N/APROP_BE_HANDLE="com.oracle.libbe:nbe_handle"
2N/APROP_CANDIDATE="com.oracle.zoneadm:candidate_zbe"
2N/A
2N/Af_incompat_options=$(gettext "cannot specify both %s and %s options")
2N/Af_sanity_detail=$(gettext "Missing %s at %s")
2N/Asanity_ok=$(gettext " Sanity Check: Passed. Looks like a Solaris system.")
2N/Asanity_fail=$(gettext " Sanity Check: FAILED (see log for details).")
2N/Asanity_fail_vers=$(gettext " Sanity Check: the Solaris image (release %s) is not an OpenSolaris image and cannot be installed in this type of branded zone.")
2N/Ap2ving=$(gettext " Updating: Converting image to non-global.")
2N/Ap2v_done=$(gettext " Result: Conversion complete.")
2N/Ap2v_fail=$(gettext " Result: Conversion failed")
2N/Ainstall_fail=$(gettext " Result: *** Installation FAILED ***")
2N/Af_zfs_in_root=$(gettext "Installing a zone inside of the root pool's 'ROOT' dataset is unsupported.")
2N/Af_no_gzbe=$(gettext "unable to determine global zone boot environment.")
2N/Af_multiple_ds=$(gettext "multiple active datasets.")
2N/Af_no_active_ds=$(gettext "no active dataset.")
2N/Af_zfs_unmount=$(gettext "Unable to unmount the zone's root ZFS dataset (%s).\nIs there a global zone process inside the zone root?\nThe current zone boot environment will remain mounted.\n")
2N/Af_zfs_mount=$(gettext "Unable to mount the zone's ZFS dataset.")
2N/A
2N/Af_sysrepo_fail=$(gettext "Unable to enable svc:/application/pkg/system-repository, please enable the service manually.")
2N/Af_zones_proxyd_fail=$(gettext "Unable to enable svc:/application/pkg/zones-proxyd, please enable the service manually.")
2N/Af_set_sysrepo_prop_fail=$(gettext "Unable to set the use-system-repo property.")
2N/A# Used by install and attach during argument processing
2N/Af_arg_not_dir=$(gettext "Argument %s is not a directory")
2N/Af_arg_not_file=$(gettext "Argument %s is not a regular file")
2N/Af_arg_not_file_or_dir=$(gettext "Argument %s is not a file or directory")
2N/Af_scxml=$(gettext "Configuration profile %s must have an .xml suffix")
2N/Af_gz_image=$(gettext "Cannot attach global zone image")
2N/Af_image_arch_mismatch=$(gettext "Current architecture (%s) doesn't match zone image architecture (%s).")
2N/A
2N/Am_brnd_usage=$(gettext "brand-specific usage: ")
2N/A
2N/Av_reconfig=$(gettext "Performing zone system configuration")
2N/Ae_reconfig=$(gettext "System configuration failed")
2N/Av_mounting=$(gettext "Mounting the zone")
2N/Ae_badmount=$(gettext "Zone mount failed")
2N/Av_unmount=$(gettext "Unmounting zone")
2N/Ae_badunmount=$(gettext "Zone unmount failed")
2N/Ae_exitfail=$(gettext "Postprocessing failed.")
2N/Av_update_format=$(gettext "Updating image format")
2N/Ae_update_format=$(gettext "Updating image format failed")
2N/A
2N/Am_complete_seconds=$(gettext " Done: Installation completed in %s seconds.")
2N/Am_postnote=$(gettext " Next Steps: Boot the zone, then log into the zone console (zlogin -C)")
2N/Am_postnote2=$(gettext " to complete the configuration process.")
2N/A
2N/Am_zbe_discover_failed=$(gettext "Unable to determine which boot environment to activate. Candidates are:\n")
2N/Am_zbe_discover_header=$(gettext "Zone Boot Environment Active Global Zone Boot Environment\n--------------------- ------ ------------------------------------")
2N/Amissing_gzbe=$(gettext "Missing Global Zone Boot Environment")
2N/Am_again_with_dash_z=$(gettext "Use the following command to attach a specific zone boot environment:\n%s")
2N/Ae_no_be_0=$(gettext "Zone has no boot environments")
2N/Ae_no_be_1=$(gettext "Zone has no boot environment with any of these names: %s")
2N/Af_sanity_variant=$(gettext " Sanity Check: FAILED, couldn't determine %s from image.")
2N/Am_cache=$(gettext " Cache: Using %s.")
2N/Af_update_required=$(gettext "Attach failed. This zone must be attached with the -u or -U option.")
2N/Af_uname_p=$(gettext "Unable to determine current architecture.")
2N/Af_list=$(gettext "Could not list packages in image: %s")
2N/Af_osnet=$(gettext "Could not find the osnet-incorporation package installed in image: %s")
2N/Af_update=$(gettext "Could not update attaching zone")
2N/Af_system_volatile=$(gettext "Could not create /system/volatile in the zone.")
2N/Am_active_zbe=$(gettext " Zone BE root dataset: %s")
2N/Am_prep_image=$(gettext " Updating non-global zone: Preparing packages.")
2N/Am_image_link=$(gettext " Updating non-global zone: Linking to image %s.")
2N/Am_image_audit=$(gettext " Updating non-global zone: Auditing packages.")
2N/Am_image_sync=$(gettext " Updating non-global zone: Syncing packages.")
2N/Am_image_sync1=$(gettext " Updating non-global zone: Syncing packages (pass 1 of 2).")
2N/Am_image_sync2=$(gettext " Updating non-global zone: Syncing packages (pass 2 of 2).")
2N/Am_image_update=$(gettext " Updating non-global zone: Updating packages.")
2N/Am_sync_done=$(gettext " Updating non-global zone: Zone updated.")
2N/Am_complete=$(gettext " Result: Attach Succeeded.")
2N/A
2N/Ais_brand_labeled() {
2N/A if [[ -z $ALTROOT ]]; then
2N/A AR_OPTIONS=""
2N/A else
2N/A AR_OPTIONS="-R $ALTROOT"
2N/A fi
2N/A brand=$(/usr/sbin/zoneadm $AR_OPTIONS -z $ZONENAME \
2N/A list -p | awk -F: '{print $6}')
2N/A [[ $brand == "labeled" ]] && return 0
2N/A return 1
2N/A}
2N/A
2N/Afunction sanity_check {
2N/A typeset dir="$1"
2N/A shift
2N/A res=0
2N/A
2N/A #
2N/A # Check for some required directories.
2N/A #
2N/A checks="etc etc/svc var var/svc"
2N/A for x in $checks; do
2N/A if [[ ! -e $dir/$x ]]; then
2N/A log "$f_sanity_detail" "$x" "$dir"
2N/A res=1
2N/A fi
2N/A done
2N/A if (( $res != 0 )); then
2N/A log "$sanity_fail"
2N/A fatal "$install_fail" "$ZONENAME"
2N/A fi
2N/A
2N/A # Check for existence of pkg command.
2N/A if [[ ! -x $dir/usr/bin/pkg ]]; then
2N/A log "$f_sanity_detail" "usr/bin/pkg" "$dir"
2N/A log "$sanity_fail"
2N/A fatal "$install_fail" "$ZONENAME"
2N/A fi
2N/A
2N/A #
2N/A # XXX There should be a better way to do this.
2N/A # Check image release. We only work on the same minor release as the
2N/A # system is running. The INST_RELEASE file doesn't exist with IPS on
2N/A # OpenSolaris, so its presence means we have an earlier Solaris
2N/A # (i.e. non-OpenSolaris) image.
2N/A #
2N/A if [[ -f "$dir/var/sadm/system/admin/INST_RELEASE" ]]; then
2N/A image_vers=$(nawk -F= '{if ($1 == "VERSION") print $2}' \
2N/A $dir/var/sadm/system/admin/INST_RELEASE)
2N/A vlog "$sanity_fail_vers" "$image_vers"
2N/A fatal "$install_fail" "$ZONENAME"
2N/A fi
2N/A
2N/A vlog "$sanity_ok"
2N/A}
2N/A
2N/Afunction get_current_gzbe {
2N/A #
2N/A # If there is no alternate root (normal case) then set the
2N/A # global zone boot environment by finding the boot environment
2N/A # that is active now.
2N/A # If a zone exists in a boot environment mounted on an alternate root,
2N/A # then find the boot environment where the alternate root is mounted.
2N/A #
2N/A CURRENT_GZBE=$(beadm list -H | nawk -v alt=$ALTROOT -F\; '{
2N/A if (length(alt) == 0) {
2N/A # Field 3 is the BE status. "N" is the active BE.
2N/A if ($3 !~ "N")
2N/A next
2N/A } else {
2N/A # Field 4 is the BE mountpoint.
2N/A if ($4 != alt)
2N/A next
2N/A }
2N/A # Field 2 is the BE UUID
2N/A print $2
2N/A }')
2N/A [[ -z "$CURRENT_GZBE" ]] && fatal "$f_no_gzbe"
2N/A return 0
2N/A}
2N/A
2N/A#
2N/A# get_active_be zone
2N/A#
2N/A# Finds the active boot environment for the given zone.
2N/A#
2N/A# Arguments:
2N/A#
2N/A# zone zone structure initialized with init_zone
2N/A#
2N/A# Globals:
2N/A#
2N/A# CURRENT_GZBE Current global zone boot environment. If not already set,
2N/A# it will be set.
2N/A#
2N/A# Returns:
2N/A#
2N/A# 0 on success, else 1.
2N/A#
2N/Afunction get_active_be {
2N/A typeset -n zone=$1
2N/A typeset active_ds=
2N/A typeset tab=$(printf "\t")
2N/A
2N/A if [[ -z "$CURRENT_GZBE" ]]; then
2N/A get_current_gzbe
2N/A fi
2N/A
2N/A typeset name parent active
2N/A zfs list -H -r -d 1 -t filesystem -o name,$PROP_PARENT,$PROP_ACTIVE \
2N/A "${zone.ROOT_ds}" | while IFS=$'\t' read name parent active ; do
2N/A [[ $parent == "$CURRENT_GZBE" ]] || continue
2N/A [[ $active == on ]] || continue
2N/A vlog "Found active dataset %s" "$name"
2N/A if [[ -n "$active_ds" ]]; then
2N/A error "$f_multiple_ds"
2N/A return 1
2N/A fi
2N/A active_ds=$name
2N/A done
2N/A if [[ -z $active_ds ]]; then
2N/A error "$f_no_active_ds"
2N/A return 1
2N/A fi
2N/A
2N/A zone.active_ds=$active_ds
2N/A}
2N/A
2N/A#
2N/A# claim_zbe zone zbe
2N/A#
2N/A# If the zbe belongs to the existing gzbe or the zbe was extracted from an
2N/A# archive and has not yet been attached, set it as the active zbe. Otherwise,
2N/A# clone it and set the clone to the active zbe.
2N/A#
2N/A# Globals:
2N/A#
2N/A# EXIT_CODE On success, set as described in clone_zbe.
2N/A#
2N/A# Returns 0 on success, !0 on failure.
2N/A#
2N/Afunction claim_zbe {
2N/A typeset -n zone=$1
2N/A typeset zbe=$2
2N/A typeset dss
2N/A
2N/A init_dataset dss "${zone.ROOT_ds}/$zbe" || return 1
2N/A
2N/A if [[ -z "$CURRENT_GZBE" ]]; then
2N/A get_current_gzbe
2N/A fi
2N/A
2N/A if [[ ${dss.props[$PROP_CANDIDATE].value} == "$CURRENT_GZBE" ||
2N/A ${dss.props[$PROP_PARENT].value} == "$CURRENT_GZBE" ]]; then
2N/A mount_active_be -b "$zbe" zone
2N/A return $?
2N/A fi
2N/A
2N/A # Sets EXIT_CODE.
2N/A clone_zbe zone "$zbe"
2N/A return $?
2N/A}
2N/A
2N/A#
2N/A# clone_zbe [-u] zone zbe
2N/A#
2N/A# Clones a zbe within a zone and sets the new ZBE as the active BE for this
2N/A# zone.
2N/A#
2N/A# Options and arguments:
2N/A#
2N/A# zone zone structure initialized with init_zone
2N/A# zbe Name of the zone boot environment to clone.
2N/A#
2N/A# Globals:
2N/A#
2N/A# EXIT_CODE On success, set to ZONE_SUBPROC_UNAVAILABLE.
2N/A# On failure, set as described in clone_zone_rpool.
2N/A#
2N/A# Returns:
2N/A#
2N/A# 0 Success, and members of the zone structure have been updated.
2N/A# zone.active_ds Updated with the dataset that is
2N/A# the root of the zbe.
2N/A# zone.zbe_cloned_from Set to the name of the zbe passed in
2N/A# 1 Failure. Error message has been logged.
2N/A#
2N/Afunction clone_zbe {
2N/A typeset -n zone=$1
2N/A typeset zbe=$2
2N/A typeset -i i
2N/A typeset snapname
2N/A typeset dsn=${zone.ROOT_ds}/$zbe
2N/A
2N/A [[ -z $zbe ]] && fail_internal "zbe not specified"
2N/A /usr/sbin/zfs list -o name "$dsn" >/dev/null 2>&1 || \
2N/A fail_internal "Dataset '%s' does not exist" "$dsn"
2N/A
2N/A typeset now=$(date +%Y-%m-%d-%H:%M:%S)
2N/A snapname=$now
2N/A for (( i=0; i < 100; i++ )); do
2N/A /usr/sbin/zfs snapshot -r "$dsn@$snapname" >/dev/null 2>&1 && \
2N/A break
2N/A snapname=$(printf "%s-%02d" "$now" $i)
2N/A done
2N/A if (( i == 100 )); then
2N/A error "$f_zfs_snapshot_of" "$dsn"
2N/A return 1
2N/A fi
2N/A
2N/A # Clone, activate, and mount ZBE
2N/A zone.active_ds=${zone.ROOT_ds}/$zbe
2N/A # Sets EXIT_CODE. "zone" appears twice as it is the source and target.
2N/A clone_zone_rpool zone zone "$snapname" || return 1
2N/A zone.zbe_cloned_from=$zbe
2N/A EXIT_CODE=$ZONE_SUBPROC_UNAVAILABLE
2N/A return 0
2N/A}
2N/A
2N/A#
2N/A# discover_active_be zone
2N/A#
2N/A# Looks for the ZBE that is best suited to be the active ZBE.
2N/A#
2N/A# The caller may optionally constrain the list of ZBEs that is considered for
2N/A# activation by populating the zone.allowed_bes associative array. In such a
2N/A# case, If zone.allowed_bes is a non-empty associative array, only BEs in that
2N/A# array are considered.
2N/A#
2N/A# After selecting which ZBE is the best candidate for activation, care will
2N/A# be taken not to "steal" the ZBE from another global zone. If the chosen
2N/A# zbe has $PROP_PARENT matching the UUID of an extant global zone BE, it is
2N/A# the chosen ZBE is cloned and this new clone is the ZBE that is selected for
2N/A# activation.
2N/A#
2N/A# Note, however, that a ZBE that appears in zone.allowed_bes is
2N/A# never cloned. It is assumed that zone.allowed_bes contains a set of ZBEs
2N/A# that was received from an archive and any existing values in $PROP_PARENT
2N/A# on these ZBEs are stale.
2N/A#
2N/A# Arguments
2N/A#
2N/A# zone A zone structure initialized with init_zone.
2N/A#
2N/A# Globals
2N/A#
2N/A# EXIT_CODE ZONE_SUBPROC_UNAVAILABLE ZBE cloning was attempted
2N/A# and succeeded.
2N/A# ZONE_SUBPROC_FATAL ZBE cloning was attempted,
2N/A# failed, and cleanup failed.
2N/A# ZONE_SUBPROC_TRYAGAIN ZBE selection required. A
2N/A# list of available ZBEs was
2N/A# displayed.
2N/A#
2N/A# Returns:
2N/A#
2N/A# 0 Success. The discovered active_be has been activated (see
2N/A# set_active_be() for details) and has been mounted on the zone root.
2N/A# 1 Active dataset could not be found and an error message has been
2N/A# printed.
2N/A#
2N/Afunction discover_active_be {
2N/A typeset -n zone=$1
2N/A shift
2N/A typeset -A uuid2gzbe
2N/A typeset -i needs_selection=0
2N/A
2N/A #
2N/A # Load an associative array of global zone BEs. Store current uuid
2N/A # of GZBE in $active_gzbe.
2N/A #
2N/A # uuid2gzbe[<gzbe uuid>]=<gzbe name>
2N/A #
2N/A typeset be uuid active junk
2N/A typeset active_gzbe
2N/A beadm list -H | while IFS=\; read be uuid active junk ; do
2N/A uuid2gzbe[$uuid]=$be
2N/A [[ $active == *N* ]] && active_gzbe=$uuid
2N/A done
2N/A if [[ -z $active_gzbe ]]; then
2N/A error "%s: unable to get global zone BE UUID" "${zone.name}"
2N/A return 1
2N/A fi
2N/A
2N/A #
2N/A # Load an associative array of non-global zone BEs and arrays of
2N/A # likely candidates.
2N/A #
2N/A # ngzbe[<ngzbe name>].parent=<gzbe uuid>
2N/A # ngzbe[<ngzbe name>].active=<on|off|->
2N/A # ngzbe[<ngzbe name>].mountpoint=</|zoneroot>
2N/A #
2N/A typeset name mountpoint parent active candidate
2N/A typeset -A ngzbe
2N/A typeset -a activezbe # NGZ BEs that are active
2N/A typeset -a this_gz # NGZ BEs that match this GZ BE
2N/A typeset -a this_gz_active # match GZ BE and is active
2N/A zfs list -H -r -d 1 -t filesystem -o \
2N/A name,mountpoint,$PROP_PARENT,$PROP_ACTIVE,$PROP_CANDIDATE \
2N/A "${zone.ROOT_ds}" | \
2N/A while IFS=$'\t' read name mountpoint parent active candidate
2N/A do
2N/A
2N/A # skip the non-BE top-level dataset
2N/A [[ $name == "${zone.ROOT_ds}" ]] && continue
2N/A
2N/A typeset curbe=$(basename "$name")
2N/A
2N/A # skip BEs that are not in the allowed_bes list
2N/A if (( ${#zone.allowed_bes[@]} != 0 )) &&
2N/A [[ -z ${zone.allowed_bes[$curbe]} ]]; then
2N/A vlog "Ignoring dataset %s: %s not in allowed_bes" \
2N/A "$name" "$(basename "$name")"
2N/A continue
2N/A fi
2N/A
2N/A if [[ -z ${uuid2gzbe[$parent]} ]]; then
2N/A uuid2gzbe[$parent]=$missing_gzbe
2N/A fi
2N/A ngzbe[$curbe].parent=$parent
2N/A ngzbe[$curbe].active=$active
2N/A ngzbe[$curbe].mountpoint=$mountpoint
2N/A ngzbe[$curbe].candidate=$candidate
2N/A
2N/A # Update some arrays used in decision process.
2N/A if [[ $parent == "$active_gzbe" ]]; then
2N/A a_push this_gz "$curbe"
2N/A [[ $active == on ]] && a_push this_gz_active "$curbe"
2N/A fi
2N/A [[ $active == on ]] && a_push activezbe "$curbe"
2N/A done
2N/A #
2N/A # If there are no BEs, return an error
2N/A #
2N/A if (( ${#ngzbe[@]} == 0 )); then
2N/A if (( ${#zone.allowed_bes[@]} == 0 )); then
2N/A error "$e_no_be_0"
2N/A else
2N/A error "$e_no_be_1" "${!zone.allowed_bes[*]}"
2N/A fi
2N/A return 1
2N/A fi
2N/A
2N/A # If there was only one ZBE active for this GZ, activate it.
2N/A if (( ${#this_gz_active[@]} == 1 )); then
2N/A mount_active_be -c -b "${this_gz_active[0]}" zone
2N/A return $?
2N/A fi
2N/A
2N/A # If there was only one ZBE associated with this GZ, activate it.
2N/A if (( ${#this_gz[@]} == 1 )); then
2N/A mount_active_be -c -b "${this_gz[0]}" zone
2N/A return $?
2N/A fi
2N/A
2N/A # If there was only one ZBE that was active, clone and/or activate it.
2N/A if (( ${#activezbe[@]} == 1 )); then
2N/A typeset zbe="${activezbe[0]}"
2N/A if [[ ${#zone.allowed_bes[@]} != 0 ]]; then
2N/A mount_active_be -c -b "$zbe" zone
2N/A return $?
2N/A fi
2N/A # If the zbe is not associated with any gzbe, do not clone it.
2N/A if [[ ${uuid2gzbe[${ngzbe[$zbe].parent}]} == "$missing_gzbe" ]]
2N/A then
2N/A mount_active_be -c -b "$zbe" zone
2N/A return $?
2N/A fi
2N/A clone_zbe zone "$zbe"
2N/A return $?
2N/A fi
2N/A
2N/A # If there was only one ZBE, clone and/or activate it
2N/A if (( ${#ngzbe[@]} == 1 )); then
2N/A #
2N/A # We really want the name of index 0, but a subscript of 0
2N/A # is not supported. Since we know that there is only one
2N/A # item in the associative array, the name of all the items
2N/A # is equivalent to the name of the first item.
2N/A #
2N/A typeset zbe="${!ngzbe[@]}"
2N/A if [[ ${#zone.allowed_bes[@]} ]]; then
2N/A mount_active_be -c -b "$zbe" zone
2N/A return $?
2N/A fi
2N/A # Sets EXIT_CODE.
2N/A clone_zbe zone "$zbe"
2N/A return $?
2N/A fi
2N/A
2N/A log "$m_zbe_discover_failed"
2N/A log "$m_zbe_discover_header"
2N/A typeset zbe
2N/A for zbe in "${!ngzbe[@]}" ; do
2N/A typeset uuid=${ngzbe[$zbe].parent}
2N/A typeset bename=${uuid2gzbe[$uuid]}
2N/A if [[ $bename == $missing_gzbe ]]; then
2N/A typeset cuuid=${ngzbe[$zbe].candidate}
2N/A if [[ $cuuid != $missing_gzbe && \
2N/A -n ${uuid2gzbe[$cuuid]} ]]; then
2N/A bename="Extracted for ${uuid2gzbe[$cuuid]}"
2N/A else
2N/A bename=$uuid
2N/A fi
2N/A fi
2N/A log "%-21s %-6s %s" "$zbe" "${ngzbe[$zbe].active}" "$bename"
2N/A done
2N/A
2N/A log "%s" ""
2N/A
2N/A #
2N/A # Install and attach need different messages. m_usage_dash_z should
2N/A # be defined in the brand's install and attach scripts.
2N/A #
2N/A if (( ${#ATTACH_Z_COMMAND[@]} != 0 )); then
2N/A EXIT_CODE=$ZONE_SUBPROC_TRYAGAIN
2N/A log "$m_again_with_dash_z" "${ATTACH_Z_COMMAND[*]}"
2N/A fi
2N/A
2N/A return 1
2N/A}
2N/A
2N/A#
2N/A# set_active_be zone bootenv
2N/A#
2N/A# Sets the active boot environment for the zone. This includes updating the
2N/A# zone structure and setting the required properties ($PROP_PARENT,
2N/A# $PROP_ACTIVE) on the top-level BE datasets.
2N/A#
2N/Afunction set_active_be {
2N/A typeset -n zone="$1"
2N/A typeset be=$2
2N/A typeset name canmount parent active candidate
2N/A
2N/A [[ -z $be ]] && fail_internal "zbe not specified"
2N/A
2N/A if [[ -z "$CURRENT_GZBE" ]]; then
2N/A get_current_gzbe
2N/A fi
2N/A
2N/A #
2N/A # Turn off the active property on BE's with the same GZBE and ensure
2N/A # that there aren't any BE datasets that will mount automatically.
2N/A #
2N/A zfs list -H -r -d 1 -t filesystem -o \
2N/A name,canmount,$PROP_PARENT,$PROP_ACTIVE,$PROP_CANDIDATE \
2N/A ${zone.ROOT_ds} | \
2N/A while IFS=$'\t' read name canmount parent active candidate ; do
2N/A # skip the ROOT dataset
2N/A [[ $name == "${zone.ROOT_ds}" ]] && continue
2N/A # The root of each BE should only be mounted explicitly.
2N/A if [[ $canmount != noauto ]]; then
2N/A zfs set canmount=noauto "$name" || \
2N/A fail_internal "$e_zfs_set" canmount "$name"
2N/A fi
2N/A #
2N/A # If this was extracted from an archive within this GZ,
2N/A # finish the association process. In the unlikely event
2N/A # that these property updates fail, manual cleanup may
2N/A # be required, but it should not prevent the attach.
2N/A #
2N/A if [[ $candidate == "$CURRENT_GZBE" ]]; then
2N/A zfs inherit "$PROP_CANDIDATE" "$name" ||
2N/A log "$e_zfs_inherit" "$PROP_CANDIDATE" "$name"
2N/A #
2N/A # Setting the parent to this gzbe makes it possible
2N/A # for beadm to clean up the zbes within the zone
2N/A # once one of the candidate zbe's is attached.
2N/A #
2N/A if [[ $parent != "$CURRENT_GZBE" ]]; then
2N/A zfs set "$PROP_PARENT=$CURRENT_GZBE" "$name" ||
2N/A log "$e_zfs_set" "$PROP_PARENT" "$name"
2N/A parent=$CURRENT_GZBE
2N/A fi
2N/A fi
2N/A
2N/A # Deactivate BEs for this GZ that are not being set to active.
2N/A [[ $parent == "$CURRENT_GZBE" ]] || continue
2N/A [[ $active == on ]] || continue
2N/A [[ $name == "${zone.ROOT_ds}/$be" ]] && continue
2N/A vlog "Deactivating active dataset %s" "$name"
2N/A zfs set $PROP_ACTIVE=off "$name" || return 1
2N/A done
2N/A
2N/A zone.active_ds="${zone.ROOT_ds}/$be"
2N/A zfs set "$PROP_PARENT=$CURRENT_GZBE" ${zone.active_ds} \
2N/A || return 1
2N/A zfs set "$PROP_ACTIVE=on" ${zone.active_ds} || return 1
2N/A zfs set "$PROP_BE_HANDLE=on" "${zone.rpool_ds}" || return 1
2N/A
2N/A typeset origin
2N/A zfs list -H -o name,origin "${zone.active_ds}" | while read name origin
2N/A do
2N/A if [[ $origin == "${zone.ROOT_ds}"/* ]]; then
2N/A vlog "Promoting active dataset '%s'" "${zone.active_ds}"
2N/A zfs promote "${zone.active_ds}"
2N/A fi
2N/A done
2N/A
2N/A return 0
2N/A}
2N/A
2N/A#
2N/A# Run system configuration inside a zone.
2N/A#
2N/Afunction reconfigure_zone {
2N/A typeset sc_config=$1
2N/A vlog "$v_reconfig"
2N/A
2N/A vlog "$v_mounting"
2N/A ZONE_IS_MOUNTED=1
2N/A zoneadm -z $ZONENAME mount -f || fatal "$e_badmount"
2N/A
2N/A if [[ -n $sc_config ]]; then
2N/A sc_config_base=$(basename "$sc_config")
2N/A # Remove in case $sc_config_base is a directory
2N/A safe_dir "/system"
2N/A safe_dir "/system/volatile"
2N/A rm -rf "$ZONEPATH/lu/system/volatile/$sc_config_base"
2N/A safe_copy_rec $sc_config \
2N/A "$ZONEPATH/lu/system/volatile/$sc_config_base"
2N/A zlogin -S $ZONENAME "_UNCONFIG_ALT_ROOT=/a \
2N/A /usr/sbin/sysconfig configure -g system \
2N/A -c /system/volatile/$sc_config_base --destructive" \
2N/A </dev/null >/dev/null 2>&1
2N/A else
2N/A zlogin -S $ZONENAME "_UNCONFIG_ALT_ROOT=/a \
2N/A /usr/sbin/sysconfig configure -g system --destructive" \
2N/A </dev/null >/dev/null 2>&1
2N/A fi
2N/A
2N/A if (( $? != 0 )); then
2N/A error "$e_reconfig"
2N/A failed=1
2N/A fi
2N/A
2N/A vlog "$v_unmount"
2N/A zoneadm -z $ZONENAME unmount || fatal "$e_badunmount"
2N/A ZONE_IS_MOUNTED=0
2N/A
2N/A [[ -n $failed ]] && fatal "$e_exitfail"
2N/A}
2N/A
2N/A#
2N/A# Emits to stdout the fmri for the supplied package,
2N/A# stripped of publisher name and other junk.
2N/A#
2N/Afunction get_pkg_fmri {
2N/A typeset pname=$1
2N/A typeset pkg_fmri=
2N/A typeset info_out=
2N/A
2N/A info_out=$(LC_ALL=C ${PKG:-pkg} info pkg:/$pname 2>/dev/null)
2N/A if (( $? != 0 )); then
2N/A return 1
2N/A fi
2N/A pkg_fmri=$(echo $info_out | grep FMRI | cut -d'@' -f 2)
2N/A echo "$pname@$pkg_fmri"
2N/A return 0
2N/A}
2N/A
2N/A#
2N/A# Emits to stdout the entire incorporation for this image,
2N/A# stripped of publisher name and other junk.
2N/A#
2N/Afunction get_entire_incorp {
2N/A get_pkg_fmri entire
2N/A return $?
2N/A}
2N/A
2N/Afunction get_osnet_incorp {
2N/A get_pkg_fmri consolidation/osnet/osnet-incorporation
2N/A return $?
2N/A}
2N/A
2N/A#
2N/A# Handle pkg exit code. Exit 0 means Command succeeded, exit 4 means
2N/A# No changes were made - nothing to do. Any other exit code is an error.
2N/A#
2N/A# Arguments:
2N/A#
2N/A# msg Error message passed as argument to error function
2N/A# errfn Function to call if an error is detected. If not specified,
2N/A# fail_fatal is used.
2N/A#
2N/Afunction pkg_err_check {
2N/A typeset res=$?
2N/A typeset msg=$1
2N/A typeset errfn=${2:-fail_fatal}
2N/A (( $res != 0 && $res != 4 )) && "$errfn" "$msg"
2N/A}
2N/A
2N/A#
2N/A# Enable the services needed to perform packaging operations inside a zone.
2N/A#
2N/Afunction enable_zones_services {
2N/A services_required="$1"
2N/A
2N/A /usr/sbin/svcadm enable -st svc:/application/pkg/system-repository
2N/A if (( $? != 0 )) && [[ -n "$services_required" ]]; then
2N/A error "$f_sysrepo_fail"
2N/A return 1
2N/A fi
2N/A /usr/sbin/svcadm enable -st svc:/application/pkg/zones-proxyd
2N/A if (( $? != 0 )) && [[ -n "$services_required" ]]; then
2N/A error "$f_zones_proxyd_fail"
2N/A return 1
2N/A fi
2N/A return 0
2N/A}
2N/A
2N/A#
2N/A# tag_candidate_zbes ROOTdsn [be_array_name [curgz_assoc_array_name]]
2N/A#
2N/A# Tags each dataset that is a child of ROOTdsn with
2N/A# $PROP_CANDIDATE=$CURRENT_GZBE.
2N/A#
2N/A# Arguments:
2N/A# ROOTdsn The name of a dataset that contains zbes.
2N/A# be_array_name If specified, this variable will contain an array
2N/A# of candidate zbes on return.
2N/A# curgz_assoc_array_name If specified and any zbes have $PROP_PARENT that
2N/A# matches $CURRENT_GZBE, curgz_assoc_array_name will
2N/A# contain that list. Otherwise, curgz_assoc_array_name
2N/A# will be updated to reflect all of the zbes found. Note
2N/A# that curgz_assoc_array_name is an associative (not
2N/A# indexed) array with keys that match the zbe name. The
2N/A# value assigned to each key is not significant.
2N/A#
2N/A# Returns 0 if there is at least one zbe found
2N/A# Returns 1 if there are no zbes or there is a failure updating properties.
2N/A#
2N/Afunction tag_candidate_zbes {
2N/A typeset ROOTdsn=$1
2N/A if [[ -n $2 ]]; then
2N/A typeset -n bes=$2
2N/A fi
2N/A typeset -a bes
2N/A if [[ -n $3 ]]; then
2N/A typeset -n curgzbes=$3
2N/A fi
2N/A typeset -A curgzbes
2N/A typeset dsn parent
2N/A
2N/A if [[ -z "$CURRENT_GZBE" ]]; then
2N/A get_current_gzbe
2N/A fi
2N/A
2N/A /usr/sbin/zfs list -H -o name -r -d 1 -t filesystem "$ROOTdsn" \
2N/A 2>/dev/null | while read dsn ; do
2N/A [[ $dsn == "$ROOTdsn" ]] && continue
2N/A a_push bes "$(basename "$dsn")"
2N/A
2N/A zfs set "$PROP_CANDIDATE=$CURRENT_GZBE" "$dsn" || return 1
2N/A
2N/A # See if the zbe is already associated with the GZBE
2N/A parent=$(zfs get "$PROP_PARENT" "$dsn")
2N/A if [[ $parent == "$CURRENT_GZBE" ]]; then
2N/A curgzbes[$(basename "$dsn")]=1
2N/A fi
2N/A done
2N/A if (( ${#bes[@]} == 0 )); then
2N/A error "$e_no_active_be"
2N/A return 1
2N/A fi
2N/A
2N/A #
2N/A # If there were no zbes that already had a parent of $CURRENT_GZBE,
2N/A # mark all of the found zbes as being allowed.
2N/A #
2N/A if (( ${#curgzbes[@]} == 0 )); then
2N/A typeset be
2N/A for be in "${bes[@]}"; do
2N/A curgzbes[$be]=1
2N/A done
2N/A fi
2N/A
2N/A return 0
2N/A}
2N/A
2N/A#
2N/A# attach_image zone allow_update
2N/A#
2N/A# Arguments:
2N/A#
2N/A# zone A zone reference, initialized by init_zone. A BE
2N/A# must be fully mounted at ${zone.root}. The BE may
2N/A# contain a GZ or NGZ pkg(5) image.
2N/A# allow_update One of "none", "min", or "all".
2N/A# none: No updates to the zone image are allowed.
2N/A# min: The mininal updates required to attach the
2N/A# zone are allowed. This includes updating
2N/A# the pkg(5) image format and satisfying
2N/A# parent dependencies. Corresponds to the
2N/A# default action of p2v (install <-a|-d>)
2N/A# and the historical -u option to attach.
2N/A# all: Like min, but updates all packages to the
2N/A# latest version that are compatible with the
2N/A# global zone image.
2N/A#
2N/A# Side effects on global variables:
2N/A#
2N/A# PKG If not set on entry, set to pkg
2N/A# GZ_IMAGE If not set on entry, set to /
2N/A# PKG_CACHEROOT If not set on entry and a pkg(5) cache exists at
2N/A# /var/pkg/publisher, it is set to PKG_CACHEROOT and exported
2N/A# to the environment.
2N/A# OPT_V If set, pkg(1) commands will be verbose.
2N/A# EXIT_CODE Not changed, but must be set.
2N/A#
2N/A# Returns:
2N/A# If it returns, all went well - the zone is attached. Otherwise, it fails.
2N/A#
2N/Afunction attach_image {
2N/A typeset -n zone=$1
2N/A typeset allow_update=$2
2N/A typeset variantname=variant.opensolaris.zone
2N/A typeset -a variant
2N/A typeset savestate
2N/A typeset variant_changed=false
2N/A typeset verbose
2N/A PKG=${PKG:-pkg}
2N/A GZ_IMAGE=${GZ_IMAGE:-/}
2N/A
2N/A [[ -n $OPT_V ]] && verbose=-v
2N/A
2N/A # Sanity check arguments
2N/A (( $# == 2 )) ||
2N/A fail_internal "expected 2 args, got %d (%s)" $# "$*"
2N/A [[ ! -d ${zone.root} ]] &&
2N/A fail_internal "zone root '%s' does not exist" "${zone.root}"
2N/A [[ $allow_update != @(none|min|all) ]] &&
2N/A fail_internal "invalid value '%s' for allow_update" "$allow_update"
2N/A
2N/A # EXIT_CODE must be set for proper error handling
2N/A [[ -z $EXIT_CODE ]] && fail_internal "EXIT_CODE is not set"
2N/A
2N/A # get the current architecture.
2N/A typeset arch
2N/A arch=$(uname -p) || fail "$f_uname_p"
2N/A
2N/A # If there is a cache, use it.
2N/A if [[ -f /var/pkg/pkg5.image && -d /var/pkg/publisher ]]; then
2N/A # respect PKG_CACHEROOT if the caller has it set.
2N/A [[ -z "$PKG_CACHEROOT" ]] &&
2N/A export PKG_CACHEROOT=/var/pkg/publisher
2N/A log "$m_cache" "$PKG_CACHEROOT"
2N/A fi
2N/A
2N/A #
2N/A # pkg update-format doesn't allow a dry run or provide any other way to
2N/A # see if an update is needed.
2N/A #
2N/A if [[ $allow_update != none ]]; then
2N/A log "$v_update_format"
2N/A $PKG -R "${zone.root}" update-format ||
2N/A pkg_err_check "$e_update_format" fatal
2N/A fi
2N/A
2N/A # Set the use-system-repo property.
2N/A $PKG -R "${zone.root}" set-property use-system-repo true ||
2N/A fatal "\n$f_set_sysrepo_prop_fail"
2N/A
2N/A #
2N/A # Update that catalogs once, subsequent packaging operations will use
2N/A # --no-refresh to avoid unnecessary catalog checks and updates. If
2N/A # image updates are not allowed, there's no need to refresh the
2N/A # catalogs.
2N/A #
2N/A if [[ $allow_update != none ]]; then
2N/A $PKG -R "${zone.root}" refresh --full ||
2N/A pkg_err_check "$e_update_format"
2N/A fi
2N/A
2N/A # prevent attach of a image with a different architecture
2N/A typeset ngz_arch
2N/A ngz_arch=$($PKG -R "${zone.root}" variant -H variant.arch) ||
2N/A (( $? == 0 )) || fatal "$f_sanity_variant" variant.arch
2N/A ngz_arch=$(set -- $ngz_arch; echo $2)
2N/A [[ "$ngz_arch" != "$arch" ]] &&
2N/A fatal "$f_image_arch_mismatch" "$arch" "$ngz_arch"
2N/A
2N/A #
2N/A # Attach the zone to the global zone as a linked image. This
2N/A # writes linked image metadata into the non-global zone which
2N/A # will constrain subsequent packaging operations (but only after
2N/A # the zone variant is set to nonglobal.) The attach operation is
2N/A # performed on the global zone image (and the pkg command will
2N/A # subsequently recurse into and modify the zone image).
2N/A #
2N/A typeset -a pkg_attach_args cmd
2N/A set -A pkg_attach_args -- \
2N/A attach-linked --no-refresh --linked-md-only --allow-relink \
2N/A -f $verbose
2N/A log "$m_image_link" "$GZ_IMAGE"
2N/A set -A cmd $PKG -R "${GZ_IMAGE}" "${pkg_attach_args[@]}" \
2N/A -c "zone:${zone.name}" "${zone.root}"
2N/A vlog "Running '%s'" "${cmd[*]}"
2N/A "${cmd[@]}" || pkg_err_check "$f_update" fatal
2N/A
2N/A # get a list of fmris installed in the ngz image.
2N/A typeset tmpfile1 tmpfile2
2N/A tmpfile1=$(mktemp -t zoneadm_image_attach.$$.XXXXXX) || \
2N/A fatal "$e_tmpfile"
2N/A tmpfile2=$(mktemp -t zoneadm_image_attach.$$.XXXXXX) || \
2N/A fatal "$e_tmpfile"
2N/A set -A cmd $PKG -R "${zone.root}" list --no-refresh -Hv
2N/A vlog "Running '%s'" "${cmd[*]}"
2N/A "${cmd[@]}" > $tmpfile2 || fatal "$f_list" "${zone.root}"
2N/A nawk '{print $1}' $tmpfile2 > $tmpfile1 || fatal "$f_list"
2N/A rm -f "$tmpfile2"
2N/A
2N/A #
2N/A # Lookup the 'entire' incorporation in the global zone. We
2N/A # check for this because if the user has removed it then we'll
2N/A # want to remove it from the zone during attach. The reason is
2N/A # that we're unlikely to be able to attach a highly constrained
2N/A # zone (one that has entire installed) to a loosely constrained
2N/A # global zone (one that doesn't have entire installed).
2N/A #
2N/A typeset gz_entire_pkgver=$(PKG_IMAGE=$GZ_IMAGE; get_entire_incorp)
2N/A
2N/A #
2N/A # Lookup the 'osnet-incorporation' package in the global zone.
2N/A # We need this to do a manual sync check (and possible manual
2N/A # sync) of the zone. (and by manual we mean a sync that does
2N/A # not utilize the pkg linked image framework.)
2N/A #
2N/A typeset gz_osnet_pkgver=$(PKG_IMAGE=$GZ_IMAGE; get_osnet_incorp)
2N/A [[ -z "$gz_osnet_pkgver" ]] && fatal "$f_osnet" "$GZ_IMAGE"
2N/A
2N/A # Lookup for the 'entire' incorporation in the non-global zone.
2N/A # Get the full package name and version.
2N/A typeset ngz_entire_fmri=$(egrep '^pkg://[^]]*/entire@' $tmpfile1)
2N/A typeset ngz_entire_pkgver=${ngz_entire_fmri#pkg://*/}
2N/A
2N/A # Lookup for the 'osnet-incorporation' package in the non-global zone.
2N/A # Get the full package name and version.
2N/A typeset ngz_osnet_fmri=$(egrep \
2N/A '^pkg://[^]]*/consolidation/osnet/osnet-incorporation@' $tmpfile1)
2N/A typeset ngz_osnet_pkgver=${ngz_osnet_fmri#pkg://*/}
2N/A [[ -z "$gz_osnet_pkgver" ]] && fatal "$f_osnet" "${zone.root}"
2N/A
2N/A # get a list of incorporation fmris installed in the ngz image.
2N/A typeset ngz_incorporations=$(
2N/A egrep '^pkg://.*/consolidation/.*/.*-incorporation@' "$tmpfile1"
2N/A )
2N/A
2N/A # we're done with the ngz list of packages
2N/A rm -f "$tmpfile1"
2N/A
2N/A # check if the 'osnet-incorporation' package is in sync between
2N/A # the gz and ngz.
2N/A typeset manual_sync_required=1
2N/A [[ "$gz_osnet_pkgver" == "$ngz_osnet_pkgver" ]] &&
2N/A manual_sync_required=0
2N/A
2N/A if [[ $manual_sync_required != 0 && $allow_update == none ]]; then
2N/A fail_tryagain "\n$f_update_required"
2N/A elif [[ $manual_sync_required != 0 ]]; then
2N/A #
2N/A # before we do a manual sync, we need to make sure that
2N/A # system/volatile exists. old (s11 express / snv_151a)
2N/A # images may not have this directory, which in turn will
2N/A # cause rem_drv and update_drv to fail (since they want
2N/A # to create lock files in that directory).
2N/A #
2N/A ZONEROOT=${zone.root} safe_opt_dir system
2N/A ZONEROOT=${zone.root} safe_opt_dir system/volatile
2N/A if [[ ! -d "${zone.root}/system/volatile" ]]; then
2N/A mkdir -m 755 -p "${zone.root}/system/volatile" || \
2N/A fatal "$f_system_volatile"
2N/A fi
2N/A
2N/A # prepare to try and manually sync the zone image
2N/A typeset -a pkg_install_args
2N/A set -A pkg_install_args -- \
2N/A install -I $verbose --no-refresh --accept
2N/A
2N/A #
2N/A # if the gz doesn't have entire installed we need to
2N/A # remove it from the ngz during out sync.
2N/A #
2N/A [[ -z "$gz_entire_pkgver" ]] &&
2N/A a_push pkg_install_args --reject pkg:///entire
2N/A
2N/A #
2N/A # to manually sync the image we must relax all the image
2N/A # install holds. we do this by specifying the names of
2N/A # all the installed incorporations (excluding publisher
2N/A # and version numbers).
2N/A #
2N/A for fmri in $ngz_incorporations; do
2N/A # strip version and publisher from the fmri
2N/A pub_pkg=${fmri%@*}
2N/A pkg=${pub_pkg#pkg://*/}
2N/A
2N/A #
2N/A # if entire is not installed then we're going to
2N/A # try to sync the image by specifying a version
2N/A # of the osnet-incorporation, but older versions
2N/A # of the pkg client don't allow you to specify
2N/A # overlapping pkg patterns on the cli, so don't
2N/A # try to relax the osnet-incorporation if we're
2N/A # going to explicitly sync it.
2N/A #
2N/A [[ -z "$gz_entire_pkgver" && $pkg == \
2N/A consolidation/osnet/osnet-incorporation ]] &&
2N/A continue
2N/A
2N/A #
2N/A # due to bugs in s11 fcs, it's possible that we
2N/A # may have the ldoms-incorporation installed on
2N/A # non-sparc machines (or nvidia-incorporation
2N/A # on non-i386 machines). if so we don't want to
2N/A # specify these packages on the command line.
2N/A # (since that would require them to be installed
2N/A # and as part of this image update the solver
2N/A # may want to remove them.)
2N/A #
2N/A [[ "$arch" != sparc && $pkg == \
2N/A consolidation/ldoms/ldoms-incorporation ]] &&
2N/A continue
2N/A [[ "$arch" != i386 && $pkg == \
2N/A consolidation/nvidia/nvidia-incorporation ]] &&
2N/A continue
2N/A
2N/A # relax this incorporation
2N/A a_push pkg_install_args pkg:///$pkg
2N/A done
2N/A
2N/A if [[ -n "$gz_entire_pkgver" && -n "$ngz_entire_pkgver" ]]; then
2N/A # entire is installed in the gz and ngz, so sync that.
2N/A a_push pkg_install_args $gz_entire_pkgver
2N/A else
2N/A # we're in one of the following three cases:
2N/A # 1) entire is installed in the gz but not in
2N/A # the ngz.
2N/A # 2) entire is not installed in the gz but is in
2N/A # the ngz (it will be rejected from the ngz).
2N/A # 3) entire is not installed in the gz or ngz
2N/A # in all these cases we must sync osnet-incorporation
2N/A a_push pkg_install_args $gz_osnet_pkgver
2N/A fi
2N/A
2N/A # try to manually sync the image.
2N/A set -A cmd $PKG -R "${zone.root}" "${pkg_install_args[@]}"
2N/A if [[ "$allow_update" == all ]]; then
2N/A log "$m_image_sync"
2N/A elif [[ "$allow_update" == min ]]; then
2N/A log "$m_image_sync1"
2N/A else
2N/A fail_internal "allow_update is '$allow_update'"
2N/A fi
2N/A vlog "Running '%s'" "${cmd[*]}"
2N/A "${cmd[@]}" || pkg_err_check "$f_update" fatal
2N/A fi
2N/A
2N/A #
2N/A # If the image is a global zone and updates are allowed, do p2v.
2N/A #
2N/A set -A variant \
2N/A $(LC_ALL=C $PKG -R "${zone.root}" variant -H $variantname)
2N/A (( $? == 0 )) || fatal "$f_sanity_variant" "$variantname"
2N/A [[ ${variant[0]} != "${variantname}" ]] &&
2N/A fatal "$f_sanity_variant" "$variantname"
2N/A case ${variant[1]} in
2N/A global)
2N/A # We can't change the variant if updates aren't allowed.
2N/A [[ $allow_update == @(min|all) ]] || fatal "$f_gz_image"
2N/A
2N/A log "$p2ving"
2N/A typeset -a p2vopts
2N/A set -A p2vopts $verbose_mode "${zone.name}" "${zone.path}"
2N/A vlog "running: p2v ${p2vopts[@]}"
2N/A /usr/lib/brand/solaris/p2v "${p2vopts[@]}"
2N/A p2v_exit=$?
2N/A if (( $p2v_exit != 0 )); then
2N/A # Pass the p2v exit code up to zoneadm
2N/A EXIT_CODE=$p2v_exit
2N/A log "$p2v_fail"
2N/A fatal "\n$install_fail"
2N/A fi
2N/A vlog "$p2v_done"
2N/A ;;
2N/A nonglobal)
2N/A :
2N/A ;;
2N/A *) fail_internal "$variantname is '${variant[1]}'"
2N/A ;;
2N/A esac
2N/A
2N/A # Assemble the arguments to sync the zone image
2N/A typeset -a pkg_sync_args
2N/A typeset log_msg
2N/A typeset fail_msg=$f_update
2N/A case $allow_update in
2N/A none)
2N/A #
2N/A # $f_update_required advises the use of -u or -U. It should
2N/A # only be used with attach, as -u means something different
2N/A # with install. install will only have "min" or "all" as
2N/A # values for allow_update.
2N/A #
2N/A fail_msg=$f_update_required
2N/A log_msg=$m_image_audit
2N/A set -A pkg_sync_args -- sync-linked --no-pkg-updates
2N/A ;;
2N/A min)
2N/A if [[ $manual_sync_required != 0 ]]; then
2N/A log_msg=$m_image_sync2
2N/A else
2N/A log_msg=$m_image_sync
2N/A fi
2N/A set -A pkg_sync_args -- sync-linked
2N/A ;;
2N/A all)
2N/A log_msg=$m_image_update
2N/A set -A pkg_sync_args -- update -f
2N/A ;;
2N/A *)
2N/A fail_internal "Invalid allow_update value: $allow_update"
2N/A esac
2N/A a_push pkg_sync_args -I $verbose --no-refresh --accept
2N/A [[ $allow_update != none && -z $gz_entire_pkgver ]] &&
2N/A a_push pkg_sync_args --reject pkg:///entire
2N/A
2N/A # Sync the zone image.
2N/A log "$log_msg"
2N/A set -A cmd $PKG -R "${zone.root}" "${pkg_sync_args[@]}"
2N/A vlog "Running '%s'" "${cmd[*]}"
2N/A "${cmd[@]}" || pkg_err_check "$fail_msg" fatal
2N/A
2N/A log "\n$m_sync_done"
2N/A log "$m_complete"
2N/A}