# HG changeset patch # User Andrzej Szeszo # Date 1306930269 -3600 # Node ID 90c532b69592c1715f48902f67bbc8890cdd47f5 # Parent 30ea7b982e91d693d0138dde33632b968365b93e# Parent f1c659f5c28eaf38e3b85c6c49f5ea3ce21ebfea Merge diff -r 30ea7b982e91 -r 90c532b69592 src/brand/Makefile --- a/src/brand/Makefile Wed Jun 01 13:04:21 2011 +0100 +++ b/src/brand/Makefile Wed Jun 01 13:11:09 2011 +0100 @@ -20,7 +20,7 @@ # # -# Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # MACH:sh = uname -p @@ -58,7 +58,6 @@ $(ROOTBRANDPKG)/poststate \ $(ROOTBRANDPKG)/prestate \ $(ROOTBRANDPKG)/support \ - $(ROOTBRANDPKG)/sysboot \ $(ROOTBRANDPKG)/uninstall ROOTFILES = \ diff -r 30ea7b982e91 -r 90c532b69592 src/brand/attach --- a/src/brand/attach Wed Jun 01 13:04:21 2011 +0100 +++ b/src/brand/attach Wed Jun 01 13:11:09 2011 +0100 @@ -97,20 +97,15 @@ # Restore the zone properties for the pre-existing # dataset. if [[ -n "$ACTIVE_DS" ]]; then - zfs set canmount=off $ACTIVE_DS - (( $? != 0 )) && error "$f_ds_config" \ - "$ACTIVE_DS" "canmount=on" zfs set zoned=off $ACTIVE_DS (( $? != 0 )) && error "$f_ds_config" \ "$ACTIVE_DS" "zoned=off" + zfs set canmount=on $ACTIVE_DS + (( $? != 0 )) && error "$f_ds_config" \ + "$ACTIVE_DS" "canmount=on" zfs set mountpoint=$ZONEROOT $ACTIVE_DS (( $? != 0 )) && error "$f_ds_config" \ "$ACTIVE_DS" "mountpoint=$ZONEROOT" - zfs set canmount=on $ACTIVE_DS - (( $? != 0 )) && error "$f_ds_config" \ - "$ACTIVE_DS" "canmount=on" - zfs mount "$ACTIVE_DS" || \ - error "$e_mount1_failed" "$ACTIVE_DS" fi fi log "$m_failed" @@ -125,19 +120,27 @@ trap trap_cleanup INT trap trap_exit EXIT +<<<<<<< local PKG=pkg +======= +#set -o xtrace + +PKG="/usr/bin/pkg" +>>>>>>> other KEYDIR=/var/pkg/ssl # 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) +ZONENAME="$1" +ZONEPATH="$2" +# XXX shared/common script currently uses lower case zonename & zonepath +zonename="$ZONENAME" +zonepath="$ZONEPATH" shift; shift # remove ZONENAME and ZONEPATH from arguments array +ZONEROOT="$ZONEPATH/root" logdir="$ZONEROOT/var/log" # @@ -161,7 +164,184 @@ typeset gz_incorporations="" # +<<<<<<< local verbose="" +======= +# Gather the zone publisher details. $1 is the location of the image we +# are processing and $2 is an associative array used to store publisher +# details. +# +gather_zone_publisher_details() { + STORED_IMAGE=$PKG_IMAGE + PKG_IMAGE=$1;export PKG_IMAGE + typeset -n publishers=$2 + typeset -li publisher_count=0 + typeset -li url_count=0 + typeset line= + typeset name= + typeset mirror= + typeset origin= + typeset opublisher= + + # + # Store publisher, origin and security details. It is assumed + # that mirrors all use the same key as the origins. + # + for line in $(get_publisher_urls all origin); do + print $line | IFS="=" read name origin + # When a publisher has multiple origins, the + # additional origins don't contain the publisher + # name. Correct for this by checking if origin is not + # set by get_publisher_urls() and, if so, use the + # "name" as the origin and set the name to the value + # we have already saved. + if [[ -z $origin ]]; then + origin=$name + name=${publisher.name} + elif [[ "$origin" == "None" ]]; then + # Publisher with no origins. + origin="" + fi + + # Use a compound variable to store all the data + # relating to a publisher. + if [[ -z ${publishers[$name]} ]]; then + typeset -C publisher_$publisher_count + typeset -n publisher=publisher_$publisher_count + typeset publisher.sticky="" + typeset publisher.preferred="" + typeset publisher.enabled="" + typeset -a publisher.origins="" + typeset -a publisher.mirrors="" + typeset publisher.name=$name + typeset publisher.keyfile="" + typeset publisher.certfile="" + + get_publisher_attrs ${publisher.name} origin | \ + IFS=" " read publisher.sticky publisher.preferred \ + publisher.enabled + if [[ -n "$origin" ]]; then + get_pub_secinfo ${publisher.name} | \ + read publisher.keyfile publisher.certfile + [[ ${publisher.keyfile} != "None" && \ + ! -f ${PKG_IMAGE}/${publisher.keyfile} ]] && \ + fail_usage "$f_nosuch_key" \ + ${publisher.keyfile} + [[ ${publisher.certfile} != "None" && \ + ! -f ${PKG_IMAGE}/${publisher.certfile} ]] && \ + fail_usage "$f_nosuch_cert" \ + ${publisher.certfile} + else + # Publisher has no origins. + publisher.keyfile="None" + publisher.certfile="None" + fi + publisher_count=publisher_count+1 + url_count=0 + fi + publisher.origins[$url_count]=$origin + publishers[$name]=${publisher} + url_count=url_count+1 + done + + # + # Store mirror details + # + url_count=0 + for line in $(get_publisher_urls all mirror); do + print $line | IFS="=" read name mirror + if [[ -z $mirror ]]; then + mirror=$name + name=${publisher.name} + fi + if [[ -z $opublisher || $opublisher != $name ]]; then + opublisher=$name + eval publisher="${publishers[$name]}" + url_count=0 + fi + publisher.mirrors[$url_count]=$mirror + publishers[$name]=${publisher} + url_count=url_count+1 + done + + PKG_IMAGE=$STORED_IMAGE;export PKG_IMAGE +} + +# +# $1 is an associative array of publishers. Search this array and +# return the preferred publisher. +# +get_preferred_publisher() { + typeset -n publishers=$1 + typeset publisher= + + for key in ${!publishers[*]}; do + eval publisher="${publishers[$key]}" + if [[ ${publisher.preferred} == "true" ]]; then + print ${key} + return 0 + fi + done + return 1 +} + +# +# $1 is an empty string to be populated with a list of incorporation +# fmris. +# +gather_incorporations() { + typeset -n incorporations=$1 + typeset p= + + for p in \ + $(LC_ALL=C $PKG search -Hl -o pkg.name \ + ':pkg.depend.install-hold:core-os*');do + incorporations="$incorporations $(get_pkg_fmri $p)" + done +} + +# +# Print the pkg(1) command which defines a publisher. $1 is an associative +# array of publisher details and $2 is the publisher to be printed. +# +print_publisher_pkg_defn() { + typeset -n publishers=$1 + typeset pname=$2 + typeset publisher= + typeset args="" + typeset origin= + typeset mirror= + + eval publisher="${publishers[$pname]}" + + if [[ ${publisher.preferred} == "true" ]]; then + args="$args -P" + fi + + for origin in ${publisher.origins[*]}; do + args="$args -g $origin" + done + + for mirror in ${publisher.mirrors[*]}; do + args="$args -m $mirror" + done + + if [[ ${publisher.sticky} == "true" ]]; then + args="$args --sticky" + else + args="$args --non-sticky" + fi + + if [[ ${publisher.enabled} == "true" ]]; then + args="$args --enable" + else + args="$args --disable" + fi + + echo "$args" +} + +>>>>>>> other # Other brand attach options are invalid for this brand. while getopts "a:d:n:r:uv" opt; do case $opt in @@ -224,17 +404,125 @@ exit $ZONE_SUBPROC_NOTCOMPLETE fi -LOGFILE=$(/usr/bin/mktemp -t -p /var/tmp ${zone.name}.attach_log.XXXXXX) +LOGFILE=$(/usr/bin/mktemp -t -p /var/tmp $ZONENAME.attach_log.XXXXXX) if [[ -z "$LOGFILE" ]]; then fatal "$e_tmpfile" fi exec 2>>"$LOGFILE" + log "$m_attach_log" "$LOGFILE" -# Remember what was mounted on the zone root in case the attach fails. -get_ds_from_path "${zone.root}" ACTIVE_DS -attach_datasets -t "$inst_type" -m "$install_media" zone -migrate_export zone +# +# TODO - once sxce is gone, move the following block into +# usr/lib/brand/shared/common.ksh code to share with other brands using +# the same zfs dataset logic for attach. This currently uses get_current_gzbe +# so we can't move it yet since beadm isn't in sxce. +# + +# Validate that the zonepath is not in the root dataset. +pdir=`dirname $ZONEPATH` +get_zonepath_ds $pdir +fail_zonepath_in_rootds $ZONEPATH_DS + +EXIT_CODE=$ZONE_SUBPROC_NOTCOMPLETE + +if [[ "$install_media" == "-" ]]; then + # + # Since we're using a pre-existing dataset, the dataset currently + # mounted on the {zonepath}/root becomes the active dataset. We + # can't depend on the usual dataset attributes to detect this since + # the dataset could be a detached zone or one that the user set up by + # hand and lacking the proper attributes. However, since the zone is + # not attached yet, the 'install_media == -' means the dataset must be + # mounted at this point. + # + ACTIVE_DS=`mount -p | nawk -v zroot=$ZONEROOT '{ + if ($3 == zroot && $4 == "zfs") + print $1 + }'` + + [[ -z "$ACTIVE_DS" ]] && fatal "$f_no_active_ds_mounted" $ZONEROOT + + # Set up proper attributes on the ROOT dataset. + get_zonepath_ds $ZONEPATH + zfs list -H -t filesystem -o name $ZONEPATH_DS/ROOT >/dev/null 2>&1 + (( $? != 0 )) && fatal "$f_no_active_ds" + + # need to ensure zoned is off to set mountpoint=legacy. + zfs set zoned=off $ZONEPATH_DS/ROOT + (( $? != 0 )) && fatal "$f_ds_config" $ZONEPATH_DS/ROOT "zoned=off" + + zfs set mountpoint=legacy $ZONEPATH_DS/ROOT + (( $? != 0 )) && fatal "$f_ds_config" $ZONEPATH_DS/ROOT \ + "mountpoint=legacy" + zfs set zoned=on $ZONEPATH_DS/ROOT + (( $? != 0 )) && fatal "$f_ds_config" $ZONEPATH_DS/ROOT "zoned=on" + + # + # We're typically using a pre-existing mounted dataset so setting the + # following propery changes will cause the {zonepath}/root dataset to + # be unmounted. However, a p2v with an update-on-attach will have + # created the dataset with the correct properties, so setting these + # attributes won't unmount the dataset. Thus, we check the mount + # and attempt the remount if necessary. + # + get_current_gzbe + zfs set $PROP_PARENT=$CURRENT_GZBE $ACTIVE_DS + (( $? != 0 )) && fatal "$f_ds_config" $ACTIVE_DS \ + "$PROP_PARENT=$CURRENT_GZBE" + zfs set $PROP_ACTIVE=on $ACTIVE_DS + (( $? != 0 )) && fatal "$f_ds_config" $ACTIVE_DS "$PROP_ACTIVE=on" + zfs set canmount=noauto $ACTIVE_DS + (( $? != 0 )) && fatal "$f_ds_config" $ACTIVE_DS "canmount=noauto" + zfs set zoned=off $ACTIVE_DS + (( $? != 0 )) && fatal "$f_ds_config" $ACTIVE_DS "zoned=off" + zfs inherit mountpoint $ACTIVE_DS + (( $? != 0 )) && fatal "$f_ds_config" $ACTIVE_DS "'inherit mountpoint'" + zfs inherit zoned $ACTIVE_DS + (( $? != 0 )) && fatal "$f_ds_config" $ACTIVE_DS "'inherit zoned'" + + mounted_ds=`mount -p | nawk -v zroot=$ZONEROOT '{ + if ($3 == zroot && $4 == "zfs") + print $1 + }'` + + if [[ -z $mounted_ds ]]; then + mount -F zfs $ACTIVE_DS $ZONEROOT || fatal "$f_zfs_mount" + fi +else + # + # Since we're not using a pre-existing ZFS dataset layout, create + # the zone datasets and mount them. Start by creating the zonepath + # dataset, similar to what zoneadm would do for an initial install. + # + zds=$(zfs list -H -t filesystem -o name $pdir 2>/dev/null) + if (( $? == 0 )); then + pnm=$(/usr/bin/basename $ZONEPATH) + # The zonepath dataset might already exist. + zfs list -H -t filesystem -o name $zds/$pnm >/dev/null 2>&1 + if (( $? != 0 )); then + zfs create "$zds/$pnm" + (( $? != 0 )) && fatal "$f_zfs_create" + vlog "$m_zfs" + fi + fi + + create_active_ds +fi + +# +# The zone's datasets are now in place. +# + +log "$m_attach_root" "$ZONEROOT" +# note \n to add whitespace +log "$m_attach_ds\n" "$ACTIVE_DS" + +install_image "$inst_type" "$install_media" + +# +# End of TODO block to move to common code. +# # # Perform a sanity check to confirm that the image is not a global zone. diff -r 30ea7b982e91 -r 90c532b69592 src/brand/clone --- a/src/brand/clone Wed Jun 01 13:04:21 2011 +0100 +++ b/src/brand/clone Wed Jun 01 13:11:09 2011 +0100 @@ -19,7 +19,9 @@ # # CDDL HEADER END # -# Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # . /usr/lib/brand/ipkg/common.ksh @@ -30,7 +32,7 @@ # Clean up on failure trap_exit() { - if (( ZONE_IS_MOUNTED != 0 )); then + if (( $ZONE_IS_MOUNTED != 0 )); then error "$v_unmount" zoneadm -z $ZONENAME unmount fi @@ -38,39 +40,108 @@ exit $ZONE_SUBPROC_INCOMPLETE } -# Source and destination zones -typeset src dst +# Set up ZFS dataset hierarchy for the zone. + +ROOT="rpool/ROOT" + # Other brand clone options are invalid for this brand. while getopts "R:z:" opt; do case $opt in - R) opt_R="$OPTARG" ;; - z) opt_z="$OPTARG" ;; + R) ZONEPATH="$OPTARG" ;; + z) ZONENAME="$OPTARG" ;; *) fail_usage "";; esac done shift $((OPTIND-1)) -if (($# != 1)); then +if [ $# -ne 1 ]; then fail_usage ""; fi -init_zone dst "$opt_z" "$opt_R" -init_zone src "$1" +sourcezone=$1 + +# Find the active source zone dataset to clone. +sourcezonepath=`/usr/sbin/zoneadm -z $sourcezone list -p | awk -F: '{print $4}'` +if [ -z "$sourcezonepath" ]; then + fail_fatal "$f_nosource" +fi get_current_gzbe -get_active_be src || fatal "$e_no_active_be" +get_zonepath_ds $sourcezonepath +get_active_ds $CURRENT_GZBE $ZONEPATH_DS + +# +# Now set up the zone's datasets +# + +# +# First make the top-level dataset. +# + +pdir=`/usr/bin/dirname $ZONEPATH` +zpname=`/usr/bin/basename $ZONEPATH` -# From here on out the global variables referenced are for the destination zone -eval $(bind_legacy_zone_globals dst) +get_zonepath_ds $pdir +zpds=$ZONEPATH_DS + +fail_zonepath_in_rootds $zpds + +# +# We need to tolerate errors while creating the datasets and making the +# mountpoint, since these could already exist from some other BE. +# + +/usr/sbin/zfs create $zpds/$zpname + +/usr/sbin/zfs create -o mountpoint=legacy -o zoned=on $zpds/$zpname/ROOT -# Make dataset snapshots -snapshot_zone_rpool src "${dst}_snap%02d" snapname \ - || fail_incomplete "$f_zfs_snapshot" +# make snapshot +SNAPNAME=${ZONENAME}_snap +SNAPNUM=0 +while [ $SNAPNUM -lt 100 ]; do + /usr/sbin/zfs snapshot $ACTIVE_DS@$SNAPNAME + if [ $? = 0 ]; then + break + fi + SNAPNUM=`expr $SNAPNUM + 1` + SNAPNAME="${ZONENAME}_snap$SNAPNUM" +done + +if [ $SNAPNUM -ge 100 ]; then + fail_fatal "$f_zfs_create" +fi -# Make dataset clones -clone_zone_rpool src dst "$snapname" || fail_incomplete "$f_zone_clone" +# do clone +BENAME=zbe +BENUM=0 +while [ $BENUM -lt 100 ]; do + /usr/sbin/zfs clone $ACTIVE_DS@$SNAPNAME $zpds/$zpname/ROOT/$BENAME + if [ $? = 0 ]; then + break + fi + BENUM=`expr $BENUM + 1` + BENAME="zbe-$BENUM" +done + +if [ $BENUM -ge 100 ]; then + fail_fatal "$f_zfs_create" +fi -ZONE_IS_MOUNTED=1 +/usr/sbin/zfs set $PROP_ACTIVE=on $zpds/$zpname/ROOT/$BENAME || \ + fail_incomplete "$f_zfs_create" + +/usr/sbin/zfs set $PROP_PARENT=$CURRENT_GZBE $zpds/$zpname/ROOT/$BENAME || \ + fail_incomplete "$f_zfs_create" + +/usr/sbin/zfs set canmount=noauto $zpds/$zpname/ROOT/$BENAME || \ + fail_incomplete "$f_zfs_create" + +if [ ! -d $ZONEPATH/root ]; then + /usr/bin/mkdir -p $ZONEPATH/root + /usr/bin/chmod 700 $ZONEPATH +fi + +ZONE_IS_MOUNTED=0 trap trap_exit EXIT # diff -r 30ea7b982e91 -r 90c532b69592 src/brand/common.ksh --- a/src/brand/common.ksh Wed Jun 01 13:04:21 2011 +0100 +++ b/src/brand/common.ksh Wed Jun 01 13:11:09 2011 +0100 @@ -23,20 +23,14 @@ # Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. # -# -# Only change PATH if you give full consideration to GNU or other variants -# of common commands having different arguments and output. Setting PATH is -# and not using the full path to executables provides a performance improvement -# by using the ksh builtin equivalent of many common commands. -# -export PATH=/usr/bin:/usr/sbin unset LD_LIBRARY_PATH +PATH=/usr/bin:/usr/sbin +export PATH . /usr/lib/brand/shared/common.ksh PROP_PARENT="org.opensolaris.libbe:parentbe" PROP_ACTIVE="org.opensolaris.libbe:active" -PROP_BE_HANDLE="com.oracle.libbe:nbe_handle" f_incompat_options=$(gettext "cannot specify both %s and %s options") f_sanity_detail=$(gettext "Missing %s at %s") @@ -46,8 +40,10 @@ sanity_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.") install_fail=$(gettext " Result: *** Installation FAILED ***") f_zfs_in_root=$(gettext "Installing a zone inside of the root pool's 'ROOT' dataset is unsupported.") +f_zfs_create=$(gettext "Unable to create the zone's ZFS dataset.") f_root_create=$(gettext "Unable to create the zone's ZFS dataset mountpoint.") f_no_gzbe=$(gettext "unable to determine global zone boot environment.") +f_no_ds=$(gettext "the zonepath must be a ZFS dataset.\nThe parent directory of the zonepath must be a ZFS dataset so that the\nzonepath ZFS dataset can be created properly.") f_multiple_ds=$(gettext "multiple active datasets.") f_no_active_ds=$(gettext "no active dataset.") f_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") @@ -77,8 +73,23 @@ m_postnote=$(gettext " Next Steps: Boot the zone, then log into the zone console (zlogin -C)") m_postnote2=$(gettext " to complete the configuration process.") +fail_incomplete() { + printf "ERROR: " 1>&2 + printf "$@" 1>&2 + printf "\n" 1>&2 + exit $ZONE_SUBPROC_NOTCOMPLETE +} + +fail_usage() { + printf "$@" 1>&2 + printf "\n" 1>&2 + printf "$m_brnd_usage" 1>&2 + printf "$m_usage\n" 1>&2 + exit $ZONE_SUBPROC_USAGE +} + is_brand_labeled() { - if [[ -z $ALTROOT ]]; then + if [ -z $ALTROOT ]; then AR_OPTIONS="" else AR_OPTIONS="-R $ALTROOT" @@ -135,7 +146,7 @@ vlog "$sanity_ok" } -function get_current_gzbe { +get_current_gzbe() { # # If there is no alternate root (normal case) then set the # global zone boot environment by finding the boot environment @@ -143,97 +154,156 @@ # If a zone exists in a boot environment mounted on an alternate root, # then find the boot environment where the alternate root is mounted. # - CURRENT_GZBE=$(beadm list -H | nawk -v alt=$ALTROOT -F\; '{ - if (length(alt) == 0) { - # Field 3 is the BE status. 'N' is the active BE. - if ($3 !~ "N") - next - } else { - # Field 4 is the BE mountpoint. - if ($4 != alt) - next + if [ -x /usr/sbin/beadm ]; then + CURRENT_GZBE=`/usr/sbin/beadm list -H | /usr/bin/nawk \ + -v alt=$ALTROOT -F\; '{ + if (length(alt) == 0) { + # Field 3 is the BE status. 'N' is the active BE. + if ($3 !~ "N") + next + } else { + # Field 4 is the BE mountpoint. + if ($4 != alt) + next + } + # Field 2 is the BE UUID + print $2 + }'` + else + # If there is no beadm command then the system doesn't really + # support multiple boot environments. We still want zones to + # work so simulate the existence of a single boot environment. + CURRENT_GZBE="opensolaris" + fi + + if [ -z "$CURRENT_GZBE" ]; then + fail_fatal "$f_no_gzbe" + fi +} + +# Find the active dataset under the zonepath dataset to mount on zonepath/root. +# $1 CURRENT_GZBE +# $2 ZONEPATH_DS +get_active_ds() { + ACTIVE_DS=`/usr/sbin/zfs list -H -r -t filesystem \ + -o name,$PROP_PARENT,$PROP_ACTIVE $2/ROOT | \ + /usr/bin/nawk -v gzbe=$1 ' { + if ($1 ~ /ROOT\/[^\/]+$/ && $2 == gzbe && $3 == "on") { + print $1 + if (found == 1) + exit 1 + found = 1 } - # Field 2 is the BE UUID - print $2 - }') - if [ -z "$CURRENT_GZBE" ]; then - return 1 + }'` + + if [ $? -ne 0 ]; then + fail_fatal "$f_multiple_ds" + fi + + if [ -z "$ACTIVE_DS" ]; then + fail_fatal "$f_no_active_ds" fi - return 0 +} + +# Check that zone is not in the ROOT dataset. +fail_zonepath_in_rootds() { + case $1 in + rpool/ROOT/*) + fail_fatal "$f_zfs_in_root" + break; + ;; + *) + break; + ;; + esac } # -# get_active_be zone -# -# Finds the active boot environment for the given zone. -# -# Arguments: -# -# zone zone structure initialized with init_zone -# -# Globals: -# -# CURRENT_GZBE Current global zone boot environment. If not already set, -# it will be set. -# -# Returns: -# -# 0 on success, else 1. +# Make sure the active dataset is mounted for the zone. There are several +# cases to consider: +# 1) First boot of the zone, nothing is mounted +# 2) Zone is halting, active dataset remains the same. +# 3) Zone is halting, there is a new active dataset to mount. # -function get_active_be { - typeset -n zone=$1 - typeset active_ds= - typeset tab=$(printf "\t") - - [[ -z "$CURRENT_GZBE" ]] && get_current_gzbe - - typeset name parent active - zfs list -H -r -d 1 -t filesystem -o name,$PROP_PARENT,$PROP_ACTIVE \ - ${zone.ROOT_ds} | while IFS=$tab read name parent active ; do - [[ $parent == "$CURRENT_GZBE" ]] || continue - [[ $active == on ]] || continue - vlog "Found active dataset %s" "$name" - if [[ -n "$active_ds" ]] ; then - error "$f_multiple_ds" - return 1 +mount_active_ds() { + mount -p | cut -d' ' -f3 | egrep -s "^$ZONEPATH/root$" + if (( $? == 0 )); then + # Umount current dataset on the root (it might be an old BE). + umount $ZONEPATH/root + if (( $? != 0 )); then + # The umount failed, leave the old BE mounted. + # Warn about gz process preventing umount. + printf "$f_zfs_unmount" "$ZONEPATH/root" + return fi - active_ds=$name - done - if [[ -z $active_ds ]]; then - error "$f_no_active_ds" - return 1 fi - zone.active_ds=$active_ds + # Mount active dataset on the root. + get_current_gzbe + get_zonepath_ds $ZONEPATH + get_active_ds $CURRENT_GZBE $ZONEPATH_DS + + mount -F zfs $ACTIVE_DS $ZONEPATH/root || fail_fatal "$f_zfs_mount" } -function set_active_be { - typeset -n zone="$1" - typeset be="$2" +# +# Set up ZFS dataset hierarchy for the zone root dataset. +# +create_active_ds() { + get_current_gzbe - [[ -z "$CURRENT_GZBE" ]] && get_current_gzbe + # + # Find the zone's current dataset. This should have been created by + # zoneadm. + # + get_zonepath_ds $zonepath + + # Check that zone is not in the ROOT dataset. + fail_zonepath_in_rootds $ZONEPATH_DS + + # + # From here on, errors should cause the zone to be incomplete. + # + int_code=$ZONE_SUBPROC_FATAL # - # Turn off the active property on BE's with the same GZBE + # We need to tolerate errors while creating the datasets and making the + # mountpoint, since these could already exist from some other BE. # - zfs list -H -r -d 1 -t filesystem -o name,$PROP_PARENT,$PROP_ACTIVE \ - ${zone.ROOT_ds} | while IFS=$tab read name parent active ; do - [[ $parent == "$CURRENT_GZBE" ]] || continue - [[ $active == on ]] || continue - [[ $name == "${zone.ROOT_ds}/$be" ]] && continue - vlog "Deactivating active dataset %s" "$name" - zfs set $PROP_ACTIVE=off "$name" || return 1 + + /usr/sbin/zfs list -H -o name $ZONEPATH_DS/ROOT >/dev/null 2>&1 + if (( $? != 0 )); then + /usr/sbin/zfs create -o mountpoint=legacy \ + -o zoned=on $ZONEPATH_DS/ROOT + if (( $? != 0 )); then + fail_fatal "$f_zfs_create" + fi + fi + + BENAME=zbe + BENUM=0 + # Try 100 different names before giving up. + while [ $BENUM -lt 100 ]; do + /usr/sbin/zfs create -o $PROP_ACTIVE=on \ + -o $PROP_PARENT=$CURRENT_GZBE \ + -o canmount=noauto $ZONEPATH_DS/ROOT/$BENAME >/dev/null 2>&1 + if (( $? == 0 )); then + break + fi + BENUM=`expr $BENUM + 1` + BENAME="zbe-$BENUM" done - zone.active_ds="${zone.ROOT_ds}/$be" + if [ $BENUM -ge 100 ]; then + fail_fatal "$f_zfs_create" + fi - zfs set "$PROP_PARENT=$CURRENT_GZBE" ${zone.active_ds} \ - || return 1 - zfs set "$PROP_ACTIVE=on" ${zone.active_ds} || return 1 + if [ ! -d $ZONEROOT ]; then + /usr/bin/mkdir $ZONEROOT + fi - zfs set "$PROP_BE_HANDLE=on" "${zone.rpool_ds}" || return 1 - - return 0 + /usr/sbin/mount -F zfs $ZONEPATH_DS/ROOT/$BENAME $ZONEROOT || \ + fail_incomplete "$f_zfs_mount" } # diff -r 30ea7b982e91 -r 90c532b69592 src/brand/detach --- a/src/brand/detach Wed Jun 01 13:04:21 2011 +0100 +++ b/src/brand/detach Wed Jun 01 13:11:09 2011 +0100 @@ -24,33 +24,61 @@ # Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. # + . /usr/lib/brand/ipkg/common.ksh m_usage=$(gettext "detach [-n ].") +f_mount=$(gettext "Error: error mounting zone root dataset.") +f_ds_config=$(gettext "Failed to configure dataset %s: could not set %s.") + noexecute=0 # Other brand detach options are invalid for this brand. while getopts "nR:z:" opt; do case $opt in n) noexecute=1 ;; - R) ZONEPATH="$OPTARG" ;; - z) ZONENAME="$OPTARG" ;; + R) zonepath="$OPTARG" ;; + z) zonename="$OPTARG" ;; ?) fail_usage "" ;; *) fail_usage "";; esac done shift $((OPTIND-1)) -init_zone zone "$ZONENAME" "$ZONEPATH" -eval $(bind_legacy_zone_globals zone) - -if (( $noexecute == 1 )); then - cat /etc/zones/$ZONENAME.xml +if [ $noexecute -eq 1 ]; then + # dry-run - output zone's config and exit + cat /etc/zones/$zonename.xml exit $ZONE_SUBPROC_OK fi -# All of the hard stuff is done in commmon code. -detach_zone zone +# +# Detaching +# +# Leave the active dataset mounted on the zone's rootpath for ease of +# migration. +# +get_current_gzbe +get_zonepath_ds $zonepath +get_active_ds $CURRENT_GZBE $ZONEPATH_DS + +/usr/sbin/zfs set zoned=off $ACTIVE_DS || \ + fail_incomplete "$f_ds_config" "$ACTIVE_DS" "zoned=off" + +/usr/sbin/zfs set canmount=on $ACTIVE_DS || \ + fail_incomplete "$f_ds_config" "$ACTIVE_DS" "canmount=on" + +# +# This mounts the dataset. +# XXX do we have to worry about subsidiary datasets? +# +/usr/sbin/zfs set mountpoint=$zonepath/root $ACTIVE_DS || \ + fail_incomplete "$f_ds_config" "$ACTIVE_DS" "mountpoint=$zonepath/root" + +# +# There is no sw inventory in an ipkg branded zone, so just use the original +# xml file. +# +cp /etc/zones/$zonename.xml $zonepath/SUNWdetached.xml exit $ZONE_SUBPROC_OK diff -r 30ea7b982e91 -r 90c532b69592 src/brand/image_install --- a/src/brand/image_install Wed Jun 01 13:04:21 2011 +0100 +++ b/src/brand/image_install Wed Jun 01 13:11:09 2011 +0100 @@ -19,9 +19,8 @@ # # CDDL HEADER END # - -# -# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # # @@ -101,8 +100,14 @@ # If we weren't passed at least two arguments, exit now. (( $# < 2 )) && exit $ZONE_SUBPROC_USAGE -init_zone zone "$1" "$2" -eval $(bind_legacy_zone_globals zone) +ZONENAME="$1" +ZONEPATH="$2" +# XXX shared/common script currently uses lower case zonename & zonepath +zonename="$ZONENAME" +zonepath="$ZONEPATH" + +ZONEROOT="$ZONEPATH/root" + shift; shift # remove zonename and zonepath from arguments array unset inst_type @@ -202,7 +207,8 @@ if (( $p2v_result != 0 )); then log "$p2v_fail" - log "\n$install_fail" + log "" + log "$install_fail" log "$install_log" "$LOGFILE" exit $ZONE_SUBPROC_FATAL fi @@ -221,9 +227,10 @@ # Mount active dataset on the root. is_brand_labeled -(( $? == 0 )) && mount_active_be -c zone +(( $? == 0 )) && mount_active_ds -log "\n$m_complete" ${SECONDS} +log "" +log "$m_complete" ${SECONDS} printf "$install_log\n" "$ZONEROOT/var/log/$ZONENAME.install$$.log" printf "$m_postnote\n" printf "$m_postnote2\n" diff -r 30ea7b982e91 -r 90c532b69592 src/brand/p2v --- a/src/brand/p2v Wed Jun 01 13:04:21 2011 +0100 +++ b/src/brand/p2v Wed Jun 01 13:11:09 2011 +0100 @@ -28,13 +28,9 @@ # zone, so care should be taken to validate any modifications so that they # are safe. -# -# Only change PATH if you give full consideration to GNU or other variants -# of common commands having different arguments and output. Setting PATH is -# and not using the full path to executables provides a performance improvement -# by using the ksh builtin equivalent of many common commands. -# -export PATH=/usr/bin:/usr/sbin +# Restrict executables to /usr/bin and /usr/sbin +PATH=/usr/bin:/usr/sbin +export PATH unset LD_LIBRARY_PATH . /usr/lib/brand/ipkg/common.ksh @@ -355,8 +351,10 @@ (( $# != 2 )) && exit 1 [[ -n $LOGFILE ]] && exec 2>>$LOGFILE -init_zone zone "$1" "$2" -eval $(bind_legacy_zone_globals zone) + +ZONENAME=$1 +ZONEPATH=$2 +ZONEROOT=$ZONEPATH/root e_badinfo=$(gettext "Failed to get '%s' zone resource") e_badfile=$(gettext "Invalid '%s' file within the zone") @@ -468,7 +466,7 @@ if (( $brand_labeled == 1 )); then # The labeled brand needs to mount the zone's root dataset back onto # ZONEROOT so we can finish processing. - mount_active_be zone + mount_active_ds fi # @@ -504,7 +502,7 @@ [[ -n $OPT_U ]] && unconfigure_zone -(( $brand_labeled == 1 )) && mount_active_be zone +(( $brand_labeled == 1 )) && mount_active_ds trap - EXIT vlog "$v_exitgood" diff -r 30ea7b982e91 -r 90c532b69592 src/brand/pkgcreatezone --- a/src/brand/pkgcreatezone Wed Jun 01 13:04:21 2011 +0100 +++ b/src/brand/pkgcreatezone Wed Jun 01 13:11:09 2011 +0100 @@ -58,10 +58,10 @@ trap_cleanup() { print "$f_interrupted" - exit $EXIT_CODE + exit $int_code } -EXIT_CODE=$ZONE_SUBPROC_NOTCOMPLETE +int_code=$ZONE_SUBPROC_NOTCOMPLETE trap trap_cleanup INT extra_packages="" @@ -109,13 +109,17 @@ print -u2 "Brand error: No zone path or name" exit $ZONE_SUBPROC_USAGE fi -zone= -init_zone zone "$ZONENAME" "$ZONEPATH" -eval $(bind_legacy_zone_globals zone) + +# XXX shared/common script currently uses lower case zonename & zonepath +zonename="$ZONENAME" +zonepath="$ZONEPATH" is_brand_labeled brand_labeled=$? +ZONEROOT=$ZONEPATH/root +secinfo="" + # An image install can't use both -a AND -d... [[ -n "$install_archive" && -n "$source_dir" ]] && fail_usage "$f_incompat_options" "-a" "-d" @@ -153,8 +157,7 @@ # Before installing the zone, set up ZFS dataset hierarchy for the zone root # dataset. # -create_active_ds zone || fail_fatal "$f_no_ds" -mount_active_be -c zone || fail_fatal "$f_no_ds" +create_active_ds # # If we're installing from an image, branch off to that installer. diff -r 30ea7b982e91 -r 90c532b69592 src/brand/poststate --- a/src/brand/poststate Wed Jun 01 13:04:21 2011 +0100 +++ b/src/brand/poststate Wed Jun 01 13:11:09 2011 +0100 @@ -21,7 +21,7 @@ # # -# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # . /usr/lib/brand/ipkg/common.ksh @@ -48,20 +48,17 @@ cmd=$4 ALTROOT=$5 -typeset zone -init_zone zone "$ZONENAME" "$ZONEPATH" -eval $(bind_legacy_zone_globals zone) - # If we're not halting the zone, then just return. if [ $cmd -eq 4 ]; then - is_brand_labeled # Note: return value is C-style, not shell-style + is_brand_labeled if (( $? == 0 )); then - # Leave the active boot environment mounted after halting (this - # might be a different dataset than what was mounted). - mount_active_be -c zone + # Leave the active dataset mounted after halting (this might be + # a different dataset than what was mounted). + mount_active_ds else # Umount dataset on the root. - unmount_be zone + zoneroot="$ZONEPATH/root" + umount $zoneroot || printf "$f_zfs_unmount" "$zoneroot" fi fi diff -r 30ea7b982e91 -r 90c532b69592 src/brand/prestate --- a/src/brand/prestate Wed Jun 01 13:04:21 2011 +0100 +++ b/src/brand/prestate Wed Jun 01 13:11:09 2011 +0100 @@ -18,10 +18,9 @@ # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END -# # -# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # . /usr/lib/brand/ipkg/common.ksh @@ -48,15 +47,10 @@ cmd=$4 ALTROOT=$5 -typeset zone -init_zone zone "$ZONENAME" "$ZONEPATH" -eval $(bind_legacy_zone_globals zone) - # If we're not readying the zone, then just return. -case $cmd in - 0) - mount_active_be zone || exit $ZONE_SUBPROC_NOTCOMPLETE - ;; -esac +if [ $cmd -eq 0 ]; then + # Mount active dataset on the root. + mount_active_ds +fi exit $ZONE_SUBPROC_OK diff -r 30ea7b982e91 -r 90c532b69592 src/brand/sysboot --- a/src/brand/sysboot Wed Jun 01 13:04:21 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -#!/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) 2011, Oracle and/or its affiliates. All rights reserved. -# - -. /usr/lib/brand/ipkg/common.ksh - -typeset zone -init_zone zone "$1" "$2" || { - error "Usage: %s zone zonepath" "$0" - exit $ZONE_SUBPROC_USAGE -} - -# Mount the active boot environment on the zoneroot. -mount_active_be -c zone || exit $ZONE_SUBPROC_NOTCOMPLETE - -enable_zones_services || exit $ZONE_SUBPROC_NOTCOMPLETE - -exit $ZONE_SUBPROC_OK diff -r 30ea7b982e91 -r 90c532b69592 src/brand/uninstall --- a/src/brand/uninstall Wed Jun 01 13:04:21 2011 +0100 +++ b/src/brand/uninstall Wed Jun 01 13:11:09 2011 +0100 @@ -19,10 +19,15 @@ # # CDDL HEADER END # +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# # -# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. +# get script name (bname) and path (dname) # +bname=`basename $0` # # common shell script functions @@ -33,13 +38,16 @@ # # options processing # - -# If we weren't passed at least two arguments, exit now. -(( $# < 2 )) && fail_fatal "$f_abort" - -typeset zone -init_zone zone "$1" "$2" -eval $(bind_legacy_zone_globals zone) +zonename=$1 +if [ -z "$zonename" ]; then + printf "$f_abort\n" >&2 + exit $ZONE_SUBPROC_FATAL +fi +zonepath=$2 +if [ -z "$zonepath" ]; then + printf "$f_abort" >&2 + exit $ZONE_SUBPROC_FATAL +fi shift 2 options="FhHnv" @@ -93,6 +101,7 @@ # # main # +zoneroot=$zonepath/root nop="" if [[ -n "$opt_n" ]]; then @@ -104,28 +113,49 @@ ZONE_SUBPROC_OK=$ZONE_SUBPROC_FATAL fi -# get_current_gzbe -get_current_gzbe || fail_fatal "$f_no_gzbe" +# +# We want uninstall to work in the face of various problems, such as a +# zone with no delegated root dataset or multiple active datasets, so we +# don't use the common functions. Instead, we do our own work here and +# are tolerant of errors. +# -# find all the zone BEs associated with this global zone BE. -typeset -a belist -if [[ -n "$CURRENT_GZBE" ]]; then - zfs list -H -t filesystem -o $PROP_PARENT,name -r -d 1 \ - ${zone.ROOT_ds} 2>/dev/null | while IFS=$'\t' read uid fs; do +# get_current_gzbe +CURRENT_GZBE=`/sbin/beadm list -H | /bin/nawk -F\; '{ + # Field 3 is the BE status. 'N' is the active BE. + if ($3 ~ "N") + # Field 2 is the BE UUID + print $2 + }'` + +if [ -z "$CURRENT_GZBE" ]; then + print "$f_no_gzbe" +fi - # Skip the ROOT dataset - [[ "$fs" == "${zone.ROOT_ds}" ]] && continue +uninstall_get_zonepath_ds +uninstall_get_zonepath_root_ds + +# find all the zone BEs datasets associated with this global zone BE. +unset fs_all +(( fs_all_c = 0 )) +if [ -n "$CURRENT_GZBE" ]; then + /sbin/zfs list -H -t filesystem -o $PROP_PARENT,name \ + -r $ZONEPATH_RDS | + while IFS=" " read uid fs; do - # - # match by PROP_PARENT uuid. If the uuid is not set ("-"), the - # BE is invalid (interrupted install?) and should be deleted. - # - if [[ $uid == "-" || $uid == "${CURRENT_GZBE}" ]] ; then - a_push belist "$(basename "$fs")" - fi + # only look at filesystems directly below $ZONEPATH_RDS + [[ "$fs" != ~()($ZONEPATH_RDS/+([^/])) ]] && + continue + + # match by PROP_PARENT uuid + [[ "$uid" != ${CURRENT_GZBE} ]] && + continue + + fs_all[$fs_all_c]=$fs + (( fs_all_c = $fs_all_c + 1 )) done fi -destroy_zone_datasets zone -b belist +destroy_zone_datasets exit $ZONE_SUBPROC_OK diff -r 30ea7b982e91 -r 90c532b69592 src/pkg/manifests/system%2Fzones%2Fbrand%2Fipkg.p5m --- a/src/pkg/manifests/system%2Fzones%2Fbrand%2Fipkg.p5m Wed Jun 01 13:04:21 2011 +0100 +++ b/src/pkg/manifests/system%2Fzones%2Fbrand%2Fipkg.p5m Wed Jun 01 13:11:09 2011 +0100 @@ -18,7 +18,7 @@ # # CDDL HEADER END # -# Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # set name=pkg.fmri value=pkg:/system/zones/brand/ipkg@$(PKGVERS) @@ -53,7 +53,6 @@ file path=usr/lib/brand/ipkg/prestate mode=0755 file path=usr/lib/brand/ipkg/smf_disable.lst file path=usr/lib/brand/ipkg/support mode=0755 -file path=usr/lib/brand/ipkg/sysboot mode=0755 file path=usr/lib/brand/ipkg/uninstall mode=0755 license cr_Oracle license=cr_Oracle legacy pkg=SUNWipkg-brand version=0.0.0