#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
#
. /usr/lib/brand/solaris/common.ksh
# Allows developer to override some things like PATH and PYTHONPATH
. /usr/lib/brand/solaris/developerenv.ksh
# m_usage is used by fail_usage()
m_usage=$(gettext "Usage:\n\t attach [-uv] [-a archive | -d directory | -z zbe] [-c profile.xml | dir]\n\n\t-u\tUpdate the software in the attached zone boot environment to\n\t\tmatch the sofware in the global zone boot environment.\n\t-v\tVerbose.\n\t-c\tUpdate the zone configuration with the sysconfig profile\n\t\tspecified in the given file or directory.\n\t-a\tExtract the specified archive into the zone then attach the\n\t\tactive boot environment found in the archive. The archive\n\t\tmay be a zfs, cpio, or tar archive. It may be compressed with\n\t\tgzip or bzip2.\n\t-d\tCopy the specified directory into a new zone boot environment\n\t\tthen attach the zone boot environment.\n\t-z\tAttach the specified zone boot environment.")
m_use_install=$(gettext "Warning: The -a and -d options to the attach subcommand may be removed in a\nfuture release of Solaris. Use of the install subcommand is recommended.")
m_failed=$(gettext " Result: Attach Failed.")
e_dataset_not_in_be=$(gettext "Dataset %s mountpoint %s is not under zone root %s")
f_multiple_extractions=$(gettext "Zone already has one or more extracted zone boot environments.\nUse 'zoneadm -z <zone> attach -z <zbe>' to attach an existing zbe.\n")
f_bad_opt_combo=$(gettext "incompatible options -%s and %-s")
f_repeated_opt=$(gettext "repeated option -%s")
# Clean up on interrupt
trap_cleanup() {
trap - INT
log "$m_interrupt"
# umount any mounted file systems
umnt_fs
trap_exit
}
# If the attach failed then clean up the ZFS datasets we created.
trap_exit() {
#
# Since trap_int calls trap_exit we need to cancel the exit
# handler so that we don't do two passes.
#
trap - INT EXIT
if [[ -n $EXIT_NOEXECUTE ]]; then
# dryrun mode, nothing to do here; exit with whatever
# EXIT_CODE is set to.
;
elif [[ $EXIT_CODE == $ZONE_SUBPROC_USAGE ]]; then
# Usage message printed, nothing to do here.
;
elif [[ $EXIT_CODE == @($ZONE_SUBPROC_OK|$ZONE_SUBPROC_UNAVAILABLE) ]]
then
# unmount the zoneroot if labeled brand
is_brand_labeled && ( umount $ZONEROOT || \
log "$f_zfs_unmount" "$ZONEPATH/root" )
unpin_datasets "${zone.path.ds}" || error "$f_unpin"
elif [[ $EXIT_CODE == $ZONE_SUBPROC_TRYAGAIN ]]; then
unpin_datasets "${zone.path.ds}" || error "$f_unpin"
log "$m_failed"
else
# Remove datasets that shouldn't exist
delete_unpinned_datasets "${zone.path.ds}" &&
EXIT_CODE=$ZONE_SUBPROC_TRYAGAIN
unpin_datasets "${zone.path.ds}" || error "$f_unpin"
log "$m_failed"
fi
vlog "Exiting with exit code $EXIT_CODE"
finish_log zone
exit $EXIT_CODE
}
EXIT_CODE=$ZONE_SUBPROC_USAGE
install_media="-"
# Will be used by start_log after option processing
set -A save_args "$0" "$@"
# If we weren't passed at least two arguments, exit now.
(( $# < 2 )) && exit $ZONE_SUBPROC_USAGE
zone=
init_zone zone "$1" "$2"
# Set ZONEPATH, etc.
eval $(bind_legacy_zone_globals zone)
shift; shift # remove ZONENAME and ZONEPATH from arguments array
allow_update=none
noexecute=0
typeset -A opts # Used in option compatibility checks.
unset inst_type
unset sc_config
# Get publisher information for global zone. These structures are used
# to store information about the global zone publishers and
# incorporations.
typeset gz_incorporations=""
#
# If extracting an archive that contains multiple zbes, it is possible that
# we won't be able to automatically select which zbe to set as the active
# zbe. In such a case, discover_active_be() will suggest the use of this
# command. It may be augmented in getopts processing.
#
set -A ATTACH_Z_COMMAND zoneadm -z "${zone.name}" attach -z "<zbe>"
# Other brand attach options are invalid for this brand.
verbose=
while getopts "a:c:d:n:Uuvz:x:" opt; do
opts[$opt]=1
case $opt in
a) # If the path is automounted, [[ -f ... ]] does not
# trigger a mount so we may get a false error.
ls "$OPTARG" >/dev/null 2>&1
[[ -f $OPTARG ]] || fatal "$f_arg_not_file" "$OPTARG"
inst_type="archive"
install_media="$OPTARG"
;;
c) ls "$OPTARG" >/dev/null 2>&1
[[ -f $OPTARG ]] || [[ -d $OPTARG ]] ||
fatal "$f_arg_not_file_or_dir" "$OPTARG"
sc_config="$OPTARG"
a_push ATTACH_Z_COMMAND -c "$OPTARG"
;;
d) # If the path is automounted, [[ -d ... ]] does not
# trigger a mount so we may get a false error.
ls "$OPTARG" >/dev/null 2>&1
[[ -d $OPTARG ]] || fatal "$f_arg_not_dir" "$OPTARG"
inst_type="directory"
install_media="$OPTARG"
;;
n) noexecute=1
EXIT_NOEXECUTE=1
dryrun_mfst=$OPTARG
;;
u) [[ $allow_update == all ]] && \
fatal "$f_bad_opt_combo" u U
[[ $allow_update == min ]] && \
fatal "$f_repeated_opt" u
allow_update=min
a_push ATTACH_Z_COMMAND -u
;;
U)
[[ $allow_update == min ]] && \
fatal "$f_bad_opt_combo" u U
[[ $allow_update == all ]] && \
fatal "$f_repeated_opt" U
allow_update=all
a_push ATTACH_Z_COMMAND -U
;;
v) verbose=-v
OPT_V=1 # used for vlog()
;;
z) inst_type=zbe
install_media="$OPTARG"
;;
x) ;; # zoneadm only
?) fail_usage "" ;;
esac
done
shift $((OPTIND-1))
# Configuration profile file must have .xml suffix
if [[ -f $sc_config && $sc_config != *.xml ]]; then
fail_usage "$f_scxml" "$sc_config"
fi
if [[ -n ${opts[a]} && -n ${opts[d]} ]]; then
fail_usage "$f_incompat_options" a d
fi
if [[ -n ${opts[a]} && -n ${opts[z]} ]]; then
fail_usage "$f_incompat_options" a z
fi
if [[ -n ${opts[d]} && -n ${opts[z]} ]]; then
fail_usage "$f_incompat_options" d z
fi
get_current_gzbe
#
# Be sure that a previous attach -a didn't leave zbes behind.
#
if [[ $inst_type == archive || $inst_type == directory ]]; then
/usr/sbin/zfs list -Hro name,$PROP_CANDIDATE "${zone.ROOT_ds}" \
2>/dev/null | while IFS='$\t' read name candidate ; do
if [[ $candidate == "$CURRENT_GZBE" ]]; then
fatal "$f_multiple_extractions"
fi
done
# Advise that install is the better choice these days.
log "$m_use_install"
fi
[[ -z "$inst_type" ]] && inst_type="directory"
if [[ $noexecute == 1 ]]; then
#
# the zone doesn't have to exist when the -n option is used, so do
# this work early.
#
# LIXXX There is no sw validation for IPS right now, so just pretend
# everything will be ok.
# Exit handler not yet active, so no need to worry about it.
exit $ZONE_SUBPROC_OK
fi
trap trap_cleanup INT
trap trap_exit EXIT
EXIT_CODE=$ZONE_SUBPROC_TRYAGAIN
start_log zone attach "${save_args[@]}"
pin_datasets "${zone.path.ds}" || fatal "$f_pin"
enable_zones_services 1 || exit $EXIT_CODE
# Create a ZBE and transfer data into it.
attach_datasets -t "$inst_type" -m "$install_media" zone || exit $EXIT_CODE
log "$m_active_zbe" "${zone.active_ds}"
# Attach the image, perhaps with updates.
attach_image zone "$allow_update"
# Be sure that shared data that shouldn't be in in the ZBE isn't in the ZBE.
migrate_export zone
migrate_rpool zone
# Apply the sysconfig profile, if needed
[[ -n $sc_config ]] && reconfigure_zone "$sc_config"
trap - EXIT
unpin_datasets "${zone.path.ds}" || error "$f_unpin"
finish_log zone
exit $ZONE_SUBPROC_OK