source: overlays/install-overlay/root/beadm.install @ aad2985

9.2-releasereleng/10.0releng/10.0.1releng/10.0.2
Last change on this file since aad2985 was aad2985, checked in by Kris Moore <kris@…>, 10 months ago

Remove version check

  • Property mode set to 100755
File size: 24.2 KB
Line 
1#!/bin/sh -e
2
3# Copyright (c) 2012 Slawomir Wojciech Wojtczak (vermaden). All rights reserved.
4# Copyright (c) 2012 Bryan Drewery (bdrewery). All rights reserved.
5# Copyright (c) 2012 Mike Clarke (rawthey). All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that following conditions are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS 'AS IS' AND ANY
16# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
19# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26unset LC_ALL
27unset LANG
28PATH=${PATH}:/bin:/usr/bin:/sbin:/usr/sbin
29
30__usage() {
31  local NAME=${0##*/}
32  echo "usage:"
33  echo "  ${NAME} activate <beName>"
34  echo "  ${NAME} create [-e nonActiveBe | -e beName@snapshot] <beName>"
35  echo "  ${NAME} create <beName@snapshot>"
36  echo "  ${NAME} destroy [-F] <beName | beName@snapshot>"
37  echo "  ${NAME} list [-a] [-s] [-D] [-H]"
38  echo "  ${NAME} rename <origBeName> <newBeName>"
39  echo "  ${NAME} mount <beName> [mountpoint]"
40  echo "  ${NAME} { umount | unmount } [-f] <beName>"
41  exit 1
42}
43
44# check if boot environment exists
45__be_exist() { # 1=DATASET
46  if ! zfs list -H -o name ${1} 1> /dev/null 2> /dev/null
47  then
48    echo "ERROR: Boot environment '${1##*/}' does not exist"
49    exit 1
50  fi
51}
52
53# check if argument is a snapshot
54__be_snapshot() { # 1=DATASET/SNAPSHOT
55  echo "${1}" | grep -q "@" 2> /dev/null
56}
57
58# check if boot environment is mounted
59__be_mounted() { # 1=BE
60  mount 2> /dev/null | grep -q -E "^${1} " 2> /dev/null
61}
62
63# check if boot environment is a clone
64__be_clone() { # 1=DATASET
65  if zfs list ${1} 1> /dev/null 2> /dev/null
66  then
67    local ORIGIN="$( zfs list -H -o origin ${1} )"
68    if [ "${ORIGIN}" = "-" ]
69    then
70      # boot environment is not a clone
71      return 1
72    else
73      # boot environment is a clone
74      return 0
75    fi
76  else
77    # boot environment does not exist
78    return 2
79  fi
80}
81
82# create new boot environment
83__be_new() { # 1=SOURCE 2=TARGET
84  local SOURCE=$( echo ${1} | cut -d '@' -f 1 )
85  if __be_snapshot ${1}
86  then
87    # create boot environment from snapshot
88    local SNAPSHOT=$( echo ${1} | cut -d '@' -f 2 )
89    zfs list -r -H -t filesystem -o name ${SOURCE} \
90      | while read FS
91        do
92          if ! zfs list -H -o name ${FS}@${SNAPSHOT} 1> /dev/null 2> /dev/null
93          then
94            echo "ERROR: Child snapshot '${FS}@${SNAPSHOT}' does not exist"
95            exit 1
96          fi
97        done
98  else
99    # create boot environment from other boot environment
100    if zfs list -H -o name ${1}@${2##*/} 1> /dev/null 2> /dev/null
101    then
102      echo "ERROR: Snapshot '${1}@${2##*/}' already exists"
103      exit 1
104    fi
105    # snapshot format
106    FMT=$( date "+%Y-%m-%d-%H:%M:%S" )
107    if ! zfs snapshot -r ${1}@${FMT} 1> /dev/null 2> /dev/null
108    then
109      echo "ERROR: Cannot create snapshot '${1}@${FMT}'"
110      exit 1
111    fi
112  fi
113  # clone properties of source boot environment
114  zfs list -H -o name -r ${SOURCE} \
115    | while read FS
116      do
117        local OPTS=""
118        while read NAME PROPERTY VALUE
119        do
120          local OPTS="-o ${PROPERTY}=${VALUE} ${OPTS}"
121        done << EOF
122$( zfs get -o name,property,value -s local,received -H all ${FS} | awk '!/[\t ]canmount[\t ]/' )
123EOF
124        DATASET=$( echo ${FS} | awk '{print $1}' | sed -E s/"^${POOL}\/ROOT\/${SOURCE##*/}"/"${POOL}\/ROOT\/${2##*/}"/g )
125        if [ "${OPTS}" = "-o = " ]
126        then
127          local OPTS=""
128        fi
129        if __be_snapshot ${1}
130        then
131          zfs clone -o canmount=off ${OPTS} ${FS}@${1##*@} ${DATASET}
132        else
133          zfs clone -o canmount=off ${OPTS} ${FS}@${FMT} ${DATASET}
134        fi
135      done
136}
137
138ROOTFS=$( mount | awk '/ \/mnt / {print $1}' )
139
140if echo ${ROOTFS} | grep -q -m 1 -E "^/dev/"
141then
142  echo "ERROR: This system does not boot from ZFS pool"
143  exit 1
144fi
145
146POOL=$( echo ${ROOTFS} | awk -F '/' '{print $1}' )
147
148if ! zfs list ${POOL}/ROOT 1> /dev/null 2> /dev/null
149then
150  echo "ERROR: This system is not configured for boot environments"
151  exit 1
152fi
153
154BOOTFS=$( zpool list -H -o bootfs ${POOL} )
155
156if [ -z "${BOOTFS}" -o "${BOOTFS}" = "-" ]
157then
158 echo "ERROR: ZFS boot pool '${POOL}' has unset 'bootfs' property"
159 exit 1
160fi
161
162case ${1} in
163
164  (list) # --------------------------------------------------------------------
165    OPTION_a=0
166    OPTION_D=0
167    OPTION_s=0
168    shift
169    while getopts "aDHs" OPT
170    do
171      case ${OPT} in
172        (a) OPTION_a=1 ;;
173        (D) OPTION_D=1 ;;
174        (H) OPTION_H=1 ;;
175        (s) OPTION_s=1
176            OPTION_a=1 ;;
177        (*) __usage    ;;
178      esac
179    done
180    awk -v POOL="${POOL}" \
181        -v ROOTFS="${ROOTFS}" \
182        -v BOOTFS="${BOOTFS}" \
183        -v OPTION_a="${OPTION_a}" \
184        -v OPTION_D="${OPTION_D}" \
185        -v OPTION_H="${OPTION_H}" \
186        -v OPTION_s="${OPTION_s}" \
187     'function __normalize(VALUE) {
188        if(VALUE == "-" || VALUE == 0)
189          return 0
190        else
191          return substr(VALUE, 1, length(VALUE) - 1) * MULTIPLIER[substr(VALUE, length(VALUE))]
192      }
193      function __show_units(VALUE) {
194             if(VALUE < 1024)                {                               UNIT = "K"; }
195        else if(VALUE < 1048576)             { VALUE /= 1024;                UNIT = "M"; }
196        else if(VALUE < 1073741824)          { VALUE /= 1048576;             UNIT = "G"; }
197        else if(VALUE < 1099511627776)       { VALUE /= 1073741824;          UNIT = "T"; }
198        else if(VALUE < 1125899906842624)    { VALUE /= 1099511627776;       UNIT = "P"; }
199        else if(VALUE < 1152921504606846976) { VALUE /= 1125899906842624;    UNIT = "E"; }
200        else                                 { VALUE /= 1152921504606846976; UNIT = "Z"; }
201        return sprintf("%.1f%s", VALUE, UNIT)
202      }
203      function __get_bename(BENAME) {
204        sub(BENAME_BEGINS_WITH "\/", "", BENAME)
205        sub("/.*", "", BENAME)
206        return BENAME
207      }
208      function __convert_date(DATE) {
209        CMD_DATE = "date -j -f \"%a %b %d %H:%M %Y\" \"" DATE "\" +\"%Y-%m-%d %H:%M\""
210        CMD_DATE | getline NEW
211        close(CMD_DATE)
212        return NEW
213      }
214      BEGIN {
215        BENAME_BEGINS_WITH = POOL "/ROOT"
216        MULTIPLIER["K"] = 1
217        MULTIPLIER["M"] = 1024
218        MULTIPLIER["G"] = 1048576
219        MULTIPLIER["T"] = 1073741824
220        MULTIPLIER["P"] = 1099511627776
221        MULTIPLIER["E"] = 1125899906842624
222        MULTIPLIER["Z"] = 1152921504606846976
223        MOUNTPOINT_LENGTH = 10
224        FSNAME_LENGTH = 2
225        if(OPTION_a == 1)
226          FSNAME_LENGTH = 19
227        CMD_MOUNT="mount"
228        while(CMD_MOUNT | getline)
229          if($1 ~ "^" BENAME_BEGINS_WITH)
230            MOUNTS[$1] = $3
231        close(CMD_MOUNT)
232        FS = "\\t"
233        CMD_ZFS_LIST = "zfs list -H -t all -s creation -o name,used,usedds,usedbysnapshots,usedrefreserv,refer,creation,origin -r "
234        while(CMD_ZFS_LIST BENAME_BEGINS_WITH | getline) {
235          if($1 != BENAME_BEGINS_WITH) {
236            FSNAME = $1
237            FSNAMES[length(FSNAMES) + 1] = FSNAME
238            USED              = __normalize($2)
239            USEDBYDATASET     = __normalize($3)
240            USEDBYSNAPSHOTS   = __normalize($4)
241            USEDREFRESERV     = __normalize($5)
242            REFER[FSNAME]     = __normalize($6)
243            CREATIONS[FSNAME] = $7
244            ORIGINS[FSNAME]   = $8
245            if(FSNAME ~ /@/)
246              SPACES[FSNAME] = USED
247            else {
248              SPACES[FSNAME] = USEDBYDATASET + USEDREFRESERV
249              if(OPTION_D != 1)
250                SPACES[FSNAME] += USEDBYSNAPSHOTS
251              BE = " " __get_bename(FSNAME) " "
252              if(index(BELIST, BE) == 0)
253                BELIST = BELIST " " BE
254              MOUNTPOINT = MOUNTS[FSNAME]
255              if(MOUNTPOINT) {
256                if((OPTION_a == 0 && FSNAME == (BENAME_BEGINS_WITH "/" __get_bename(FSNAME))) || (OPTION_a == 1)) {
257                  LM = length(MOUNTPOINT)
258                  if(LM > MOUNTPOINT_LENGTH)
259                    MOUNTPOINT_LENGTH = LM
260                }
261              }
262              else
263                MOUNTPOINT = "-"
264            }
265            if(OPTION_a == 1)
266              LF = length(FSNAME)
267            else if(FSNAME !~ /@/)
268              LF = length(__get_bename(FSNAME))
269            if(LF > FSNAME_LENGTH)
270              FSNAME_LENGTH = LF
271          }
272        }
273        close(CMD_ZFS_LIST)
274        split(BELIST, BENAMES, " ")
275        if(OPTION_a == 1) {
276          BE_HEAD = "BE/Dataset/Snapshot"
277          printf "%-" FSNAME_LENGTH + 2 "s %-6s %-" MOUNTPOINT_LENGTH "s %6s %s\n", BE_HEAD, "Active", "Mountpoint", "Space", "Created"
278        }
279        else if(OPTION_H == 1)
280          BE_HEAD = ""
281        else {
282          BE_HEAD = "BE"
283          printf "%-" FSNAME_LENGTH "s %-6s %-" MOUNTPOINT_LENGTH "s %6s %s\n", BE_HEAD, "Active", "Mountpoint", "Space", "Created"
284        }
285        if(OPTION_s != 1)
286          SNAPSHOT_FILTER = "(/[^@]*)?$"
287        for(I = 1; I <= length(BENAMES); I++) {
288          BENAME = BENAMES[I]
289          if(OPTION_a == 1) {
290            printf "\n"
291            print BENAME
292            for(J = 1; J <= length(FSNAMES); J++) {
293              FSNAME = FSNAMES[J]
294              if(FSNAME ~ "^" BENAME_BEGINS_WITH "/" BENAME SNAPSHOT_FILTER) {
295                ACTIVE = ""
296                if(FSNAME == ROOTFS)
297                  ACTIVE = ACTIVE "N"
298                if(FSNAME == BOOTFS)
299                  ACTIVE = ACTIVE "R"
300                if(! ACTIVE)
301                  ACTIVE = "-"
302                MOUNTPOINT = MOUNTS[FSNAME]
303                if(! MOUNTPOINT)
304                  MOUNTPOINT = "-"
305                printf "  %-" FSNAME_LENGTH "s %-6s %-" MOUNTPOINT_LENGTH "s %6s %s\n", FSNAME, ACTIVE, MOUNTPOINT, __show_units(SPACES[FSNAME]), __convert_date(CREATIONS[FSNAME])
306                ORIGIN = ORIGINS[FSNAME]
307                ORIGIN_DISPLAY = ORIGIN
308                sub(BENAME_BEGINS_WITH "/", "", ORIGIN_DISPLAY)
309                if(ORIGIN != "-") {
310                  if(OPTION_D == 1)
311                    SPACE = REFER[ORIGIN]
312                  else
313                    SPACE = SPACES[ORIGIN]
314                  printf  "  %-" FSNAME_LENGTH "s %-6s %-" MOUNTPOINT_LENGTH "s %6s %s\n", "  " ORIGIN_DISPLAY, "-", "-", __show_units(SPACE), __convert_date(CREATIONS[ORIGIN])
315                }
316              }
317            }
318          }
319          else {
320            SPACE = 0
321            ACTIVE = ""
322            NAME = BENAME_BEGINS_WITH "/" BENAME
323            if(NAME == ROOTFS)
324              ACTIVE = ACTIVE "N"
325            if(NAME == BOOTFS)
326              ACTIVE = ACTIVE "R"
327            if(! ACTIVE)
328              ACTIVE = "-"
329            for(J = 1; J <= length(FSNAMES); J++) {
330              FSNAME = FSNAMES[J]
331              if(FSNAME ~ "^" BENAME_BEGINS_WITH "/" BENAME "(/[^@]*)?$") {
332                if((BENAME_BEGINS_WITH "/" BENAME) == FSNAME) {
333                  MOUNTPOINT = MOUNTS[FSNAME]
334                  if(! MOUNTPOINT)
335                    MOUNTPOINT = "-"
336                  CREATION = __convert_date(CREATIONS[FSNAME])
337                }
338                ORIGIN = ORIGINS[FSNAME]
339                if(ORIGIN == "-")
340                  SPACE += SPACES[FSNAME]
341                else {
342                  if(OPTION_D == 1)
343                    SPACE += REFER[FSNAME]
344                  else
345                    SPACE += SPACES[FSNAME] + SPACES[ORIGIN]
346                }
347              }
348            }
349            if(OPTION_H == 1)
350              printf "%s\t%s\t%s\t%s\t%s\n", BENAME, ACTIVE, MOUNTPOINT, __show_units(SPACE), CREATION
351            else
352              printf "%-" FSNAME_LENGTH "s %-6s %-" MOUNTPOINT_LENGTH "s %6s %s\n", BENAME, ACTIVE, MOUNTPOINT, __show_units(SPACE), CREATION
353          }
354        }
355      }'
356    ;;
357
358  (create) # ------------------------------------------------------------------
359    case ${#} in
360      (4)
361        if ! [ ${2} = "-e" ]
362        then
363          __usage
364        fi
365        # check if argument for -e option is full path dataset
366        # argument for -e option must be 'beName' or 'beName@snapshot'
367        if echo ${3} | grep -q "/" 2> /dev/null
368        then
369          __usage
370        fi
371        __be_exist ${POOL}/ROOT/${3}
372        if zfs list -H -o name ${POOL}/ROOT/${4} 1> /dev/null 2> /dev/null
373        then
374          echo "ERROR: Boot environment '${4}' already exists"
375          exit 1
376        fi
377        __be_new ${POOL}/ROOT/${3} ${POOL}/ROOT/${4}
378        ;;
379      (2)
380        if __be_snapshot ${2}
381        then
382          if ! zfs snapshot -r ${POOL}/ROOT/${2} 1> /dev/null 2> /dev/null
383          then
384            echo "ERROR: Cannot create '${2}' recursive snapshot"
385            exit 1
386          fi
387        else
388          __be_new ${ROOTFS} ${POOL}/ROOT/${2}
389        fi
390        ;;
391      (*)
392        __usage
393        ;;
394    esac
395    echo "Created successfully"
396    ;;
397
398  (activate) # ----------------------------------------------------------------
399    if [ ${#} -ne 2 ]
400    then
401      __usage
402    fi
403    __be_exist ${POOL}/ROOT/${2}
404    if [ "${BOOTFS}" = "${POOL}/ROOT/${2}" ]
405    then
406      echo "Already activated"
407      exit 0
408    else
409      if __be_mounted ${POOL}/ROOT/${2}
410      then
411        MNT=$( mount | grep -E "^${POOL}/ROOT/${2} " | awk '{print $3}' )
412        if [ "${MNT}" != "/" ]
413        then
414          # boot environment is not current root and its mounted
415          echo "ERROR: Boot environment '${2}' is mounted at '${MNT}'"
416          echo "ERROR: Cannot activate manually mounted boot environment"
417          exit 1
418        fi
419      fi
420      # do not change root (/) mounted boot environment mountpoint
421      if [ "${ROOTFS}" != "${POOL}/ROOT/${2}" ]
422      then
423        TMPMNT=$( mktemp -d -t BE-${2} )
424        if ! mkdir -p ${TMPMNT} 2> /dev/null
425        then
426          echo "ERROR: Cannot create '${TMPMNT}' directory"
427          exit 1
428        fi
429        MOUNT=0
430        while read FS MNT TYPE OPTS DUMP FSCK;
431        do
432          if [ "${FS}" = "${POOL}/ROOT/${2}" ]
433          then
434            MOUNT=${MNT}
435            break
436          fi
437        done << EOF
438$( mount -p )
439EOF
440        if [ ${MOUNT} -eq 0 ]
441        then
442          zfs set canmount=noauto ${POOL}/ROOT/${2}
443          zfs set mountpoint=${TMPMNT} ${POOL}/ROOT/${2}
444          zfs mount ${POOL}/ROOT/${2}
445        else
446          TMPMNT=${MOUNT}
447        fi
448        cp /boot/zfs/zpool.cache ${TMPMNT}/boot/zfs/zpool.cache
449        LOADER_CONFIGS=${TMPMNT}/boot/loader.conf
450        if [ -f ${TMPMNT}/boot/loader.conf.local ]
451        then
452          LOADER_CONFIGS="${LOADER_CONFIGS} ${TMPMNT}/boot/loader.conf.local"
453        fi
454        sed -i '' -E s/"^vfs.root.mountfrom=.*$"/"vfs.root.mountfrom=\"zfs:${POOL}\/ROOT\/${2##*/}\""/g ${LOADER_CONFIGS}
455        if [ ${MOUNT} -eq 0 ]
456        then
457          zfs umount ${POOL}/ROOT/${2}
458          zfs set mountpoint=legacy ${POOL}/ROOT/${2}
459        fi
460      fi
461      if ! zpool set bootfs=${POOL}/ROOT/${2} ${POOL} 1> /dev/null 2> /dev/null
462      then
463        echo "ERROR: Failed to activate '${2}' boot environment"
464        exit 1
465      fi
466    fi
467    # execute ZFS LIST only once
468    ZFS_LIST=$( zfs list -H -o name -r ${POOL}/ROOT )
469    # disable automatic mount on all inactive boot environments
470    echo "${ZFS_LIST}" \
471      | grep -v "^${POOL}/ROOT/${2}$" \
472      | grep -v "^${POOL}/ROOT/${2}/" \
473      | while read NAME
474        do
475          zfs set canmount=noauto ${NAME}
476        done
477    # enable automatic mount for active boot environment and promote it
478    echo "${ZFS_LIST}" \
479      | grep -E "^${POOL}/ROOT/${2}(/|$)" \
480      | while read NAME
481        do
482          zfs set canmount=on ${NAME}
483          while __be_clone ${NAME}
484          do
485            zfs promote ${NAME}
486          done
487        done
488    echo "Activated successfully"
489    ;;
490
491  (destroy) # -----------------------------------------------------------------
492    if [ "${2}" != "-F" ]
493    then
494      DESTROY=${2}
495    else
496      DESTROY=${3}
497    fi
498    __be_exist ${POOL}/ROOT/${DESTROY}
499    case ${#} in
500      (2)
501        echo "Are you sure you want to destroy '${2}'?"
502        echo -n "This action cannot be undone (y/[n]): "
503        read CHOICE
504        ;;
505      (3)
506        if [ "${2}" != "-F" ]
507        then
508          __usage
509        fi
510        CHOICE=Y
511        ;;
512      (*)
513        __usage
514        ;;
515    esac
516    if [ "${BOOTFS}" = "${POOL}/ROOT/${DESTROY}" ]
517    then
518      echo "ERROR: Cannot destroy active boot environment"
519      exit 1
520    fi
521    case ${CHOICE} in
522      (Y|y|[Yy][Ee][Ss])
523        # destroy snapshot or boot environment
524        if __be_snapshot ${POOL}/ROOT/${DESTROY}
525        then
526          # destroy desired snapshot
527          if ! zfs destroy -r ${POOL}/ROOT/${DESTROY} 1> /dev/null 2> /dev/null
528          then
529            echo "ERROR: Snapshot '${2}' is origin for other boot environment"
530            exit 1
531          fi
532        else
533          if __be_clone ${POOL}/ROOT/${DESTROY}
534          then
535            # promote clones dependent on snapshots used by destroyed boot environment
536            zfs list -H -t all -o name,origin \
537              | while read NAME ORIGIN
538                do
539                  if echo "${ORIGIN}" | grep -q -E "${POOL}/ROOT/${DESTROY}(/.*@|@)" 2> /dev/null
540                  then
541                    zfs promote ${NAME}
542                  fi
543                done
544            # get origins used by destroyed boot environment
545            ORIGIN_SNAPSHOTS=$( zfs list -H -t all -o origin -r ${POOL}/ROOT/${DESTROY} | grep -v '^-$' | awk -F "@" '{print $2}' | sort -u )
546          fi
547          # check if boot environment was created from existing snapshot
548          ORIGIN=$( zfs list -H -o origin ${POOL}/ROOT/${DESTROY} )
549          CREATION=$( zfs list -H -o creation ${POOL}/ROOT/${DESTROY} )
550          CREATION=$( date -j -f "%a %b %d %H:%M %Y" "${CREATION}" +"%Y-%m-%d-%H:%M" )
551          SNAPSHOT_NAME=$( echo "${ORIGIN}" | cut -d '@' -f 2 | sed -E 's/:[0-9]{2}$//g' )
552          if [ "${2}" = "-F" ]
553          then
554            CHOICE=1
555          elif [ "${SNAPSHOT_NAME}" != "${CREATION}" ]
556          then
557            ORIGIN=$( basename ${ORIGIN} )
558            echo "Boot environment '${DESTROY}' was created from existing snapshot"
559            echo -n "Destroy '${ORIGIN}' snapshot? (y/[n]): "
560            read CHOICE
561            case ${CHOICE} in
562              (Y|y|[Yy][Ee][Ss])
563                CHOICE=1
564                ;;
565              (*)
566                CHOICE=0
567                echo "Origin snapshot '${ORIGIN}' will be preserved"
568                ;;
569            esac
570          else
571            CHOICE=1
572          fi
573          # destroy boot environment
574          zfs destroy -r ${POOL}/ROOT/${DESTROY}
575          # check if boot environment is a clone
576          if __be_clone ${POOL}/ROOT/${DESTROY}
577          then
578            # promote datasets dependent on origins used by destroyed boot environment
579            ALL_ORIGINS=$( zfs list -H -t all -o name,origin )
580            echo "${ORIGIN_SNAPSHOTS}" \
581              | while read S
582                do
583                  echo "${ALL_ORIGINS}" \
584                    | grep "${S}" \
585                    | awk '{print $1}' \
586                    | while read I
587                      do
588                        zfs promote ${I}
589                      done
590                done
591          fi
592          # destroy origins used by destroyed boot environment
593          SNAPSHOTS=$( zfs list -H -t snapshot -o name )
594          echo "${ORIGIN_SNAPSHOTS}" \
595            | while read S
596              do
597                echo "${SNAPSHOTS}" \
598                  | grep "@${S}$" \
599                  | while read I
600                    do
601                      if [ ${CHOICE} -eq 1 ]
602                      then
603                        zfs destroy ${I}
604                      fi
605                    done
606              done
607        fi
608        echo "Destroyed successfully"
609        ;;
610      (*)
611        echo "Boot environment '${DESTROY}' has not been destroyed"
612        ;;
613    esac
614    ;;
615
616  (rename) # ------------------------------------------------------------------
617    if [ ${#} -ne 3 ]
618    then
619      __usage
620    fi
621    __be_exist ${POOL}/ROOT/${2}
622    if [ "${BOOTFS}" = "${POOL}/ROOT/${2}" ]
623    then
624      echo "ERROR: Renaming active boot environment is not supported"
625      exit 1
626    fi
627    if zfs list -H -o name ${POOL}/ROOT/${3} 2> /dev/null
628    then
629      echo "ERROR: Boot environment '${3}' already exists"
630      exit 1
631    fi
632    zfs rename ${POOL}/ROOT/${2} ${POOL}/ROOT/${3}
633    echo "Renamed successfully"
634    ;;
635
636  (mount) # ------------------------------------------------------------
637    if [ ${#} -eq 2 ]
638    then
639      TARGET=$( mktemp -d -t BE-${2} )
640    elif [ ${#} -eq 3 ]
641    then
642      TARGET=${3}
643    else
644      __usage
645    fi
646    __be_exist "${POOL}/ROOT/${2}"
647    if __be_mounted "${POOL}/ROOT/${2}"
648    then
649      MNT=$( mount | grep -E "^${POOL}/ROOT/${2} " | awk '{print $3}' )
650      echo "Boot environment '${2}' is already mounted at '${MNT}'"
651      exit 1
652    fi
653    if ! mkdir -p ${TARGET} 2> /dev/null
654    then
655      echo "ERROR: Cannot create '${TARGET}' mountpoint"
656      exit 1
657    fi
658    if ! mount -t zfs ${POOL}/ROOT/${2} ${TARGET}
659    then
660      echo "ERROR: Cannot mount '${2}' at '${TARGET}' mountpoint"
661      exit 1
662    fi
663    PREFIX=$( echo ${POOL}/ROOT/${2}/ | sed 's/\//\\\//g' )
664    zfs list -H -o name,mountpoint -r ${POOL}/ROOT/${2} \
665      | grep -v -E "[[:space:]](legacy|none)$" \
666      | sort -n \
667      | grep -E "^${POOL}/ROOT/${2}/" \
668      | while read FS MOUNTPOINT
669        do
670          if [ "{FS}" != "${POOL}/ROOT/${2}" ]
671          then
672            INHERIT=$( zfs get -H -o source mountpoint ${FS} )
673            if [ "${INHERIT}" = "local" ]
674            then
675              case ${MOUNTPOINT} in
676                (legacy|none)
677                  continue
678                  ;;
679                (*)
680                  MOUNTPOINT="/$( echo "${FS}" | sed s/"${PREFIX}"//g )"
681                  ;;
682              esac
683            fi
684          fi
685          if ! mkdir -p ${TARGET}${MOUNTPOINT} 1> /dev/null 2> /dev/null
686          then
687            echo "ERROR: Cannot create '${TARGET}${MOUNTPOINT}' mountpoint"
688            exit 1
689          fi
690          if ! mount -t zfs ${FS} ${TARGET}${MOUNTPOINT} 1> /dev/null 2> /dev/null
691          then
692            echo "ERROR: Cannot mount '${FS}' at '${TARGET}${MOUNTPOINT}' mountpoint"
693            exit 1
694          fi
695        done
696    echo "Mounted successfully on '${TARGET}'"
697    ;;
698
699  (umount|unmount) # ----------------------------------------------------------
700    if [ ${#} -eq 2 ]
701    then
702      # we need this empty section for argument checking
703      :
704    elif [ ${#} -eq 3 -a "${2}" = "-f" ]
705    then
706      OPTS="-f"
707      shift
708    else
709      __usage
710    fi
711    __be_exist "${POOL}/ROOT/${2}"
712    if ! __be_mounted "${POOL}/ROOT/${2}"
713    then
714      echo "Boot environment '${2}' is not mounted"
715      exit 1
716    fi
717    MOUNT=$( mount )
718    MOUNTPOINT=$( echo "${MOUNT}" | grep -m 1 "^${POOL}/ROOT/${2} on " | awk '{print $3}' )
719    echo "${MOUNT}" \
720      | awk '{print $1}' \
721      | grep -E "^${POOL}/ROOT/${2}(/|$)" \
722      | sort -n -r \
723      | while read FS
724        do
725          if ! umount ${OPTS} ${FS} 1> /dev/null 2> /dev/null
726          then
727            echo "ERROR: Cannot umount '${FS}' dataset"
728            exit 1
729          fi
730        done
731    echo "Unmounted successfully"
732    # only delete the temporary mountpoint directory
733    if echo "${MOUNTPOINT}" | grep -q -E "/BE-${2}\.[a-zA-Z0-9]{8}" 1> /dev/null 2> /dev/null
734    then
735      # delete only when it is an empty directory
736      if [ $( find ${MOUNTPOINT} | head | wc -l | bc ) -eq 1 ]
737      then
738        rm -r ${MOUNTPOINT}
739      fi
740    fi
741    ;;
742
743  (*) # -----------------------------------------------------------------------
744    __usage
745    ;;
746
747esac
Note: See TracBrowser for help on using the repository browser.