2N/A#
2N/A# CDDL HEADER START
2N/A#
2N/A# The contents of this file are subject to the terms of the
2N/A# Common Development and Distribution License (the "License").
2N/A# You may not use this file except in compliance with the License.
2N/A#
2N/A# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A# or http://www.opensolaris.org/os/licensing.
2N/A# See the License for the specific language governing permissions
2N/A# and limitations under the License.
2N/A#
2N/A# When distributing Covered Code, include this CDDL HEADER in each
2N/A# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A# If applicable, add the following below this CDDL HEADER, with the
2N/A# fields enclosed by brackets "[]" replaced with your own identifying
2N/A# information: Portions Copyright [yyyy] [name of copyright owner]
2N/A#
2N/A# CDDL HEADER END
2N/A#
2N/A#
2N/A# Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A#
2N/A
2N/A#
2N/A# get script name (bname)
2N/A#
2N/Abname=`basename $0`
2N/A
2N/A#
2N/A# error messages
2N/A#
2N/Am_uninstall_usage=$(gettext "Usage: %s: [-hFn]")
2N/A
2N/Am_1_zfs_promote=$(gettext "promoting '%s'.")
2N/Am_1_zfs_destroy=$(gettext "destroying '%s'.")
2N/Am_2_zfs_rename=$(gettext "renaming '%s' to '%s'.")
2N/Am_3_zfs_set=$(gettext "setting property %s='%s' for '%s'.")
2N/A
2N/Af_usage_err=$(gettext "Error: invalid usage")
2N/Af_abort=$(gettext "Error: internal error detected, aborting.")
2N/Af_1_zfs_promote=$(gettext "Error: promoting ZFS dataset '%s'.")
2N/Af_2_zfs_rename=$(gettext "Error: renaming ZFS dataset '%s' to '%s'.")
2N/Af_3_zfs_set=$(gettext "Error: setting ZFS propery %s='%s' for '%s'.")
2N/Af_1_zfs_destroy=$(gettext "Error: destroying ZFS dataset %s.")
2N/Af_2_zfs_get=$(gettext "Error: reading ZFS dataset property '%s' from '%s'.")
2N/Af_user_snap=$(gettext "Error: user snapshot(s) detected.")
2N/Af_stray_snap=$(gettext "Error: uncloned snapshot(s) detected.")
2N/Af_stray_clone=$(gettext "Error: cloned zone datasets found outsize of zone.")
2N/Af_rm_snap=$(gettext "Error: please delete snapshot(s) and retry uninstall.")
2N/Af_rm_clone=$(gettext "Error: please delete clone(s) and retry uninstall.")
2N/Af_iu_clone=$(gettext "Error: cloned zone dataset(s) in use.")
2N/Af_dis_clone=$(gettext "Error: please stop using clone(s) and retry uninstall.")
2N/A
2N/A#
2N/A# functions
2N/A#
2N/Afunction print_array {
2N/A typeset -n pa_array=$1
2N/A
2N/A (( pa_i = 0 ))
2N/A while (( $pa_i < ${#pa_array[@]} )); do
2N/A log "\t%s\n" "${pa_array[$pa_i]}"
2N/A (( pa_i = $pa_i + 1 ))
2N/A done
2N/A}
2N/A
2N/Afunction uninstall_usage {
2N/A log "$m_uninstall_usage\n" "$bname"
2N/A EXIT_CODE=$ZONE_SUBPROC_USAGE
2N/A exit $ZONE_SUBPROC_USAGE
2N/A}
2N/A
2N/Afunction uninstall_usage_err {
2N/A log "$f_usage_err\n"
2N/A uninstall_usage
2N/A}
2N/A
2N/Afunction zfs_destroy {
2N/A zd_fs1="$1"
2N/A
2N/A # first figure out if the target fs has an origin snapshot
2N/A zd_origin=`zfs get -H -o value origin "$zd_fs1"`
2N/A if [[ $? != 0 ]]; then
2N/A fail_fatal "$f_2_zfs_get\n" origin "$zd_fs1"
2N/A fi
2N/A
2N/A [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
2N/A log "$m_1_zfs_destroy\n" "$zd_fs1"
2N/A
2N/A #
2N/A # note that we specify the '-r' flag so that we destroy any
2N/A # descendants (filesystems and snapshot) of the specified
2N/A # filesystem.
2N/A #
2N/A $nop zfs destroy -r "$zd_fs1"
2N/A if [[ $? != 0 ]]; then
2N/A fail_fatal "$f_1_zfs_destroy\n" "$zd_fs1"
2N/A fi
2N/A
2N/A [[ "$zd_origin" == "-" ]] && return
2N/A
2N/A [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
2N/A log "$m_1_zfs_destroy\n" "$zd_origin"
2N/A
2N/A $nop /usr/sbin/zfs destroy "$zd_origin" 2>/dev/null
2N/A #
2N/A # we ignore errors while trying to destroy the origin since
2N/A # the origin could have been used as the source for other
2N/A # clones
2N/A #
2N/A}
2N/A
2N/Afunction zfs_promote {
2N/A zp_fs1="$1"
2N/A
2N/A [[ -z "$opt_n" ]] &&
2N/A log "$m_1_zfs_promote\n" "$zp_fs1"
2N/A
2N/A $nop zfs promote "$zp_fs1"
2N/A if [[ $? != 0 ]]; then
2N/A log "$f_1_zfs_promote\n" "$zp_fs1"
2N/A exit $ZONE_SUBPROC_FATAL
2N/A fi
2N/A}
2N/A
2N/Afunction zfs_rename {
2N/A zr_fs1="$1"
2N/A zr_fs2="$2"
2N/A
2N/A [[ -z "$opt_n" ]] &&
2N/A log "$m_2_zfs_rename\n" "$zr_fs1" "$zr_fs2"
2N/A
2N/A $nop zfs rename "$zr_fs1" "$zr_fs2"
2N/A if [[ $? != 0 ]]; then
2N/A log "$f_2_zfs_rename\n" "$zr_fs1" "$zr_fs2"
2N/A return 1
2N/A fi
2N/A return 0
2N/A}
2N/A
2N/A# Note: name prefixed with _ to not conflict with zfs_set in shared/common.ksh
2N/Afunction _zfs_set {
2N/A zs_prop=$1
2N/A zs_value=$2
2N/A zs_fs1=$3
2N/A
2N/A [[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
2N/A log "$m_3_zfs_set\n" "$zs_prop" "$zs_value" "$zs_fs1"
2N/A
2N/A $nop zfs set "$zs_prop"="$zs_value" "$zs_fs1"
2N/A if [[ $? != 0 ]]; then
2N/A log "$f_3_zfs_set\n" "$zs_prop" "$zs_value" "$zs_fs1"
2N/A return 1
2N/A fi
2N/A return 0
2N/A}
2N/A
2N/Afunction zfs_set_array {
2N/A zsa_prop=$1
2N/A zsa_value=$2
2N/A typeset -n zsa_array=$3
2N/A zsa_ignore_errors=$4
2N/A
2N/A (( zsa_i = 0 ))
2N/A while (( $zsa_i < ${#zsa_array[@]} )); do
2N/A _zfs_set "$zsa_prop" "$zsa_value" "${zsa_array[$zsa_i]}"
2N/A [[ $? != 0 ]] && [[ -z "$zsa_ignore_errors" ]] &&
2N/A return 1
2N/A (( zsa_i = $zsa_i + 1 ))
2N/A done
2N/A return 0
2N/A}
2N/A
2N/A
2N/A(( snap_rename_zbe_i = 1 ))
2N/A(( snap_rename_snap_i = 1 ))
2N/Afunction snap_rename_init {
2N/A (( snap_rename_zbe_i = 1 ))
2N/A (( snap_rename_snap_i = 1 ))
2N/A}
2N/A
2N/Afunction snap_rename {
2N/A eval sr_fs=\${$1}
2N/A eval sr_snap=\${$2}
2N/A
2N/A if [[ "$sr_snap" == ~(Elr)(zbe-[0-9][0-9]*) ]]; then
2N/A sr_snap="zbe-$snap_rename_zbe_i"
2N/A (( snap_rename_zbe_i = $snap_rename_zbe_i + 1 ))
2N/A elif [[ "$sr_snap" == ~(Er)(_snap[0-9]*) ]]; then
2N/A sr_snap=${sr_snap##~(Er)([0-9]*)}
2N/A sr_snap="${sr_snap}${snap_rename_snap_i}"
2N/A (( snap_rename_snap_i = $snap_rename_snap_i + 1 ))
2N/A else
2N/A log "$f_user_snap\n"
2N/A log "\t$sr_fs@$sr_snap\n"
2N/A fail_fatal "$f_rm_snap\n"
2N/A fi
2N/A
2N/A eval $2="$sr_snap"
2N/A}
2N/A
2N/Afunction destroy_zone_dataset {
2N/A fs=$1
2N/A
2N/A pool=${fs%%/*}
2N/A
2N/A # Fastpath. if there are no snapshots of $fs then just delete it.
2N/A c=`zfs list -H -t snapshot -o name -r $fs | grep "^$fs@" |
2N/A LC_ALL=C LANG=C wc -l`
2N/A if (( $c == 0 )); then
2N/A zfs_destroy "$fs"
2N/A return
2N/A fi
2N/A
2N/A #
2N/A # This zone BE has snapshots. This can happen if a zone has
2N/A # multiple BEs (in which case we have snapshots named "zbe-XXX"),
2N/A # if this zone has been used as the source for a clone of
2N/A # another zone (in which case we have snapshots named
2N/A # "XXX_snap"), or if an administrator has been doing manual
2N/A # snapshotting.
2N/A #
2N/A # To be able to destroy this dataset (which we'll call the
2N/A # origin) we need to get rid of all it's snapshots. The "easiest"
2N/A # way to do this is to:
2N/A #
2N/A # - delete any uncloned origin snapshots
2N/A # - find the oldest clone of the youngest origin snapshot (which
2N/A # we'll call the oldest clone)
2N/A # - check if there are any snapshots naming conflicts between
2N/A # the origin and the oldest clone.
2N/A # - if so, find any clones of those conflicting origin snapshots
2N/A # - make sure that those clones are not zoned an in-use.
2N/A # - if any of those clones are zoned, unzone them.
2N/A # - rename origin snapshots to eliminate naming conflicts
2N/A # - for any clones that we unzoned, rezone them.
2N/A # - promote the oldest clone
2N/A # - destroy the origin and all it's descendants
2N/A #
2N/A
2N/A #
2N/A # Get a list of all the cloned datasets within the zpool
2N/A # containing the origin filesystem. Filter out any filesystems
2N/A # that are descendants of origin because we are planning to
2N/A # destroy them anyway.
2N/A #
2N/A unset clones clones_origin
2N/A (( clones_c = 0 ))
2N/A pool=${fs%%/*}
2N/A LANG=C LC_ALL=C zfs list -H -t filesystem -s creation \
2N/A -o name,origin -r "$pool" |
2N/A while IFS=" " read name origin; do
2N/A
2N/A # skip non-clone filesystems
2N/A [[ "$origin" == "-" ]] &&
2N/A continue
2N/A
2N/A # skip desendents of the origin we plan to destroy
2N/A [[ "$name" == ~()(${fs}/*) ]] &&
2N/A continue
2N/A
2N/A # record this clone and it's origin
2N/A clones[$clones_c]="$name"
2N/A clones_origin[$clones_c]="$origin"
2N/A (( clones_c = $clones_c + 1 ))
2N/A done
2N/A
2N/A #
2N/A # Now do a sanity check. Search for clones of a child datasets
2N/A # of the dataset we want to destroy, that are not themselves
2N/A # children of the dataset we're going to destroy). This should
2N/A # really never happen unless the global zone admin has cloned a
2N/A # snapshot of a zone filesystem to a location outside of that
2N/A # zone. bad admin...
2N/A #
2N/A unset stray_clones
2N/A (( stray_clones_c = 0 ))
2N/A (( j = 0 ))
2N/A while (( $j < $clones_c )); do
2N/A # is the clone origin a descendant of $fs?
2N/A if [[ "${clones_origin[$j]}" != ~()(${fs}/*) ]]; then
2N/A # we don't care.
2N/A (( j = $j + 1 ))
2N/A continue
2N/A fi
2N/A stray_clones[$stray_clones_c]=${clones[$j]}
2N/A (( stray_clones_c = $stray_clones_c + 1 ))
2N/A (( j = $j + 1 ))
2N/A done
2N/A if (( stray_clones_c > 0 )); then
2N/A #
2N/A # sigh. the admin has done something strange.
2N/A # tell them to clean it up and retry.
2N/A #
2N/A log "$f_stray_clone\n"
2N/A print_array stray_clones
2N/A fail_fatal "$f_rm_clone\n"
2N/A exit $ZONE_SUBPROC_FATAL
2N/A fi
2N/A
2N/A # Find all the snapshots of the origin filesystem.
2N/A unset s_origin
2N/A (( s_origin_c = 0 ))
2N/A zfs list -H -t snapshot -s creation -o name -r $fs |
2N/A grep "^$fs@" | while read name; do
2N/A s_origin[$s_origin_c]=$name
2N/A (( s_origin_c = $s_origin_c + 1 ))
2N/A done
2N/A
2N/A #
2N/A # Now go through the origin snapshots and find those which don't
2N/A # have clones. We're going to explicity delete these snapshots
2N/A # before we do the promotion.
2N/A #
2N/A unset s_delete
2N/A (( s_delete_c = 0 ))
2N/A (( j = 0 ))
2N/A while (( $j < $s_origin_c )); do
2N/A (( k = 0 ))
2N/A while (( $k < $clones_c )); do
2N/A # if we have a match then break out of this loop
2N/A [[ "${s_origin[$j]}" == "${clones_origin[$k]}" ]] &&
2N/A break
2N/A (( k = $k + 1 ))
2N/A done
2N/A if (( $k != $clones_c )); then
2N/A # this snapshot has a clone, move on to the next one
2N/A (( j = $j + 1 ))
2N/A continue
2N/A fi
2N/A
2N/A # snapshot has no clones so add it to our delete list
2N/A s_delete[$s_delete_c]=${s_origin[$j]}
2N/A (( s_delete_c = $s_delete_c + 1 ))
2N/A # remove it from the origin snapshot list
2N/A (( k = $j + 1 ))
2N/A while (( $k < $s_origin_c )); do
2N/A s_origin[(( $k - 1 ))]=${s_origin[$k]}
2N/A (( k = $k + 1 ))
2N/A done
2N/A (( s_origin_c = $s_origin_c - 1 ))
2N/A done
2N/A
2N/A #
2N/A # Fastpath. If there are no remaining snapshots then just
2N/A # delete the origin filesystem (and all it's descendents) and
2N/A # move onto the next zone BE.
2N/A #
2N/A if (( $s_origin_c == 0 )); then
2N/A zfs_destroy "$fs"
2N/A return
2N/A fi
2N/A
2N/A # find the youngest snapshot of $fs
2N/A s_youngest=${s_origin[(( $s_origin_c - 1 ))]}
2N/A
2N/A # Find the oldest clone of the youngest snapshot of $fs
2N/A unset s_clone
2N/A (( j = $clones_c - 1 ))
2N/A while (( $j >= 0 )); do
2N/A if [[ "$s_youngest" == "${clones_origin[$j]}" ]]; then
2N/A s_clone=${clones[$j]}
2N/A break
2N/A fi
2N/A (( j = $j - 1 ))
2N/A done
2N/A if [[ -z "$s_clone" ]]; then
2N/A # uh oh. something has gone wrong. bail.
2N/A log "$f_stray_snap\n"
2N/A log "\t$s_youngest\n"
2N/A fail_fatal "$f_rm_snap\n"
2N/A fi
2N/A
2N/A # create an array of clone snapshot names
2N/A unset s_clone_s
2N/A (( s_clone_s_c = 0 ))
2N/A zfs list -H -t snapshot -s creation -o name -r $s_clone |
2N/A grep "^$s_clone@" | while read name; do
2N/A s_clone_s[$s_clone_s_c]=${name##*@}
2N/A (( s_clone_s_c = $s_clone_s_c + 1 ))
2N/A done
2N/A
2N/A # create an arrays of possible origin snapshot renames
2N/A unset s_origin_snap
2N/A unset s_rename
2N/A (( j = 0 ))
2N/A while (( $j < $s_origin_c )); do
2N/A s_origin_snap[$j]=${s_origin[$j]##*@}
2N/A s_rename[$j]=${s_origin[$j]##*@}
2N/A (( j = $j + 1 ))
2N/A done
2N/A
2N/A #
2N/A # Search for snapshot name collisions between the origin and
2N/A # oldest clone. If we find one, generate a new name for the
2N/A # origin snapshot and re-do the collision check.
2N/A #
2N/A snap_rename_init
2N/A (( j = 0 ))
2N/A while (( $j < $s_origin_c )); do
2N/A (( k = 0 ))
2N/A while (( $k < $s_clone_s_c )); do
2N/A
2N/A # if there's no naming conflict continue
2N/A if [[ "${s_rename[$j]}" != "${s_clone_s[$k]}" ]]; then
2N/A (( k = $k + 1 ))
2N/A continue
2N/A fi
2N/A
2N/A #
2N/A # The origin snapshot conflicts with a clone
2N/A # snapshot. Choose a new name and then restart
2N/A # then check that against clone snapshot names.
2N/A #
2N/A snap_rename fs "s_rename[$j]"
2N/A (( k = 0 ))
2N/A continue;
2N/A done
2N/A
2N/A # if we didn't rename this snapshot then continue
2N/A if [[ "${s_rename[$j]}" == "${s_origin_snap[$j]}" ]]; then
2N/A (( j = $j + 1 ))
2N/A continue
2N/A fi
2N/A
2N/A #
2N/A # We need to rename this origin snapshot because it
2N/A # conflicts with a clone snapshot name. So above we
2N/A # chose a name that didn't conflict with any other clone
2N/A # snapshot names. But we also have to avoid naming
2N/A # conflicts with any other origin snapshot names. So
2N/A # check for that now.
2N/A #
2N/A (( k = 0 ))
2N/A while (( $k < $s_origin_c )); do
2N/A
2N/A # don't compare against ourself
2N/A if (( $j == $k )); then
2N/A (( k = $k + 1 ))
2N/A continue
2N/A fi
2N/A
2N/A # if there's no naming conflict continue
2N/A if [[ "${s_rename[$j]}" != "${s_rename[$k]}" ]]; then
2N/A (( k = $k + 1 ))
2N/A continue
2N/A fi
2N/A
2N/A #
2N/A # The new origin snapshot name conflicts with
2N/A # another origin snapshot name. Choose a new
2N/A # name and then go back to check the new name
2N/A # for uniqueness against all the clone snapshot
2N/A # names.
2N/A #
2N/A snap_rename fs "s_rename[$j]"
2N/A continue 2;
2N/A done
2N/A
2N/A #
2N/A # A new unique name has been chosen. Move on to the
2N/A # next origin snapshot.
2N/A #
2N/A (( j = $j + 1 ))
2N/A snap_rename_init
2N/A done
2N/A
2N/A #
2N/A # So now we know what snapshots need to be renamed before the
2N/A # promotion. But there's an additional problem. If any of the
2N/A # filesystems cloned from these snapshots have the "zoned"
2N/A # attribute set (which is highly likely) or if they are in use
2N/A # (and can't be unmounted and re-mounted) then the snapshot
2N/A # rename will fail. So now we'll search for all the clones of
2N/A # snapshots we plan to rename and look for ones that are zoned.
2N/A #
2N/A # We'll ignore any snapshot clones that may be in use but are
2N/A # not zoned. If these clones are in-use, the rename will fail
2N/A # and we'll abort, there's not much else we can do about it.
2N/A # But if they are not in use the snapshot rename will unmount
2N/A # and remount the clone. This is ok because when the zoned
2N/A # attribute is off, we know that the clone was originally
2N/A # mounted from the global zone. (So unmounting and remounting
2N/A # it from the global zone is ok.)
2N/A #
2N/A # But we'll abort this whole operation if we find any clones
2N/A # that that are zoned and in use. (This can happen if another
2N/A # zone has been cloned from this one and is now booted.) The
2N/A # reason we do this is because those zoned filesystems could
2N/A # have originally mounted from within the zone. So if we
2N/A # cleared the zone attribute and did the rename, we'd be
2N/A # remounting the filesystem from the global zone. This would
2N/A # result in the zone losing the ability to unmount the
2N/A # filesystem, which would be bad.
2N/A #
2N/A unset zoned_clones zoned_iu_clones
2N/A (( zoned_clones_c = 0 ))
2N/A (( zoned_iu_clones_c = 0 ))
2N/A (( j = 0 ))
2N/A # walk through all the clones
2N/A while (( $j < $clones_c )); do
2N/A # walk through all the origin snapshots
2N/A (( k = 0 ))
2N/A while (( $k < $s_origin_c )); do
2N/A #
2N/A # check if this clone originated from a snapshot that
2N/A # we need to rename.
2N/A #
2N/A [[ "${clones_origin[$j]}" == "${s_origin[$k]}" ]] &&
2N/A [[ "${s_origin_snap[$k]}" != "${s_rename[$k]}" ]] &&
2N/A break
2N/A (( k = $k + 1 ))
2N/A continue
2N/A done
2N/A if (( $k == $s_origin_c )); then
2N/A # This isn't a clone of a snapshot we want to rename.
2N/A (( j = $j + 1 ))
2N/A continue;
2N/A fi
2N/A
2N/A # get the zoned attr for this clone.
2N/A zoned=`LC_ALL=C LANG=C \
2N/A zfs get -H -o value zoned ${clones[$j]}`
2N/A if [[ "$zoned" != on ]]; then
2N/A # This clone isn't zoned so ignore it.
2N/A (( j = $j + 1 ))
2N/A continue
2N/A fi
2N/A
2N/A # remember this clone so we can muck with it's zoned attr.
2N/A zoned_clones[$zoned_clones_c]=${clones[$j]}
2N/A (( zoned_clones_c = $zoned_clones_c + 1 ))
2N/A
2N/A # check if it's in use
2N/A mounted=`LC_ALL=C LANG=C \
2N/A zfs get -H -o value mounted ${clones[$j]}`
2N/A if [[ "$mounted" != yes ]]; then
2N/A # Good news. This clone isn't in use.
2N/A (( j = $j + 1 ))
2N/A continue
2N/A fi
2N/A
2N/A # Sigh. This clone is in use so we're destined to fail.
2N/A zoned_iu_clones[$zoned_iu_clones_c]=${clones[$j]}
2N/A (( zoned_iu_clones_c = $zoned_iu_clones_c + 1 ))
2N/A
2N/A # keep looking for errors so we can report them all at once.
2N/A (( j = $j + 1 ))
2N/A done
2N/A if (( zoned_iu_clones_c > 0 )); then
2N/A #
2N/A # Tell the admin
2N/A #
2N/A log "$f_iu_clone\n"
2N/A print_array zoned_iu_clones
2N/A fail_fatal "$f_dis_clone\n"
2N/A fi
2N/A
2N/A #
2N/A # Ok. So we're finally done with planning and we can do some
2N/A # damage. We're going to:
2N/A # - destroy unused snapshots
2N/A # - unzone clones which originate from snapshots we need to rename
2N/A # - rename conflicting snapshots
2N/A # - rezone any clones which we unzoned
2N/A # - promote the oldest clone of the youngest snapshot
2N/A # - finally destroy the origin filesystem.
2N/A #
2N/A
2N/A # delete any unsed snapshot
2N/A (( j = 0 ))
2N/A while (( $j < $s_delete_c )); do
2N/A zfs_destroy "${s_delete[$j]}"
2N/A (( j = $j + 1 ))
2N/A done
2N/A
2N/A # unzone clones
2N/A zfs_set_array zoned off zoned_clones ||
2N/A zfs_set_array zoned on zoned_clones 1
2N/A
2N/A # rename conflicting snapshots
2N/A (( j = 0 ))
2N/A while (( $j < $s_origin_c )); do
2N/A if [[ "${s_origin_snap[$j]}" != "${s_rename[$j]}" ]]; then
2N/A zfs_rename "${s_origin[$j]}" "$fs@${s_rename[$j]}"
2N/A if [[ $? != 0 ]]; then
2N/A # re-zone the clones before aborting
2N/A zfs_set_array zoned on zoned_clones 1
2N/A exit $ZONE_SUBPROC_FATAL
2N/A fi
2N/A fi
2N/A (( j = $j + 1 ))
2N/A done
2N/A
2N/A # re-zone the clones
2N/A zfs_set_array zoned on zoned_clones 1
2N/A
2N/A # promote the youngest clone of the oldest snapshot
2N/A zfs_promote "$s_clone"
2N/A
2N/A # destroy the origin filesystem and it's descendants
2N/A zfs_destroy "$fs"
2N/A}
2N/A
2N/A#
2N/A# destroy_zone_datasets
2N/A#
2N/A# Destroys datasets associated with a zone. If the -b option is used, the
2N/A# specified boot environments under $ZONEPATH_DS/rpool/ROOT are destroyed.
2N/A# If the -a option is used, all boot environments are destroyed. If, after
2N/A# processing -a and -b options, there are no boot environments left, all
2N/A# remaining datasets belonging to the zone are destroyed.
2N/A#
2N/A# Options and Arguments
2N/A#
2N/A# -a Destroy all boot environments
2N/A# -b <be array> Destroy the boot environments listed in this array.
2N/A# zonepath_dataset The zonepath dataset for the zone
2N/A#
2N/A# Globals:
2N/A#
2N/A# ZONEPATH_RDS The zone's root dataset
2N/A#
2N/A# Example:
2N/A# typeset -a dslist
2N/A# dslist[0]=...
2N/A# destroy_zone_datasets dslist
2N/A#
2N/Afunction destroy_zone_datasets {
2N/A typeset opt be
2N/A typeset -i opt_a=0 opt_b=0
2N/A typeset -a dslist
2N/A typeset -i i # temp used while iterating
2N/A typeset -i rv=0 # return value
2N/A typeset belist
2N/A typeset -n zone="$1"
2N/A
2N/A shift
2N/A while getopts :ab: opt; do
2N/A case $opt in
2N/A a) (( opt_a=1 ))
2N/A ;;
2N/A b) (( opt_b=1 ))
2N/A typeset -n belist="$OPTARG"
2N/A ;;
2N/A ?) fail_fatal "$f_int_bad_opt" "$OPTARG" "${.sh.file}" \
2N/A "${.sh.fun}"
2N/A ;;
2N/A esac
2N/A done
2N/A shift $(( OPTIND - 1 ))
2N/A
2N/A (( opt_a + opt_b > 1 )) && fail_internal "$f_int_bad_opt_combo" a b
2N/A [[ -z "${zone.name}" ]] && fail_internal "$f_int_missing_arg" zone
2N/A
2N/A #
2N/A # It is possible that the zone structure hasn't initialized zone.path
2N/A # yet. This could be because of an interruption between the time that
2N/A # the zonepath dataset was created and the initialization or it could
2N/A # be because there is no such dataset.
2N/A #
2N/A if [[ -z "${zone.path.ds}" ]]; then
2N/A set -- $(zonecfg -z "$ref" info zonepath 2>/dev/null)
2N/A # Leverage the zone.path.set discipline function.
2N/A zone.path=$2
2N/A # If it is still undefined, zonepath dataset doesn't exist.
2N/A [[ -z ${zone.path.ds} ]] && return 0
2N/A fi
2N/A
2N/A #
2N/A # Delete any boot environments that were passed in
2N/A #
2N/A for be in "${belist[@]}" ; do
2N/A vlog "Destroying zbe: %s" "$be"
2N/A get_datasets "${zone.ROOT_ds}/$be" dslist
2N/A if (( $? != 0 )); then
2N/A error "$e_no_such_dataset" "${zone.ROOT_ds}/$be"
2N/A continue
2N/A fi
2N/A
2N/A # Destroy the datasets starting with the most nested
2N/A i=${#dslist[@]}
2N/A for (( i = ${#dslist[@]} - 1; i >= 0; i-- )); do
2N/A destroy_zone_dataset "${dslist[$i]}"
2N/A done
2N/A
2N/A # Check to be sure that none remain
2N/A get_datasets "${zone.ROOT_ds}/$be" dslist
2N/A if (( $? == 0 )); then
2N/A error "$f_1_zfs_destroy" "${dslist[*]}"
2N/A rv=1
2N/A fi
2N/A done
2N/A
2N/A #
2N/A # Check to see if rpool/ROOT is empty. If so, pretend -a was passed
2N/A # in and delete the rest of the zone datasets.
2N/A #
2N/A typeset -i dscount=0
2N/A if [[ -n "${zone.ROOT_ds}" ]]; then
2N/A get_datasets "${zone.ROOT_ds}" dslist
2N/A if (( $? == 0 )); then
2N/A dscount=$(( ${#dslist[@]} - 1 ))
2N/A fi
2N/A fi
2N/A
2N/A if (( opt_a == 1 || dscount == 0 )); then
2N/A # If there are no datasets at zone.path.ds there's nothing to do
2N/A get_datasets "${zone.path.ds}" dslist || return 0
2N/A
2N/A #
2N/A # Destroy the datasets in an order that ensures children
2N/A # go before parents
2N/A #
2N/A for (( i = ${#dslist[@]} - 1; i >= 0; i-- )); do
2N/A vlog "Destroying zone dataset: %s" "${dslist[$i]}"
2N/A destroy_zone_dataset "${dslist[$i]}"
2N/A done
2N/A
2N/A # Check to be sure that none remain
2N/A get_datasets "${zone.path.ds}" dslist
2N/A if (( $? == 0 )); then
2N/A rv=1
2N/A fi
2N/A fi
2N/A
2N/A return $rv
2N/A}