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