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 # Import ip-interface-management service in S10C, network 337 # loopback service requires ipmgmtd in exclusive stack zones. 338 # 339 /usr/sbin/zlogin -S $ZONENAME /usr/sbin/svccfg import \ 340 $ZONEROOT/var/svc/manifest/network/network-ipmgmt.xml 341 342 # 343 # Fix network services if shared stack. 344 # 345 if [[ "$STACK_TYPE" == "shared" ]]; then 346 vlog "$v_fixnetsvcs" 347 348 NETPHYSDEF="svc:/network/physical:default" 349 NETPHYSNWAM="svc:/network/physical:nwam" 350 351 /usr/bin/egrep -s "$NETPHYSDEF" $insttmpfile 352 if (( $? == 0 )); then 353 vlog "$v_enblsvc" "$NETPHYSDEF" 354 /usr/sbin/zlogin -S $ZONENAME \ 355 /usr/sbin/svcadm enable $NETPHYSDEF || \ 356 error "$e_dissvc" "$NETPHYSDEF" 357 fi 358 359 /usr/bin/egrep -s "$NETPHYSNWAM" $insttmpfile 360 if (( $? == 0 )); then 361 vlog "$v_dissvc" "$NETPHYSNWAM" 362 /usr/sbin/zlogin -S $ZONENAME \ 363 /usr/sbin/svcadm disable $NETPHYSNWAM || \ 364 error "$e_enblsvc" "$NETPHYSNWAM" 365 fi 366 367 for i in $(/usr/bin/egrep network/routing $insttmpfile) 368 do 369 # Disable the svc. 370 vlog "$v_dissvc" "$i" 371 /usr/sbin/zlogin -S $ZONENAME \ 372 /usr/sbin/svcadm disable $i || \ 373 error "$e_dissvc" $i 374 done 375 fi 376 377 # 378 # Disable well-known services that don't run in a zone. 379 # 380 vlog "$v_rminvalidsvcs" 381 for i in $(/usr/bin/egrep -hv "^#" \ 382 /usr/lib/brand/solaris10/smf_disable.lst \ 383 /etc/brand/solaris10/smf_disable.conf) 384 do 385 # Skip svcs not installed in the zone. 386 /usr/bin/egrep -s "$i:" $insttmpfile || continue 387 388 # Disable the svc. 389 vlog "$v_dissvc" "$i" 390 /usr/sbin/zlogin -S $ZONENAME /usr/sbin/svcadm disable $i || \ 391 error "$e_dissvc" $i 392 done 393 394 # 395 # Since zones can't be NFS servers, disable all of the instances of 396 # the shares svc. 397 # 398 for i in $(/usr/bin/egrep network/shares/group $insttmpfile) 399 do 400 vlog "$v_dissvc" "$i" 401 /usr/sbin/zlogin -S $ZONENAME /usr/sbin/svcadm disable $i || \ 402 error "$e_dissvc" $i 403 done 404 405 /usr/bin/rm -f $insttmpfile 406 407 return 0 408} 409 410# 411# Remove well-known pkgs that do not work inside a zone. 412# 413rm_pkgs() 414{ 415 /usr/bin/cat <<-EOF > $ZONEROOT/tmp/admin || fatal "$e_adminf" 416 mail= 417 instance=overwrite 418 partial=nocheck 419 runlevel=nocheck 420 idepend=nocheck 421 rdepend=nocheck 422 space=nocheck 423 setuid=nocheck 424 conflict=nocheck 425 action=nocheck 426 basedir=default 427 EOF 428 429 for i in $(/usr/bin/egrep -hv "^#" /usr/lib/brand/solaris10/pkgrm.lst \ 430 /etc/brand/solaris10/pkgrm.conf) 431 do 432 [[ ! -d $ZONEROOT/var/sadm/pkg/$i ]] && continue 433 434 vlog "$v_rmpkg" "$i" 435 /usr/sbin/zlogin -S $ZONENAME \ 436 /usr/sbin/pkgrm -na /tmp/admin $i >&2 || error "$e_rmpkg" $i 437 done 438} 439 440# 441# Zoneadmd writes a one-line index file into the zone when the zone boots, 442# so any information about installed zones from the original system will 443# be lost at that time. Here we'll warn the sysadmin about any pre-existing 444# zones that they might want to clean up by hand, but we'll leave the zonepaths 445# in place in case they're on shared storage and will be migrated to 446# a new host. 447# 448warn_zones() 449{ 450 zoneconfig=$ZONEROOT/etc/zones 451 452 [[ ! -d $zoneconfig ]] && return 453 454 if [[ -h $zoneconfig/index || ! -f $zoneconfig/index ]]; then 455 error "$e_badfile" "/etc/zones/index" 456 return 457 fi 458 459 NGZ=$(/usr/bin/nawk -F: '{ 460 if (substr($1, 0, 1) == "#" || $1 == "global") 461 continue 462 463 if ($2 == "installed") 464 printf("%s ", $1) 465 }' $zoneconfig/index) 466 467 # Return if there are no installed zones to warn about. 468 [[ -z "$NGZ" ]] && return 469 470 log "$v_rmzones" "$NGZ" 471 472 NGZP=$(/usr/bin/nawk -F: '{ 473 if (substr($1, 0, 1) == "#" || $1 == "global") 474 continue 475 476 if ($2 == "installed") 477 printf("%s ", $3) 478 }' $zoneconfig/index) 479 480 log "$v_rmzonepaths" 481 482 for i in $NGZP 483 do 484 log " %s" "$i" 485 done 486} 487 488# 489# ^C Should cleanup; if the zone is running, it should try to halt it. 490# 491zone_is_running=0 492trap trap_cleanup INT 493 494# 495# Parse the command line options. 496# 497OPT_U= 498OPT_V= 499OPT_M= 500OPT_L= 501while getopts "uvm:l:" opt 502do 503 case "$opt" in 504 u) OPT_U="-u";; 505 v) OPT_V="-v";; 506 m) MSG_PREFIX="$OPTARG"; OPT_M="-m \"$OPTARG\"";; 507 l) LOGFILE="$OPTARG"; OPT_L="-l \"$OPTARG\"";; 508 *) usage;; 509 esac 510done 511shift OPTIND-1 512 513(( $# < 1 )) && usage 514 515(( $# > 2 )) && usage 516 517[[ -n $LOGFILE ]] && exec 2>>$LOGFILE 518 519ZONENAME=$1 520ZONEPATH=$2 521# XXX shared/common script currently uses lower case zonename & zonepath 522zonename="$ZONENAME" 523zonepath="$ZONEPATH" 524ZONEROOT=$ZONEPATH/root 525 526e_badinfo=$(gettext "Failed to get '%s' zone resource") 527e_badfile=$(gettext "Invalid '%s' file within the zone") 528v_mkdirs=$(gettext "Creating mount points") 529v_nonetfix=$(gettext "Cannot update /etc/hostname.{net} file") 530v_adjust=$(gettext "Updating the image to run within a zone") 531v_stacktype=$(gettext "Stack type '%s'") 532v_booting=$(gettext "Booting zone to single user mode") 533e_bootfail=$(gettext "Failed to boot zone to single user mode.") 534e_nosmf=$(gettext "SMF repository unavailable.") 535v_svcsinzone=$(gettext "The following SMF services are installed:") 536v_rmhollowsvcs=$(gettext "Deleting SMF services from hollow packages") 537v_fixnetsvcs=$(gettext "Adjusting network SMF services") 538v_rminvalidsvcs=$(gettext "Disabling invalid SMF services") 539v_delsvc=$(gettext "Delete SMF svc '%s'") 540e_delsvc=$(gettext "deleting SMF svc '%s'") 541v_enblsvc=$(gettext "Enable SMF svc '%s'") 542e_enblsvc=$(gettext "enabling SMF svc '%s'") 543v_dissvc=$(gettext "Disable SMF svc '%s'") 544e_dissvc=$(gettext "disabling SMF svc '%s'") 545e_adminf=$(gettext "Unable to create admin file") 546v_rmpkg=$(gettext "Remove package '%s'") 547e_rmpkg=$(gettext "removing package '%s'") 548v_rmzones=$(gettext "The following zones in this image will be unusable: %s") 549v_rmzonepaths=$(gettext "These zonepaths could be removed from this image:") 550v_halting=$(gettext "Halting zone") 551e_shutdown=$(gettext "Shutting down zone %s...") 552e_badhalt=$(gettext "Zone halt failed") 553v_exitgood=$(gettext "Postprocessing successful.") 554e_exitfail=$(gettext "Postprocessing failed.") 555 556# 557# Do some validation on the paths we'll be accessing 558# 559safe_dir /etc 560safe_dir /var 561safe_dir /var/sadm 562safe_dir /var/sadm/install 563safe_dir /var/sadm/pkg 564safe_opt_dir /etc/dfs 565safe_opt_dir /etc/lu 566safe_opt_dir /etc/zones 567 568mk_zone_dirs 569 570# Now do the work to update the zone. 571 572# Check for zones inside of image. 573warn_zones 574fix_smf_pre_uoa 575 576log "$v_adjust" 577 578# 579# Any errors in these functions are not considered fatal. The zone can be 580# be fixed up manually afterwards and it may need some additional manual 581# cleanup in any case. 582# 583 584STACK_TYPE=$(/usr/sbin/zoneadm -z $ZONENAME list -p | \ 585 /usr/bin/nawk -F: '{print $7}') 586if (( $? != 0 )); then 587 error "$e_badinfo" "stacktype" 588fi 589vlog "$v_stacktype" "$STACK_TYPE" 590 591fix_lu 592fix_net 593fix_nfs 594fix_vfstab 595 596vlog "$v_booting" 597 598# 599# Boot the zone so that we can do all of the SMF updates needed on the zone's 600# repository. 601# 602 603zone_is_running=1 604 605/usr/sbin/zoneadm -z $ZONENAME boot -f -- -m milestone=none 606if (( $? != 0 )); then 607 error "$e_badboot" 608 /usr/bin/rm -f $SMFTMPFILE 609 fatal "$e_exitfail" 610fi 611 612# 613# Remove all files and directories installed by hollow packages. Such files 614# and directories shouldn't exist inside zones. 615# 616hollow_pkgs=$(mktemp -t .hollow.pkgs.XXXXXX) 617hollow_file_list=$(mktemp $ZONEROOT/.hollow.pkgs.files.XXXXXX) 618hollow_dir_list=$(mktemp $ZONEROOT/.hollow.pkgs.dirs.XXXXXX) 619[ -f "$hollow_pkgs" -a -f "$hollow_file_list" -a -f "$hollow_dir_list" ] || { 620 error "$e_tmpfile" 621 rm -f $hollow_pkgs $hollow_file_list $hollow_dir_list 622 fatal "$e_exitfail" 623} 624for pkg_name in $ZONEROOT/var/sadm/pkg/*; do 625 grep 'SUNW_PKG_HOLLOW=true' $pkg_name/pkginfo >/dev/null 2>&1 && \ 626 basename $pkg_name >>$hollow_pkgs 627done 628/usr/bin/nawk -v hollowpkgs=$hollow_pkgs -v filelist=$hollow_file_list \ 629 -v dirlist=$hollow_dir_list ' 630 BEGIN { 631 while (getline p <hollowpkgs > 0) 632 pkgs[p] = 1; 633 close(hollowpkgs); 634 } 635 { 636 # fld is the field where the pkg names begin. 637 # nm is the file/dir entry name. 638 if ($2 == "f") { 639 fld=10; 640 nm=$1; 641 } else if ($2 == "d") { 642 fld=7; 643 nm=$1; 644 } else if ($2 == "s" || $2 == "l") { 645 fld=4; 646 split($1, a, "="); 647 nm=a[1]; 648 } else { 649 next; 650 } 651 652 # Determine whether the file or directory is delivered by any 653 # non-hollow packages. Files and directories can be 654 # delivered by multiple pkgs. The file or directory should only 655 # be removed if it is only delivered by hollow packages. 656 for (i = fld; i <= NF; i++) { 657 if (pkgs[get_pkg_name($i)] != 1) { 658 # We encountered a non-hollow package. Skip 659 # this entry. 660 next; 661 } 662 } 663 664 # The file or directory is only delivered by hollow packages. 665 # Mark it for removal. 666 if (fld != 7) 667 print nm >>filelist 668 else 669 print nm >>dirlist 670 } 671 672 # Get the clean pkg name from the fld entry. 673 function get_pkg_name(fld) { 674 # Remove any pkg control prefix (e.g. *, !) 675 first = substr(fld, 1, 1) 676 if (match(first, /[A-Za-z]/)) { 677 pname = fld 678 } else { 679 pname = substr(fld, 2) 680 } 681 682 # Then remove any class action script name 683 pos = index(pname, ":") 684 if (pos != 0) 685 pname = substr(pname, 1, pos - 1) 686 return (pname) 687 } 688' $ZONEROOT/var/sadm/install/contents 689/usr/sbin/zlogin -S $ZONENAME "cat /$(basename $hollow_file_list) | xargs rm -f" 690/usr/sbin/zlogin -S $ZONENAME "sort -r /$(basename $hollow_dir_list) | \ 691 xargs rmdir >/dev/null 2>&1" 692rm -f $hollow_pkgs $hollow_file_list $hollow_dir_list 693 694# cleanup SMF services 695fix_smf || failed=1 696 697# remove invalid pkgs 698[[ -z $failed ]] && rm_pkgs 699 700if [[ -z $failed && -n $OPT_U ]]; then 701 vlog "$v_unconfig" 702 703 sysunconfig_zone 704 if (( $? != 0 )); then 705 failed=1 706 fi 707fi 708 709vlog "$v_halting" 710/usr/sbin/zoneadm -z $ZONENAME halt 711if (( $? != 0 )); then 712 error "$e_badhalt" 713 failed=1 714fi 715zone_is_running=0 716 717if [[ -n $failed ]]; then 718 fatal "$e_exitfail" 719fi 720 721vlog "$v_exitgood" 722exit 0 723