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