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