Home | History | Annotate | Download | only in zone
      1 #!/bin/ksh -p
      2 #
      3 # CDDL HEADER START
      4 #
      5 # The contents of this file are subject to the terms of the
      6 # Common Development and Distribution License (the "License").
      7 # You may not use this file except in compliance with the License.
      8 #
      9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10 # or http://www.opensolaris.org/os/licensing.
     11 # See the License for the specific language governing permissions
     12 # and limitations under the License.
     13 #
     14 # When distributing Covered Code, include this CDDL HEADER in each
     15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16 # If applicable, add the following below this CDDL HEADER, with the
     17 # fields enclosed by brackets "[]" replaced with your own identifying
     18 # information: Portions Copyright [yyyy] [name of copyright owner]
     19 #
     20 # CDDL HEADER END
     21 #
     22 # Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23 # Use is subject to license terms.
     24 #
     25 
     26 # NOTE: this script runs in the global zone and touches the non-global
     27 # zone, so care should be taken to validate any modifications so that they
     28 # are safe.
     29 
     30 . /usr/lib/brand/shared/common.ksh
     31 
     32 LOGFILE=
     33 MSG_PREFIX="p2v: "
     34 EXIT_CODE=1
     35 
     36 usage()
     37 {
     38 	echo "$0 [-s] [-m msgprefix] [-u] [-v] [-b patchid]* zonename" >&2
     39 	exit $EXIT_CODE
     40 }
     41 
     42 # Clean up on interrupt
     43 trap_cleanup()
     44 {
     45 	msg=$(gettext "Postprocessing cancelled due to interrupt.")
     46 	error "$msg"
     47 
     48 	if (( $zone_is_running != 0 )); then
     49 		error "$e_shutdown" "$ZONENAME"
     50 		/usr/sbin/zoneadm -z $ZONENAME halt
     51 	fi
     52 
     53 	exit $EXIT_CODE
     54 }
     55 
     56 #
     57 # For an exclusive stack zone, fix up the network configuration files.
     58 # We need to do this even if unconfiguring the zone so sys-unconfig works
     59 # correctly.
     60 #
     61 fix_net()
     62 {
     63 	[[ "$STACK_TYPE" == "shared" ]] && return
     64 
     65 	NETIF_CNT=$(/usr/bin/ls $ZONEROOT/etc/hostname.* 2>/dev/null | \
     66 	    /usr/bin/wc -l)
     67 	if (( $NETIF_CNT != 1 )); then
     68 		vlog "$v_nonetfix"
     69 		return
     70 	fi
     71 
     72 	NET=$(LC_ALL=C /usr/sbin/zonecfg -z $ZONENAME info net)
     73 	if (( $? != 0 )); then
     74 		error "$e_badinfo" "net"
     75 		return
     76 	fi
     77 
     78 	NETIF=$(echo $NET | /usr/bin/nawk '{
     79 		for (i = 1; i < NF; i++) {
     80 			if ($i == "physical:") {
     81 				if (length(net) == 0) {
     82 					i++
     83 					net = $i
     84 				} else {
     85 					multiple=1
     86 				}
     87 			}
     88 		}
     89 	}
     90 	END {	if (!multiple)
     91 			print net
     92 	}')
     93 
     94 	if [[ -z "$NETIF" ]]; then
     95 		vlog "$v_nonetfix"
     96 		return
     97 	fi
     98 
     99 	OLD_HOSTNET=$(/usr/bin/ls $ZONEROOT/etc/hostname.*)
    100 	if [[ "$OLD_HOSTNET" != "$ZONEROOT/etc/hostname.$NETIF" ]]; then
    101 		safe_move $OLD_HOSTNET $ZONEROOT/etc/hostname.$NETIF
    102 	fi
    103 }
    104 
    105 #
    106 # Disable all of the shares since the zone cannot be an NFS server.
    107 # Note that we disable the various instances of the svc:/network/shares/group
    108 # SMF service in the fix_smf function. 
    109 #
    110 fix_nfs()
    111 {
    112 	zonedfs=$ZONEROOT/etc/dfs
    113 
    114 	if [[ -h $zonedfs/dfstab || ! -f $zonedfs/dfstab ]]; then
    115 		error "$e_badfile" "/etc/dfs/dfstab"
    116 		return
    117 	fi
    118 
    119 	tmpfile=$(/usr/bin/mktemp -t -p /var/tmp)
    120 	if [[ -z "$tmpfile" ]]; then
    121 		error "$e_tmpfile"
    122 		return
    123 	fi
    124 
    125 	/usr/bin/nawk '{
    126 		if (substr($1, 0, 1) == "#") {
    127 			print $0
    128 		} else {
    129 			print "#", $0
    130 			modified=1
    131 		}
    132 	}
    133 	END {
    134 		if (modified == 1) {
    135 			printf("# Modified by p2v ")
    136 			system("/usr/bin/date")
    137 			exit 0
    138 		}
    139 		exit 1
    140 	}' $zonedfs/dfstab >>$tmpfile
    141 
    142 	if (( $? == 0 )); then
    143 		if [[ ! -f $zonedfs/dfstab.pre_p2v ]]; then
    144 			safe_copy $zonedfs/dfstab $zonedfs/dfstab.pre_p2v
    145 		fi
    146 		safe_copy $tmpfile $zonedfs/dfstab
    147 	fi
    148 	/usr/bin/rm -f $tmpfile
    149 }
    150 
    151 #
    152 # Comment out most of the old mounts since they are either unneeded or
    153 # likely incorrect within a zone.  Specific mounts can be manually 
    154 # reenabled if the corresponding device is added to the zone.
    155 #
    156 fix_vfstab()
    157 {
    158 	if [[ -h $ZONEROOT/etc/vfstab || ! -f $ZONEROOT/etc/vfstab ]]; then
    159 		error "$e_badfile" "/etc/vfstab"
    160 		return
    161 	fi
    162 
    163 	tmpfile=$(/usr/bin/mktemp -t -p /var/tmp)
    164 	if [[ -z "$tmpfile" ]]; then
    165 		error "$e_tmpfile"
    166 		return
    167 	fi
    168 
    169 	/usr/bin/nawk '{
    170 		if (substr($1, 0, 1) == "#") {
    171 			print $0
    172 		} else if ($1 == "fd" || $1 == "/proc" || $1 == "swap" ||
    173 		    $1 == "ctfs" || $1 == "objfs" || $1 == "sharefs" ||
    174 		    $4 == "nfs" || $4 == "lofs") {
    175 			print $0
    176 		} else {
    177 			print "#", $0
    178 			modified=1
    179 		}
    180 	}
    181 	END {
    182 		if (modified == 1) {
    183 			printf("# Modified by p2v ")
    184 			system("/usr/bin/date")
    185 			exit 0
    186 		}
    187 		exit 1
    188 	}' $ZONEROOT/etc/vfstab >>$tmpfile
    189 
    190 	if (( $? == 0 )); then
    191 		if [[ ! -f $ZONEROOT/etc/vfstab.pre_p2v ]]; then
    192 			safe_copy $ZONEROOT/etc/vfstab \
    193 			    $ZONEROOT/etc/vfstab.pre_p2v
    194 		fi
    195 		safe_copy $tmpfile $ZONEROOT/etc/vfstab
    196 	fi
    197 	/usr/bin/rm -f $tmpfile
    198 }
    199 
    200 #
    201 # Collect the data needed to delete or disable SMF services before we run
    202 # the 'update on attach'.  For a normal zone migration, 'update on attach'
    203 # will fix things up, but since we're p2v-ing a physical image there are
    204 # SMF services which UoA can't handle (since those services aren't enabled
    205 # in a simple zone image.
    206 #
    207 fix_smf_pre_uoa()
    208 {
    209 	#
    210 	# Start by getting the svc manifests that are delivered by hollow
    211 	# pkgs then use 'svccfg inventory' to get the names of the svcs
    212 	# delivered by those manifests.  The svc names are saved into a
    213 	# temporary file.
    214 	#
    215 
    216 	SMFTMPFILE=$(/usr/bin/mktemp -t -p /var/tmp smf.XXXXXX)
    217 	if [[ -z "$SMFTMPFILE" ]]; then
    218 		error "$e_tmpfile"
    219 		return
    220 	fi
    221 
    222 	for i in $ZONEROOT/var/sadm/pkg/*
    223 	do
    224 		pkg=$(/usr/bin/basename $i)
    225 		[[ ! -f $ZONEROOT/var/sadm/pkg/$pkg/save/pspool/$pkg/pkgmap ]] \
    226 		    && continue
    227 
    228 		/usr/bin/egrep -s "SUNW_PKG_HOLLOW=true" \
    229 		    $ZONEROOT/var/sadm/pkg/$pkg/pkginfo || continue
    230 
    231 		for j in $(/usr/bin/nawk '{if ($2 == "f" &&
    232 		    substr($4, 1, 17) == "var/svc/manifest/") print $4}' \
    233 		    $ZONEROOT/var/sadm/pkg/$pkg/save/pspool/$pkg/pkgmap)
    234 		do
    235 			svcs=$(SVCCFG_NOVALIDATE=1 \
    236 			    SVCCFG_REPOSITORY=$ZONEROOT/etc/svc/repository.db \
    237 			    /usr/sbin/svccfg inventory $ZONEROOT/$j)
    238 			for k in $svcs
    239 			do
    240 				echo $k /$j >> $SMFTMPFILE
    241 			done
    242 		done
    243 	done
    244 }
    245 
    246 #
    247 # Delete or disable SMF services.
    248 # Zone is booted to milestone=none when this function is called.
    249 # Use the SMF data collected by fix_smf_pre_uoa() to delete the services.
    250 #
    251 fix_smf()
    252 {
    253 	# 
    254 	# Zone was already booted to milestone=none, wait until SMF door exists.
    255 	#
    256 	for i in 0 1 2 3 4 5 6 7 8 9
    257 	do
    258 		[[ -r $ZONEROOT/etc/svc/volatile/repository_door ]] && break
    259 		sleep 5
    260 	done
    261 
    262 	if [[ $i -eq 9 && ! -r $ZONEROOT/etc/svc/volatile/repository_door ]];
    263 	then
    264 		error "$e_nosmf"
    265 		/usr/bin/rm -f $SMFTMPFILE
    266 		return
    267 	fi
    268 
    269 	insttmpfile=$(/usr/bin/mktemp -t -p /var/tmp instsmf.XXXXXX)
    270 	if [[ -z "$insttmpfile" ]]; then
    271 		error "$e_tmpfile"
    272 		/usr/bin/rm -f $SMFTMPFILE
    273 		return
    274 	fi
    275 
    276 	vlog "$v_rmhollowsvcs"
    277         while read fmri mfst
    278 	do
    279 		# Delete the svc.
    280 		vlog "$v_delsvc" "$fmri"
    281 		echo "/usr/sbin/svccfg delete -f $fmri"
    282 		echo "/usr/sbin/svccfg delhash -d $mfst"
    283 		echo "rm -f $mfst"
    284 	done < $SMFTMPFILE > $ZONEROOT/tmp/smf_rm
    285 
    286 	/usr/sbin/zlogin -S $ZONENAME /bin/sh /tmp/smf_rm >/dev/null 2>&1
    287 
    288 	/usr/bin/rm -f $SMFTMPFILE
    289 
    290 	# Get a list of the svcs that now exist in the zone.
    291 	/usr/sbin/zlogin -S $ZONENAME /usr/bin/svcs -aH | \
    292 	    /usr/bin/nawk '{print $3}' >>$insttmpfile
    293 
    294 	[[ -n $LOGFILE ]] && \
    295 	    printf "[$(date)] ${MSG_PREFIX}${v_svcsinzone}\n" >&2
    296 	[[ -n $LOGFILE ]] && cat $insttmpfile >&2
    297 
    298 	#
    299 	# Fix network services if shared stack.
    300 	#
    301 	if [[ "$STACK_TYPE" == "shared" ]]; then
    302 		vlog "$v_fixnetsvcs"
    303 
    304 		NETPHYSDEF="svc:/network/physical:default"
    305 		NETPHYSNWAM="svc:/network/physical:nwam"
    306 
    307 		/usr/bin/egrep -s "$NETPHYSDEF" $insttmpfile
    308 		if (( $? == 0 )); then
    309 			vlog "$v_enblsvc" "$NETPHYSDEF"
    310 			/usr/sbin/zlogin -S $ZONENAME \
    311 			    /usr/sbin/svcadm enable $NETPHYSDEF || \
    312 			    error "$e_dissvc" "$NETPHYSDEF"
    313 		fi
    314 
    315 		/usr/bin/egrep -s "$NETPHYSNWAM" $insttmpfile
    316 		if (( $? == 0 )); then
    317 			vlog "$v_dissvc" "$NETPHYSNWAM"
    318 			/usr/sbin/zlogin -S $ZONENAME \
    319 			    /usr/sbin/svcadm disable $NETPHYSNWAM || \
    320 			    error "$e_enblsvc" "$NETPHYSNWAM"
    321 		fi
    322 
    323 		for i in $(/usr/bin/egrep network/routing $insttmpfile)
    324 		do
    325 			# Disable the svc.
    326 			vlog "$v_dissvc" "$i"
    327 			/usr/sbin/zlogin -S $ZONENAME \
    328 			    /usr/sbin/svcadm disable $i || \
    329 			    error "$e_dissvc" $i
    330 		done
    331 	fi
    332 
    333 	#
    334 	# Disable well-known services that don't run in a zone.
    335 	#
    336 	vlog "$v_rminvalidsvcs"
    337 	for i in $(/usr/bin/egrep -hv "^#" \
    338 	    /usr/lib/brand/native/smf_disable.lst \
    339 	    /etc/brand/native/smf_disable.conf)
    340 	do
    341 		# Skip svcs not installed in the zone.
    342 		/usr/bin/egrep -s "$i:" $insttmpfile || continue
    343 
    344 		# Disable the svc.
    345 		vlog "$v_dissvc" "$i"
    346 		/usr/sbin/zlogin -S $ZONENAME /usr/sbin/svcadm disable $i || \
    347 		    error "$e_dissvc" $i
    348 	done
    349 
    350 	#
    351 	# Since zones can't be NFS servers, disable all of the instances of
    352 	# the shares svc.
    353 	#
    354 	for i in $(/usr/bin/egrep network/shares/group $insttmpfile)
    355 	do
    356 		vlog "$v_dissvc" "$i"
    357 		/usr/sbin/zlogin -S $ZONENAME /usr/sbin/svcadm disable $i || \
    358 		    error "$e_dissvc" $i
    359 	done
    360 
    361 	/usr/bin/rm -f $insttmpfile
    362 }
    363 
    364 #
    365 # Remove well-known pkgs that do not work inside a zone.
    366 #
    367 rm_pkgs()
    368 {
    369 	/usr/bin/cat <<-EOF > $ZONEROOT/tmp/admin || fatal "$e_adminf"
    370 	mail=
    371 	instance=overwrite
    372 	partial=nocheck
    373 	runlevel=nocheck
    374 	idepend=nocheck
    375 	rdepend=nocheck
    376 	space=nocheck
    377 	setuid=nocheck
    378 	conflict=nocheck
    379 	action=nocheck
    380 	basedir=default
    381 	EOF
    382 
    383 	for i in $(/usr/bin/egrep -hv "^#" /usr/lib/brand/native/pkgrm.lst \
    384 	    /etc/brand/native/pkgrm.conf)
    385 	do
    386 		[[ ! -d $ZONEROOT/var/sadm/pkg/$i ]] && continue
    387 
    388 		vlog "$v_rmpkg" "$i"
    389 		/usr/sbin/zlogin -S $ZONENAME \
    390 		    /usr/sbin/pkgrm -na /tmp/admin $i >&2 || error "$e_rmpkg" $i
    391 	done
    392 }
    393 
    394 #
    395 # Zoneadmd writes a one-line index file into the zone when the zone boots,
    396 # so any information about installed zones from the original system will
    397 # be lost at that time.  Here we'll warn the sysadmin about any pre-existing
    398 # zones that they might want to clean up by hand, but we'll leave the zonepaths
    399 # in place in case they're on shared storage and will be migrated to
    400 # a new host.
    401 #
    402 warn_zones()
    403 {
    404 	zoneconfig=$ZONEROOT/etc/zones
    405 
    406 	if [[ -h $zoneconfig/index || ! -f $zoneconfig/index ]]; then
    407 		error "$e_badfile" "/etc/zones/index"
    408 		return
    409 	fi
    410 
    411 	NGZ=$(/usr/bin/nawk -F: '{
    412 		if (substr($1, 0, 1) == "#" || $1 == "global")
    413 			continue
    414 
    415 		if ($2 == "installed")
    416 			printf("%s ", $1)
    417 	}' $zoneconfig/index)
    418 
    419 	# Return if there are no installed zones to warn about.
    420 	[[ -z "$NGZ" ]] && return
    421 
    422 	log "$v_rmzones" "$NGZ"
    423 
    424 	NGZP=$(/usr/bin/nawk -F: '{
    425 		if (substr($1, 0, 1) == "#" || $1 == "global")
    426 			continue
    427 
    428 		if ($2 == "installed")
    429 			printf("%s ", $3)
    430 	}' $zoneconfig/index)
    431 
    432 	log "$v_rmzonepaths"
    433 
    434 	for i in $NGZP
    435 	do
    436 		log "    %s" "$i"
    437 	done
    438 }
    439 
    440 unset LD_LIBRARY_PATH
    441 PATH=/usr/sbin:/usr/bin
    442 export PATH
    443 
    444 #
    445 # ^C Should cleanup; if the zone is running, it should try to halt it.
    446 #
    447 zone_is_running=0
    448 trap trap_cleanup INT
    449 
    450 #
    451 # Parse the command line options.
    452 #
    453 unset backout
    454 OPT_U=
    455 OPT_V=
    456 OPT_M=
    457 OPT_L=
    458 while getopts "b:uvm:l:" opt
    459 do
    460 	case "$opt" in
    461 		b)	if [[ -n "$backout" ]]; then
    462 				backout="$backout -b $OPTARG"
    463 			else
    464 				backout="-b $OPTARG"
    465 			fi
    466 			;;
    467 		u)	OPT_U="-u";;
    468 		v)	OPT_V="-v";;
    469 		m)	MSG_PREFIX="$OPTARG"; OPT_M="-m \"$OPTARG\"";;
    470 		l)	LOGFILE="$OPTARG"; OPT_L="-l \"$OPTARG\"";;
    471 		*)	usage;;
    472 	esac
    473 done
    474 shift OPTIND-1
    475 
    476 (( $# < 1 )) && usage
    477 
    478 (( $# > 2 )) && usage
    479 
    480 [[ -n $LOGFILE ]] && exec 2>>$LOGFILE
    481 
    482 ZONENAME=$1
    483 ZONEPATH=$2
    484 ZONEROOT=$ZONEPATH/root
    485 
    486 e_badinfo=$(gettext "Failed to get '%s' zone resource")
    487 e_badfile=$(gettext "Invalid '%s' file within the zone")
    488 e_tmpfile=$(gettext "Unable to create temporary file")
    489 v_mkdirs=$(gettext "Creating mount points")
    490 v_nonetfix=$(gettext "Cannot update /etc/hostname.{net} file")
    491 v_update=$(gettext "Updating the zone software to match the global zone...")
    492 v_updatedone=$(gettext "Zone software update complete")
    493 e_badupdate=$(gettext "Updating the Zone software failed")
    494 v_adjust=$(gettext "Updating the image to run within a zone")
    495 v_stacktype=$(gettext "Stack type '%s'")
    496 v_booting=$(gettext "Booting zone to single user mode")
    497 e_badboot=$(gettext "Zone boot failed")
    498 e_nosmf=$(gettext "ERROR: SMF repository unavailable.")
    499 e_nosingleuser=$(gettext "ERROR: zone did not finish booting to single-user.")
    500 v_svcsinzone=$(gettext "The following SMF services are installed:")
    501 v_rmhollowsvcs=$(gettext "Deleting SMF services from hollow packages")
    502 v_fixnetsvcs=$(gettext "Adjusting network SMF services")
    503 v_rminvalidsvcs=$(gettext "Disabling invalid SMF services")
    504 v_delsvc=$(gettext "Delete SMF svc '%s'")
    505 e_delsvc=$(gettext "deleting SMF svc '%s'")
    506 v_enblsvc=$(gettext "Enable SMF svc '%s'")
    507 e_enblsvc=$(gettext "enabling SMF svc '%s'")
    508 v_dissvc=$(gettext "Disable SMF svc '%s'")
    509 e_dissvc=$(gettext "disabling SMF svc '%s'")
    510 e_adminf=$(gettext "Unable to create admin file")
    511 v_rmpkg=$(gettext "Remove package '%s'")
    512 e_rmpkg=$(gettext "removing package '%s'")
    513 v_rmzones=$(gettext "The following zones in this image will be unusable: %s")
    514 v_rmzonepaths=$(gettext "These zonepaths could be removed from this image:")
    515 v_unconfig=$(gettext "Performing zone sys-unconfig")
    516 e_unconfig=$(gettext "sys-unconfig failed")
    517 v_halting=$(gettext "Halting zone")
    518 e_shutdown=$(gettext "Shutting down zone %s...")
    519 e_badhalt=$(gettext "Zone halt failed")
    520 v_exitgood=$(gettext "Postprocessing successful.")
    521 e_exitfail=$(gettext "Postprocessing failed.")
    522 
    523 #
    524 # Do some validation on the paths we'll be accessing
    525 #
    526 safe_dir etc
    527 safe_dir etc/dfs
    528 safe_dir etc/zones
    529 safe_dir var
    530 
    531 # Now do the work to update the zone.
    532 
    533 # Before booting the zone we may need to create a few mnt points, just in
    534 # case they don't exist for some reason.
    535 #
    536 # Whenever we reach into the zone while running in the global zone we
    537 # need to validate that none of the interim directories are symlinks
    538 # that could cause us to inadvertently modify the global zone.
    539 vlog "$v_mkdirs"
    540 if [[ ! -f $ZONEROOT/tmp && ! -d $ZONEROOT/tmp ]]; then
    541 	mkdir -m 1777 -p $ZONEROOT/tmp || exit $EXIT_CODE
    542 fi
    543 if [[ ! -f $ZONEROOT/var/run && ! -d $ZONEROOT/var/run ]]; then
    544 	mkdir -m 1755 -p $ZONEROOT/var/run || exit $EXIT_CODE
    545 fi
    546 if [[ ! -f $ZONEROOT/var/tmp && ! -d $ZONEROOT/var/tmp ]]; then
    547 	mkdir -m 1777 -p $ZONEROOT/var/tmp || exit $EXIT_CODE
    548 fi
    549 if [[ ! -h $ZONEROOT/etc && ! -f $ZONEROOT/etc/mnttab ]]; then
    550 	/usr/bin/touch $ZONEROOT/etc/mnttab || exit $EXIT_CODE
    551 	/usr/bin/chmod 444 $ZONEROOT/etc/mnttab || exit $EXIT_CODE
    552 fi
    553 if [[ ! -f $ZONEROOT/proc && ! -d $ZONEROOT/proc ]]; then
    554 	mkdir -m 755 -p $ZONEROOT/proc || exit $EXIT_CODE
    555 fi
    556 if [[ ! -f $ZONEROOT/dev && ! -d $ZONEROOT/dev ]]; then
    557 	mkdir -m 755 -p $ZONEROOT/dev || exit $EXIT_CODE
    558 fi
    559 if [[ ! -h $ZONEROOT/etc && ! -h $ZONEROOT/etc/svc && ! -d $ZONEROOT/etc/svc ]]
    560 then
    561 	mkdir -m 755 -p $ZONEROOT/etc/svc/volatile || exit $EXIT_CODE
    562 fi
    563 
    564 # Check for zones inside of image.
    565 warn_zones
    566 fix_smf_pre_uoa
    567 
    568 #
    569 # Run update on attach.  State is currently 'incomplete' so use the private
    570 # force-update option.
    571 #
    572 log "$v_update"
    573 /usr/sbin/zoneadm -z $ZONENAME attach -U $backout >&2
    574 if (( $? != 0 )); then
    575 	/usr/bin/rm -f $SMFTMPFILE
    576 	fatal "$e_badupdate"
    577 else
    578 	log "$v_updatedone"
    579 fi
    580 
    581 log "$v_adjust"
    582 
    583 #
    584 # Any errors in these functions are not considered fatal.  The zone can be
    585 # be fixed up manually afterwards and it may need some additional manual
    586 # cleanup in any case.
    587 #
    588 
    589 STACK_TYPE=$(/usr/sbin/zoneadm -z $ZONENAME list -p | \
    590     /usr/bin/nawk -F: '{print $7}')
    591 if (( $? != 0 )); then
    592 	error "$e_badinfo" "stacktype"
    593 fi
    594 vlog "$v_stacktype" "$STACK_TYPE"
    595 
    596 fix_net
    597 fix_nfs
    598 fix_vfstab
    599 
    600 vlog "$v_booting"
    601 
    602 #
    603 # Boot the zone so that we can do all of the SMF updates needed on the zone's
    604 # repository.
    605 #
    606 
    607 zone_is_running=1
    608 
    609 # The 'update on attach' left the zone installed.
    610 /usr/sbin/zoneadm -z $ZONENAME boot -f -- -m milestone=none
    611 if (( $? != 0 )); then
    612 	error "$e_badboot"
    613 	/usr/bin/rm -f $SMFTMPFILE
    614 	fatal "$e_exitfail"
    615 fi
    616 
    617 # cleanup SMF services
    618 fix_smf
    619 
    620 # remove invalid pkgs
    621 rm_pkgs
    622 
    623 vlog "$v_halting"
    624 /usr/sbin/zoneadm -z $ZONENAME halt
    625 if (( $? != 0 )); then
    626 	error "$e_badhalt"
    627 	failed=1
    628 fi
    629 zone_is_running=0
    630 
    631 if [[ -z $failed && -n $OPT_U ]]; then
    632 	#
    633 	# We're sys-unconfiging the zone.  This will halt the zone, however
    634 	# there are problems with sys-unconfig and it usually hangs when the
    635 	# zone is booted to milestone=none.  This is why we previously halted
    636 	# the zone.  We now boot to milestone=single-user.  Again, the
    637 	# sys-unconfig can hang if the zone is still in the process of
    638 	# booting when we try to run sys-unconfig.  Wait until the boot is
    639 	# done, which we do by checking for sulogin, or waiting 30 seconds,
    640 	# whichever comes first.
    641 	#
    642 
    643 	vlog "$v_unconfig"
    644 
    645 	zone_is_running=1
    646 	/usr/sbin/zoneadm -z $ZONENAME boot -- -m milestone=single-user
    647 	if (( $? != 0 )); then
    648 		error "$e_badboot"
    649 		fatal "$e_exitfail"
    650 	fi
    651 
    652         for i in 0 1 2 3 4 5 6 7 8 9
    653         do
    654                 sleep 10
    655 		/usr/sbin/zlogin $ZONENAME \
    656 		    /usr/bin/svcs -H svc:/milestone/single-user:default 2>&1 |
    657 		    /usr/bin/nawk '{
    658 			if ($1 == "online")
    659 				exit 0
    660 			else
    661 				exit 1
    662 		    }' && break
    663         done
    664 
    665 	if (( $i == 9 )); then
    666 		vlog "$e_nosingleuser"
    667         fi
    668 
    669 	echo "yes" | /usr/sbin/zlogin -S $ZONENAME \
    670 	    /usr/sbin/sys-unconfig >/dev/null 2>&1
    671 	if (( $? != 0 )); then
    672 		error "$e_unconfig"
    673 		failed=1
    674 	fi
    675 fi
    676 
    677 
    678 if [[ -n $failed ]]; then
    679 	fatal "$e_exitfail"
    680 fi
    681 
    682 vlog "$v_exitgood"
    683 exit 0
    684