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