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