1 #
   2 # CDDL HEADER START
   3 #
   4 # The contents of this file are subject to the terms of the
   5 # Common Development and Distribution License (the "License").
   6 # You may not use this file except in compliance with the License.
   7 #
   8 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9 # or http://www.opensolaris.org/os/licensing.
  10 # See the License for the specific language governing permissions
  11 # and limitations under the License.
  12 #
  13 # When distributing Covered Code, include this CDDL HEADER in each
  14 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15 # If applicable, add the following below this CDDL HEADER, with the
  16 # fields enclosed by brackets "[]" replaced with your own identifying
  17 # information: Portions Copyright [yyyy] [name of copyright owner]
  18 #
  19 # CDDL HEADER END
  20 #
  21 #
  22 # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  23 #
  24 
  25 #
  26 # get script name (bname)
  27 #
  28 bname=`basename $0`
  29 
  30 #
  31 # common shell script functions
  32 #
  33 . /usr/lib/brand/shared/common.ksh
  34 
  35 #
  36 # error messages
  37 #
  38 m_usage=$(gettext "Usage: %s: [-hFn]")
  39 
  40 m_1_zfs_promote=$(gettext "promoting '%s'.")
  41 m_1_zfs_destroy=$(gettext "destroying '%s'.")
  42 m_2_zfs_rename=$(gettext "renaming '%s' to '%s'.")
  43 m_3_zfs_set=$(gettext "setting property %s='%s' for '%s'.")
  44 m_rm_r=$(gettext "recursively deleting '%s'.")
  45 m_rm=$(gettext "deleting '%s'.")
  46 
  47 w_no_ds=$(gettext "Warning: no zonepath dataset found.")
  48 
  49 f_usage_err=$(gettext "Error: invalid usage")
  50 f_abort=$(gettext "Error: internal error detected, aborting.")
  51 f_1_zfs_promote=$(gettext "Error: promoting ZFS dataset '%s'.")
  52 f_2_zfs_rename=$(gettext "Error: renaming ZFS dataset '%s' to '%s'.")
  53 f_3_zfs_set=$(gettext "Error: setting ZFS propery %s='%s' for '%s'.")
  54 f_1_zfs_destroy=$(gettext "Error: destroying ZFS dataset.")
  55 f_2_zfs_get=$(gettext "Error: reading ZFS dataset property '%s' from '%s'.")
  56 f_user_snap=$(gettext "Error: user snapshot(s) detected.")
  57 f_stray_snap=$(gettext "Error: uncloned snapshot(s) detected.")
  58 f_stray_clone=$(gettext "Error: cloned zone datasets found outsize of zone.")
  59 f_rm_snap=$(gettext "Error: please delete snapshot(s) and retry uninstall.")
  60 f_rm_clone=$(gettext "Error: please delete clone(s) and retry uninstall.")
  61 f_iu_clone=$(gettext "Error: cloned zone dataset(s) in use.")
  62 f_dis_clone=$(gettext "Error: please stop using clone(s) and retry uninstall.")
  63 
  64 #
  65 # functions
  66 #
  67 print_array()
  68 {
  69         typeset -n pa_array=$1
  70 
  71         (( pa_i = 0 ))
  72         while (( $pa_i < ${#pa_array[@]} )); do
  73                 printf "\t${pa_array[$pa_i]}\n"
  74                 (( pa_i = $pa_i + 1 ))
  75         done
  76 }
  77 
  78 usage()
  79 {
  80         printf "$m_usage\n" "$bname"
  81         exit $ZONE_SUBPROC_USAGE
  82 }
  83 
  84 usage_err()
  85 {
  86         printf "$f_usage_err\n" >&2
  87         usage >&2
  88 }
  89 
  90 rm_zonepath()
  91 {
  92         # cleanup stuff we know about and leave any user data alone
  93 
  94         [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
  95                 printf "$m_rm\n" "$zonepath/SUNWattached.xml"
  96         $nop /bin/rm -f "$zonepath/SUNWattached.xml"
  97 
  98         [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
  99                 printf "$m_rm_r\n" "$zonepath/lu"
 100         $nop /bin/rm -rf "$zonepath/lu"
 101 
 102         [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
 103                 printf "$m_rm_r\n" "$zonepath/dev"
 104         $nop /bin/rm -rf "$zonepath/dev"
 105 
 106         [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
 107                 printf "$m_rm_r\n" "$zonepath/root"
 108         $nop /bin/rm -rf "$zonepath/root"
 109 
 110         [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
 111                 printf "$m_rm\n" "$zonepath"
 112         $nop /bin/rmdir "$zonepath" 2>/dev/null
 113 }
 114 
 115 zfs_destroy()
 116 {
 117         zd_fs1="$1"
 118 
 119         # first figure out if the target fs has an origin snapshot
 120         zd_origin=`/sbin/zfs get -H -o value origin "$zd_fs1"`
 121         if [[ $? != 0 ]]; then
 122                 printf "$f_2_zfs_get\n" origin "$zd_fs1" >&2
 123                 exit $ZONE_SUBPROC_FATAL
 124         fi
 125 
 126         [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
 127                 printf "$m_1_zfs_destroy\n" "$zd_fs1"
 128 
 129         #
 130         # note that we specify the '-r' flag so that we destroy any
 131         # descendants (filesystems and snapshot) of the specified
 132         # filesystem.
 133         #
 134         $nop /sbin/zfs destroy -r "$zd_fs1"
 135         if [[ $? != 0 ]]; then
 136                 printf "$f_1_zfs_destroy\n" "$zd_fs1" >&2
 137                 exit $ZONE_SUBPROC_FATAL
 138         fi
 139 
 140         [[ "$zd_origin" == "-" ]] && return
 141 
 142         [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
 143                 printf "$m_1_zfs_destroy\n" "$zd_origin"
 144 
 145         $nop /sbin/zfs destroy "$zd_origin" 2>/dev/null
 146         #
 147         # we ignore errors while trying to destroy the origin since
 148         # the origin could have been used as the source for other
 149         # clones
 150         #
 151 }
 152 
 153 zfs_promote()
 154 {
 155         zp_fs1="$1"
 156 
 157         [[ -z "$opt_n" ]] &&
 158                 printf "$m_1_zfs_promote\n" "$zp_fs1"
 159 
 160         $nop /sbin/zfs promote "$zp_fs1"
 161         if [[ $? != 0 ]]; then
 162                 printf "$f_1_zfs_promote\n" "$zp_fs1" >&2
 163                 exit $ZONE_SUBPROC_FATAL
 164         fi
 165 }
 166 
 167 zfs_rename()
 168 {
 169         zr_fs1="$1"
 170         zr_fs2="$2"
 171 
 172         [[ -z "$opt_n" ]] &&
 173                 printf "$m_2_zfs_rename\n" "$zr_fs1" "$zr_fs2"
 174 
 175         $nop /sbin/zfs rename "$zr_fs1" "$zr_fs2"
 176         if [[ $? != 0 ]]; then
 177                 printf "$f_2_zfs_rename\n" "$zr_fs1" "$zr_fs2" >&2
 178                 return 1
 179         fi
 180         return 0
 181 }
 182 
 183 zfs_set()
 184 {
 185         zs_prop=$1
 186         zs_value=$2
 187         zs_fs1=$3
 188 
 189         [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
 190                 printf "$m_3_zfs_set\n" "$zs_prop" "$zs_value" "$zs_fs1"
 191 
 192         $nop /sbin/zfs set "$zs_prop"="$zs_value" "$zs_fs1"
 193         if [[ $? != 0 ]]; then
 194                 printf "$f_3_zfs_set\n" "$zs_prop" "$zs_value" "$zs_fs1"
 195                 return 1
 196         fi
 197         return 0
 198 }
 199 
 200 zfs_set_array()
 201 {
 202         zsa_prop=$1
 203         zsa_value=$2
 204         typeset -n zsa_array=$3
 205         zsa_ignore_errors=$4
 206 
 207         (( zsa_i = 0 ))
 208         while (( $zsa_i < ${#zsa_array[@]} )); do
 209                 zfs_set "$zsa_prop" "$zsa_value" "${zsa_array[$zsa_i]}"
 210                 [[ $? != 0 ]] && [[ -z "$zsa_ignore_errors" ]] &&
 211                         return 1
 212                 (( zsa_i = $zsa_i + 1 ))
 213         done
 214         return 0
 215 }
 216 
 217 
 218 (( snap_rename_zbe_i = 1 ))
 219 (( snap_rename_snap_i = 1 ))
 220 snap_rename_init()
 221 {
 222         (( snap_rename_zbe_i = 1 ))
 223         (( snap_rename_snap_i = 1 ))
 224 }
 225 
 226 snap_rename()
 227 {
 228         eval sr_fs=\${$1}
 229         eval sr_snap=\${$2}
 230 
 231         if [[ "$sr_snap" == ~(Elr)(zbe-[0-9][0-9]*) ]]; then
 232                 sr_snap="zbe-$snap_rename_zbe_i"
 233                 (( snap_rename_zbe_i = $snap_rename_zbe_i + 1 ))
 234         elif [[ "$sr_snap" == ~(Er)(_snap[0-9]*) ]]; then
 235                 sr_snap=${sr_snap##~(Er)([0-9]*)}
 236                 sr_snap="${sr_snap}${snap_rename_snap_i}"
 237                 (( snap_rename_snap_i = $snap_rename_snap_i + 1 ))
 238         else
 239                 printf "$f_user_snap\n" >&2
 240                 printf "\t$sr_fs@$sr_snap\n" >&2
 241                 printf "$f_rm_snap\n" >&2
 242                 exit $ZONE_SUBPROC_FATAL
 243         fi
 244 
 245         eval $2="$sr_snap"
 246 }
 247 
 248 # find the dataset associated with $zonepath
 249 uninstall_get_zonepath_ds()
 250 {
 251         ZONEPATH_DS=`/sbin/zfs list -t filesystem -o name,mountpoint | \
 252             /usr/xpg4/bin/awk -v zonepath=$zonepath '{
 253                 if ($2 == zonepath)
 254                         print $1
 255         }'`
 256 
 257         if [ -z "$ZONEPATH_DS" ]; then
 258                 # there is no $zonepath dataset
 259                 rm_zonepath
 260                 exit $ZONE_SUBPROC_OK
 261         fi
 262 }
 263 
 264 # find the dataset associated with $ZONEPATH_DS/ROOT
 265 uninstall_get_zonepath_root_ds()
 266 {
 267         ZONEPATH_RDS=`/sbin/zfs list -H -t filesystem -o name \
 268                 $ZONEPATH_DS/ROOT 2>/dev/null`
 269 
 270         if [ -z "$ZONEPATH_RDS" ]; then
 271                 # there is no $ZONEPATH_DS/ROOT dataset
 272                 c=`/sbin/zfs list -H -t filesystem -r $ZONEPATH_DS | wc -l`
 273                 if [ $c = 1 ]; then
 274                         # $zonepath dataset has no descendents
 275                         zfs_destroy "$ZONEPATH_DS"
 276                 fi
 277                 rm_zonepath
 278                 exit $ZONE_SUBPROC_OK
 279         fi
 280 }
 281 
 282 destroy_zone_dataset()
 283 {
 284         fs=$1
 285 
 286         pool=${fs%%/*}
 287 
 288         # Fastpath.  if there are no snapshots of $fs then just delete it.
 289         c=`/sbin/zfs list -H -t snapshot -o name -r $fs | grep "^$fs@" |
 290             LC_ALL=C LANG=C wc -l`
 291         if (( $c == 0 )) ; then
 292                 zfs_destroy "$fs"
 293                 return
 294         fi
 295 
 296         #
 297         # This zone BE has snapshots.  This can happen if a zone has
 298         # multiple BEs (in which case we have snapshots named "zbe-XXX"),
 299         # if this zone has been used as the source for a clone of
 300         # another zone (in which case we have snapshots named
 301         # "XXX_snap"), or if an administrator has been doing manual
 302         # snapshotting.
 303         #
 304         # To be able to destroy this dataset (which we'll call the
 305         # origin) we need to get rid of all it's snapshots.  The "easiest"
 306         # way to do this is to:
 307         #
 308         # - delete any uncloned origin snapshots
 309         # - find the oldest clone of the youngest origin snapshot (which
 310         #   we'll call the oldest clone)
 311         # - check if there are any snapshots naming conflicts between
 312         #   the origin and the oldest clone.
 313         # - if so, find any clones of those conflicting origin snapshots
 314         # - make sure that those clones are not zoned an in-use.
 315         # - if any of those clones are zoned, unzone them.
 316         # - rename origin snapshots to eliminate naming conflicts
 317         # - for any clones that we unzoned, rezone them.
 318         # - promote the oldest clone
 319         # - destroy the origin and all it's descendants
 320         #
 321 
 322         #
 323         # Get a list of all the cloned datasets within the zpool
 324         # containing the origin filesystem.  Filter out any filesystems
 325         # that are descendants of origin because we are planning to
 326         # destroy them anyway.
 327         #
 328         unset clones clones_origin
 329         (( clones_c = 0 ))
 330         pool=${fs%%/*}
 331         LANG=C LC_ALL=C /sbin/zfs list -H -t filesystem -s creation \
 332             -o name,origin -r "$pool" |
 333             while IFS=" " read name origin; do
 334 
 335                 # skip non-clone filesystems
 336                 [[ "$origin" == "-" ]] &&
 337                         continue
 338 
 339                 # skip desendents of the origin we plan to destroy
 340                 [[ "$name" == ~()(${fs}/*) ]] &&
 341                         continue
 342 
 343                 # record this clone and it's origin
 344                 clones[$clones_c]="$name"
 345                 clones_origin[$clones_c]="$origin"
 346                 (( clones_c = $clones_c + 1 ))
 347         done
 348 
 349         #
 350         # Now do a sanity check.  Search for clones of a child datasets
 351         # of the dataset we want to destroy, that are not themselves
 352         # children of the dataset we're going to destroy).  This should
 353         # really never happen unless the global zone admin has cloned a
 354         # snapshot of a zone filesystem to a location outside of that
 355         # zone.  bad admin...
 356         #
 357         unset stray_clones
 358         (( stray_clones_c = 0 ))
 359         (( j = 0 ))
 360         while (( $j < $clones_c )); do
 361                 # is the clone origin a descendant of $fs?
 362                 if [[ "${clones_origin[$j]}" != ~()(${fs}/*) ]]; then
 363                         # we don't care.
 364                         (( j = $j + 1 ))
 365                         continue
 366                 fi
 367                 stray_clones[$stray_clones_c]=${clones[$j]}
 368                 (( stray_clones_c = $stray_clones_c + 1 ))
 369                 (( j = $j + 1 ))
 370         done
 371         if (( stray_clones_c > 0 )); then
 372                 #
 373                 # sigh.  the admin has done something strange.
 374                 # tell them to clean it up and retry.
 375                 #
 376                 printf "$f_stray_clone\n" >&2
 377                 print_array stray_clones >&2
 378                 printf "$f_rm_clone\n" >&2
 379                 exit $ZONE_SUBPROC_FATAL
 380         fi
 381 
 382         # Find all the snapshots of the origin filesystem.
 383         unset s_origin
 384         (( s_origin_c = 0 ))
 385         /sbin/zfs list -H -t snapshot -s creation -o name -r $fs |
 386             grep "^$fs@" | while read name; do
 387                 s_origin[$s_origin_c]=$name
 388                 (( s_origin_c = $s_origin_c + 1 ))
 389         done
 390 
 391         #
 392         # Now go through the origin snapshots and find those which don't
 393         # have clones.  We're going to explicity delete these snapshots
 394         # before we do the promotion.
 395         #
 396         unset s_delete
 397         (( s_delete_c = 0 ))
 398         (( j = 0 ))
 399         while (( $j < $s_origin_c )); do
 400                 (( k = 0 ))
 401                 while (( $k < $clones_c )); do
 402                         # if we have a match then break out of this loop
 403                         [[ "${s_origin[$j]}" == "${clones_origin[$k]}" ]] &&
 404                                 break
 405                         (( k = $k + 1 ))
 406                 done
 407                 if (( $k != $clones_c )); then
 408                         # this snapshot has a clone, move on to the next one
 409                         (( j = $j + 1 ))
 410                         continue
 411                 fi
 412 
 413                 # snapshot has no clones so add it to our delete list
 414                 s_delete[$s_delete_c]=${s_origin[$j]}
 415                 (( s_delete_c = $s_delete_c + 1 ))
 416                 # remove it from the origin snapshot list
 417                 (( k = $j + 1 ))
 418                 while (( $k < $s_origin_c )); do
 419                         s_origin[(( $k - 1 ))]=${s_origin[$k]}
 420                         (( k = $k + 1 ))
 421                 done
 422                 (( s_origin_c = $s_origin_c - 1 ))
 423         done
 424 
 425         #
 426         # Fastpath.  If there are no remaining snapshots then just
 427         # delete the origin filesystem (and all it's descendents) and
 428         # move onto the next zone BE.
 429         #
 430         if (( $s_origin_c == 0 )); then
 431                 zfs_destroy "$fs"
 432                 return
 433         fi
 434 
 435         # find the youngest snapshot of $fs
 436         s_youngest=${s_origin[(( $s_origin_c - 1 ))]}
 437 
 438         # Find the oldest clone of the youngest snapshot of $fs
 439         unset s_clone
 440         (( j = $clones_c - 1 ))
 441         while (( $j >= 0 )); do
 442                 if [[ "$s_youngest" == "${clones_origin[$j]}" ]]; then
 443                         s_clone=${clones[$j]}
 444                         break
 445                 fi
 446                 (( j = $j - 1 ))
 447         done
 448         if [[ -z "$s_clone" ]]; then
 449                 # uh oh.  something has gone wrong.  bail.
 450                 printf "$f_stray_snap\n" >&2
 451                 printf "\t$s_youngest\n" >&2
 452                 printf "$f_rm_snap\n" >&2
 453                 exit $ZONE_SUBPROC_FATAL
 454         fi
 455 
 456         # create an array of clone snapshot names
 457         unset s_clone_s
 458         (( s_clone_s_c = 0 ))
 459         /sbin/zfs list -H -t snapshot -s creation -o name -r $s_clone |
 460             grep "^$s_clone@" | while read name; do
 461                 s_clone_s[$s_clone_s_c]=${name##*@}
 462                 (( s_clone_s_c = $s_clone_s_c + 1 ))
 463         done
 464 
 465         # create an arrays of possible origin snapshot renames
 466         unset s_origin_snap
 467         unset s_rename
 468         (( j = 0 ))
 469         while (( $j < $s_origin_c )); do
 470                 s_origin_snap[$j]=${s_origin[$j]##*@}
 471                 s_rename[$j]=${s_origin[$j]##*@}
 472                 (( j = $j + 1 ))
 473         done
 474 
 475         #
 476         # Search for snapshot name collisions between the origin and
 477         # oldest clone.  If we find one, generate a new name for the
 478         # origin snapshot and re-do the collision check.
 479         #
 480         snap_rename_init
 481         (( j = 0 ))
 482         while (( $j < $s_origin_c )); do
 483                 (( k = 0 ))
 484                 while (( $k < $s_clone_s_c )); do
 485 
 486                         # if there's no naming conflict continue
 487                         if [[ "${s_rename[$j]}" != "${s_clone_s[$k]}" ]]; then
 488                                 (( k = $k + 1 ))
 489                                 continue
 490                         fi
 491 
 492                         #
 493                         # The origin snapshot conflicts with a clone
 494                         # snapshot.  Choose a new name and then restart
 495                         # then check that against clone snapshot names.
 496                         #
 497                         snap_rename fs "s_rename[$j]"
 498                         (( k = 0 ))
 499                         continue;
 500                 done
 501 
 502                 # if we didn't rename this snapshot then continue
 503                 if [[ "${s_rename[$j]}" == "${s_origin_snap[$j]}" ]]; then
 504                         (( j = $j + 1 ))
 505                         continue
 506                 fi
 507 
 508                 #
 509                 # We need to rename this origin snapshot because it
 510                 # conflicts with a clone snapshot name.  So above we
 511                 # chose a name that didn't conflict with any other clone
 512                 # snapshot names.  But we also have to avoid naming
 513                 # conflicts with any other origin snapshot names.  So
 514                 # check for that now.
 515                 #
 516                 (( k = 0 ))
 517                 while (( $k < $s_origin_c )); do
 518 
 519                         # don't compare against ourself
 520                         if (( $j == $k )); then
 521                                 (( k = $k + 1 ))
 522                                 continue
 523                         fi
 524 
 525                         # if there's no naming conflict continue
 526                         if [[ "${s_rename[$j]}" != "${s_rename[$k]}" ]]; then
 527                                 (( k = $k + 1 ))
 528                                 continue
 529                         fi
 530 
 531                         #
 532                         # The new origin snapshot name conflicts with
 533                         # another origin snapshot name.  Choose a new
 534                         # name and then go back to check the new name
 535                         # for uniqueness against all the clone snapshot
 536                         # names.
 537                         #
 538                         snap_rename fs "s_rename[$j]"
 539                         continue 2;
 540                 done
 541 
 542                 #
 543                 # A new unique name has been chosen.  Move on to the
 544                 # next origin snapshot.
 545                 #
 546                 (( j = $j + 1 ))
 547                 snap_rename_init
 548         done
 549 
 550         #
 551         # So now we know what snapshots need to be renamed before the
 552         # promotion.  But there's an additional problem.  If any of the
 553         # filesystems cloned from these snapshots have the "zoned"
 554         # attribute set (which is highly likely) or if they are in use
 555         # (and can't be unmounted and re-mounted) then the snapshot
 556         # rename will fail.  So now we'll search for all the clones of
 557         # snapshots we plan to rename and look for ones that are zoned.
 558         #
 559         # We'll ignore any snapshot clones that may be in use but are
 560         # not zoned.  If these clones are in-use, the rename will fail
 561         # and we'll abort, there's not much else we can do about it.
 562         # But if they are not in use the snapshot rename will unmount
 563         # and remount the clone.  This is ok because when the zoned
 564         # attribute is off, we know that the clone was originally
 565         # mounted from the global zone.  (So unmounting and remounting
 566         # it from the global zone is ok.)
 567         #
 568         # But we'll abort this whole operation if we find any clones
 569         # that that are zoned and in use.  (This can happen if another
 570         # zone has been cloned from this one and is now booted.)  The
 571         # reason we do this is because those zoned filesystems could
 572         # have originally mounted from within the zone.  So if we
 573         # cleared the zone attribute and did the rename, we'd be
 574         # remounting the filesystem from the global zone.  This would
 575         # result in the zone losing the ability to unmount the
 576         # filesystem, which would be bad.
 577         #
 578         unset zoned_clones zoned_iu_clones
 579         (( zoned_clones_c = 0 ))
 580         (( zoned_iu_clones_c = 0 ))
 581         (( j = 0 ))
 582         # walk through all the clones
 583         while (( $j < $clones_c )); do
 584                 # walk through all the origin snapshots
 585                 (( k = 0 ))
 586                 while (( $k < $s_origin_c )); do
 587                         #
 588                         # check if this clone originated from a snapshot that
 589                         # we need to rename.
 590                         #
 591                         [[ "${clones_origin[$j]}" == "${s_origin[$k]}" ]] &&
 592                             [[ "${s_origin_snap[$k]}" != "${s_rename[$k]}" ]] &&
 593                                 break
 594                         (( k = $k + 1 ))
 595                         continue
 596                 done
 597                 if (( $k == $s_origin_c )); then
 598                         # This isn't a clone of a snapshot we want to rename.
 599                         (( j = $j + 1 ))
 600                         continue;
 601                 fi
 602 
 603                 # get the zoned attr for this clone.
 604                 zoned=`LC_ALL=C LANG=C \
 605                     /sbin/zfs get -H -o value zoned ${clones[$j]}`
 606                 if [[ "$zoned" != on ]]; then
 607                         # This clone isn't zoned so ignore it.
 608                         (( j = $j + 1 ))
 609                         continue
 610                 fi
 611 
 612                 # remember this clone so we can muck with it's zoned attr.
 613                 zoned_clones[$zoned_clones_c]=${clones[$j]}
 614                 (( zoned_clones_c = $zoned_clones_c + 1 ))
 615 
 616                 # check if it's in use
 617                 mounted=`LC_ALL=C LANG=C \
 618                     /sbin/zfs get -H -o value mounted ${clones[$j]}`
 619                 if [[ "$mounted" != yes ]]; then
 620                         # Good news.  This clone isn't in use.
 621                         (( j = $j + 1 ))
 622                         continue
 623                 fi
 624 
 625                 # Sigh.  This clone is in use so we're destined to fail.
 626                 zoned_iu_clones[$zoned_iu_clones_c]=${clones[$j]}
 627                 (( zoned_iu_clones_c = $zoned_iu_clones_c + 1 ))
 628 
 629                 # keep looking for errors so we can report them all at once.
 630                 (( j = $j + 1 ))
 631         done
 632         if (( zoned_iu_clones_c > 0 )); then
 633                 #
 634                 # Tell the admin
 635                 #
 636                 printf "$f_iu_clone\n" >&2
 637                 print_array zoned_iu_clones >&2
 638                 printf "$f_dis_clone\n" >&2
 639                 exit $ZONE_SUBPROC_FATAL
 640         fi
 641 
 642         #
 643         # Ok.  So we're finally done with planning and we can do some
 644         # damage.  We're going to:
 645         # - destroy unused snapshots
 646         # - unzone clones which originate from snapshots we need to rename
 647         # - rename conflicting snapshots
 648         # - rezone any clones which we unzoned
 649         # - promote the oldest clone of the youngest snapshot
 650         # - finally destroy the origin filesystem.
 651         #
 652 
 653         # delete any unsed snapshot
 654         (( j = 0 ))
 655         while (( $j < $s_delete_c )); do
 656                 zfs_destroy "${s_delete[$j]}"
 657                 (( j = $j + 1 ))
 658         done
 659 
 660         # unzone clones
 661         zfs_set_array zoned off zoned_clones ||
 662                 zfs_set_array zoned on zoned_clones 1
 663 
 664         # rename conflicting snapshots
 665         (( j = 0 ))
 666         while (( $j < $s_origin_c )); do
 667                 if [[ "${s_origin_snap[$j]}" != "${s_rename[$j]}" ]]; then
 668                         zfs_rename "${s_origin[$j]}" "$fs@${s_rename[$j]}"
 669                         if [[ $? != 0 ]]; then
 670                                 # re-zone the clones before aborting
 671                                 zfs_set_array zoned on zoned_clones 1
 672                                 exit $ZONE_SUBPROC_FATAL
 673                         fi
 674                 fi
 675                 (( j = $j + 1 ))
 676         done
 677 
 678         # re-zone the clones
 679         zfs_set_array zoned on zoned_clones 1
 680 
 681         # promote the youngest clone of the oldest snapshot
 682         zfs_promote "$s_clone"
 683 
 684         # destroy the origin filesystem and it's descendants
 685         zfs_destroy "$fs"
 686 }
 687 
 688 #
 689 # This function expects an array named fs_all to exist which is initialized
 690 # with the zone's ZFS datasets that should be destroyed.  fs_all_c is the
 691 # count of the number of elements in the array.  ZONEPATH_RDS is the
 692 # zonepath/root dataset and ZONEPATH_DS is the zonepath dataset.
 693 #
 694 destroy_zone_datasets()
 695 {
 696         # Destroy the zone BEs datasets one by one.
 697         (( i = 0 ))
 698         while (( $i < $fs_all_c )); do
 699                 fs=${fs_all[$i]}
 700 
 701                 destroy_zone_dataset "$fs"
 702                 (( i = $i + 1 ))
 703         done
 704 
 705         #
 706         # Check if there are any other datasets left.  There may be datasets
 707         # associated with other GZ BEs, so we need to leave things alone in
 708         # that case.
 709         #
 710         c=`/sbin/zfs list -H -t filesystem -r $ZONEPATH_RDS | wc -l`
 711         if [ $c = 1 ]; then
 712                 zfs_destroy "$ZONEPATH_RDS"
 713         fi
 714         c=`/sbin/zfs list -H -t filesystem -r $ZONEPATH_DS | wc -l`
 715         if [ $c = 1 ]; then
 716                 zfs_destroy "$ZONEPATH_DS"
 717         fi
 718 
 719         rm_zonepath
 720 }