#!/bin/sh -e

# Copyright (c) 2012 Slawomir Wojciech Wojtczak (vermaden). All rights reserved.
# Copyright (c) 2012 Bryan Drewery (bdrewery). All rights reserved.
# Copyright (c) 2012 Mike Clarke (rawthey). All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that following conditions are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS 'AS IS' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

unset LC_ALL
unset LANG
PATH=${PATH}:/bin:/usr/bin:/sbin:/usr/sbin

if [ $( uname -r | cut -d '.' -f1 ) -lt 8 ]
then
  echo "ERROR: beadm works on FreeBSD 8.0 or later"
  exit 1
fi

__usage() {
  local NAME=${0##*/}
  echo "usage:"
  echo "  ${NAME} activate beName"
  echo "  ${NAME} create [-e nonActiveBe] beName"
  echo "  ${NAME} create [-e beName@snapshot] beName"
  echo "  ${NAME} create beName@snapshot"
  echo "  ${NAME} destroy [-F] beName"
  echo "  ${NAME} destroy [-F] beName@snapshot"
  echo "  ${NAME} list"
  echo "  ${NAME} mount"
  echo "  ${NAME} mount beName [mountpoint]"
  echo "  ${NAME} umount [-f] beName"
  echo "  ${NAME} unmount [-f] beName"
  echo "  ${NAME} rename origBeName newBeName"
  exit 1
}

# check if boot environment exists
__be_exist() { # 1=DATASET
  if ! zfs list -H -o name ${1} 1> /dev/null 2> /dev/null
  then
    echo "ERROR: Boot environment '${1##*/}' does not exist"
    exit 1
  fi
}

# check if argument is a snapshot
__be_snapshot() { # 1=DATASET/SNAPSHOT
  echo "${1}" | grep -q "@" 2> /dev/null
}

# check if boot environment is mounted
__be_mounted() { # 1=BE
  mount 2> /dev/null | grep -q -E "^${1} " 2> /dev/null
}

# check if boot environment is a clone
__be_clone() { # 1=DATASET
  if zfs list ${1} 1> /dev/null 2> /dev/null
  then
    local ORIGIN="$( zfs list -H -o origin ${1} )"
    if [ "${ORIGIN}" = "-" ]
    then
      # boot environment is not a clone
      return 1
    else
      # boot environment is a clone
      return 0
    fi
  else
    # boot environment does not exist
    return 2
  fi
}

# create new boot environment
__be_new() { # 1=SOURCE 2=TARGET
  local SOURCE=$( echo ${1} | cut -d '@' -f 1 )
  if __be_snapshot ${1}
  then
    # create boot environment from snapshot
    local SNAPSHOT=$( echo ${1} | cut -d '@' -f 2 )
    zfs list -r -H -t filesystem -o name ${SOURCE} \
      | while read FS
        do
          if ! zfs list -H -o name ${FS}@${SNAPSHOT} 1> /dev/null 2> /dev/null
          then
            echo "ERROR: Child snapshot '${FS}@${SNAPSHOT}' does not exist"
            exit 1
          fi
        done
  else
    # create boot environment from other boot environment
    if zfs list -H -o name ${1}@${2##*/} 1> /dev/null 2> /dev/null
    then
      echo "ERROR: Snapshot '${1}@${2##*/}' already exists"
      exit 1
    fi
    # snapshot format
    FMT=$( date "+%Y-%m-%d-%H:%M:%S" )
    if ! zfs snapshot -r ${1}@${FMT} 1> /dev/null 2> /dev/null
    then
      echo "ERROR: Cannot create snapshot '${1}@${FMT}'"
      exit 1
    fi
  fi
  # clone properties of source boot environment
  zfs list -H -o name -r ${SOURCE} \
    | while read FS
      do
        local OPTS=""
        while read NAME PROPERTY VALUE
        do
          local OPTS="-o ${PROPERTY}=${VALUE} ${OPTS}"
        done << EOF
$( zfs get -o name,property,value -s local,received -H all ${FS} | awk '!/[\t ]canmount[\t ]/' )
EOF
        DATASET=$( echo ${FS} | awk '{print $1}' | sed -E s/"^${POOL}\/ROOT\/${SOURCE##*/}"/"${POOL}\/ROOT\/${2##*/}"/g )
        if [ "${OPTS}" = "-o = " ]
        then
          local OPTS=""
        fi
        if __be_snapshot ${1}
        then
          zfs clone -o canmount=off ${OPTS} ${FS}@${1##*@} ${DATASET}
        else
          zfs clone -o canmount=off ${OPTS} ${FS}@${FMT} ${DATASET}
        fi
      done
}

ROOTFS=$( mount | awk '/ \/ / {print $1}' )

if echo ${ROOTFS} | grep -q -m 1 -E "^/dev/"
then
  echo "ERROR: This system does not boot from ZFS pool"
  exit 1
fi

POOL=$( echo ${ROOTFS} | awk -F '/' '{print $1}' )

if ! zfs list ${POOL}/ROOT 1> /dev/null 2> /dev/null
then
  echo "ERROR: This system is not configured for boot environments"
  exit 1
fi

BOOTFS=$( zpool list -H -o bootfs ${POOL} )

if [ -z "${BOOTFS}" -o "${BOOTFS}" = "-" ]
then
 echo "ERROR: ZFS boot pool '${POOL}' has unset 'bootfs' property"
 exit 1
fi

case ${1} in

  (list) # --------------------------------------------------------------------
    if [ ${#} -ne 1 -a "${2}" != "-a" ]
    then
      __usage
    fi
    if [ "${2}" = "-a" ]
    then
      ZFS_LIST=$( zfs list -o name,mountpoint,used,creation -H -t all -r ${POOL}/ROOT | sed 1d )
    else
      ZFS_LIST=$( zfs list -o name,mountpoint,used,creation -s creation -H -d 1 -r ${POOL}/ROOT | sed 1d )
    fi
    WIDTH_CREATION=$( echo "${ZFS_LIST}" | awk '{print $5}' | wc -L )
    WIDTH_NAME=$( echo "${ZFS_LIST}" | awk '{print $1}' | wc -L )
    ZFS_MOUNT_LIST=$( zfs mount | grep "^${POOL}/ROOT/" )
    if [ "${2}" = "-a" ]
    then
      WIDTH_MOUNT=$( echo "${ZFS_MOUNT_LIST}" | awk '{print $2}' | wc -L )
    else
      BENAMES=$( echo "${ZFS_LIST}" | awk '{print $1}' | xargs basename | tr '\n' '|' | sed 's/.$//' )
      WIDTH_MOUNT=$( echo "${ZFS_MOUNT_LIST}" | grep -E "(${BENAMES}) " | awk '{print $2}' | wc -L )
      WIDTH_NAME=$(( ${WIDTH_NAME} - ${#POOL} - 6 ))
      if [ ${WIDTH_MOUNT} -lt 10 ]
      then
        WIDTH_MOUNT=10
      fi
    fi
    # get list of USEDBYDATASET and USED properties
    USED_ALL=$( zfs list -H -t all -o name,usedbydataset,used -r sys/ROOT \
                  | sed 1d \
                  | sed '/0$/d' \
                  | awk '{ gsub("-"," 0 0 ",$2);                 gsub("-"," 0 0 ",$3);
                           gsub("K"," 1 ",$2);                   gsub("K"," 1 ",$3);
                           gsub("M"," 1024 ",$2);                gsub("M"," 1024 ",$3);
                           gsub("G"," 1048576 ",$2);             gsub("G"," 1048576 ",$3);
                           gsub("T"," 1073741824 ",$2);          gsub("T"," 1073741824 ",$3);
                           gsub("P"," 1099511627776 ",$2);       gsub("P"," 1099511627776 ",$3);
                           gsub("E"," 1125899906842624 ",$2);    gsub("E"," 1125899906842624 ",$3);
                           gsub("Z"," 1152921504606846976 ",$2); gsub("Z"," 1152921504606846976 ",$3);
                           print $0;
                         }' )
    # get the list of names and origins for all boot environments
    SNAPSHOT_ALL=$( zfs list -H -t all -o name,origin -d 1 ${POOL}/ROOT )
    if [ "${2}" = "-a" ]
    then
      printf "%-${WIDTH_NAME}s   %-6s %-${WIDTH_MOUNT}s %6s %s\n" \
        BE/Dataset/Snapshot Active Mountpoint Space Created
    else
      printf "%-${WIDTH_NAME}s %-6s %-${WIDTH_MOUNT}s %6s %s\n" \
        BE Active Mountpoint Space Created
    fi
    echo "${ZFS_LIST}" \
      | while read NAME MOUNTPOINT USED a b d HM Y
        do
          TOTAL=0
          DATASET=${NAME}
          NAME=${NAME##*/}
          ACTIVE=''
          if [ "${POOL}/ROOT/${NAME}" = "${ROOTFS}" ]
          then
            ACTIVE="${ACTIVE}N"
            fi
          if [ "${POOL}/ROOT/${NAME}" = "${BOOTFS}" ]
          then
            ACTIVE="${ACTIVE}R"
          fi
          if [ -z "${ACTIVE}" ]
          then
            ACTIVE="-"
          fi
          if [ "${2}" = "-a" ]
          then
            MOUNT=$( echo "${ZFS_MOUNT_LIST}" | grep -m 1 "^${DATASET}" | awk '{print $2}' )
          else
            MOUNT=$( echo "${ZFS_MOUNT_LIST}" | grep -m 1 "^${POOL}/ROOT/${NAME}" | awk '{print $2}' )
          fi
          if [ -z "${MOUNT}" ]
          then
            MOUNT="-"
          fi
          # get the name of origin snapshot for boot environment
          SNAPSHOT=$( echo "${SNAPSHOT_ALL}" | awk "/^${POOL}\/ROOT\/${NAME}\t/" | awk -F '@' '{print $2}' )
          if [ "${2}" = "-a" ]
          then
            # use the USED field from ZFS LIST
            TOTAL=${USED}
          else
            # calculate space total usage for boot environment
            TOTAL=$( echo "${USED_ALL}" \
                      | awk -v name="^${POOL}\/ROOT\/${NAME}" -v snapshot="@${SNAPSHOT}$" \
                        'BEGIN {total = 0}
                          ($1 ~ name)     {total += $2 * $3}
                          ($1 ~ snapshot) {total += $4 * $5}
                          END {
                               if (total <= 1024)                  {                                      unit = "K"; }
                          else if (total <= 1048576)               { total = total / 1024;                unit = "M"; }
                          else if (total <= 1073741824)            { total = total / 1048576;             unit = "G"; }
                          else if (total <= 1099511627776)         { total = total / 1073741824;          unit = "T"; }
                          else if (total <= 1125899906842624)      { total = total / 1099511627776;       unit = "P"; }
                          else if (total <= 1152921504606846976)   { total = total / 1125899906842624;    unit = "E"; }
                                                              else { total = total / 1152921504606846976; unit = "Z"; }
                          printf ("%.1f%s",total,unit);
                          }' )
          fi
          if [ "${2}" = "-a" ]
          then
            if echo "${DATASET}" | grep -v "@" | grep -q "${POOL}/ROOT/${NAME}" 2> /dev/null
            then
              echo ${NAME}
            fi
            printf "  %-${WIDTH_NAME}s %-6s %-${WIDTH_MOUNT}s %6s " ${DATASET} ${ACTIVE} ${MOUNT} ${TOTAL}
            date -j -f "%a %b %d %H:%M %Y" "${a} ${b} ${d} ${HM} ${y}" +"%Y-%m-%d %H:%M"
          else
            printf "%-${WIDTH_NAME}s %-6s %-${WIDTH_MOUNT}s %6s " ${NAME} ${ACTIVE} ${MOUNT} ${TOTAL}
            date -j -f "%a %b %d %H:%M %Y" "${a} ${b} ${d} ${HM} ${y}" +"%Y-%m-%d %H:%M"
          fi
        done
    ;;

  (create) # ------------------------------------------------------------------
    case ${#} in
      (4)
        if ! [ ${2} = "-e" ]
        then
          __usage
        fi
        # check if argument for -e option is full path dataset
        # argument for -e option must be 'beName' or 'beName@snapshot'
        if echo ${3} | grep -q "/" 2> /dev/null
        then
          __usage
        fi
        __be_exist ${POOL}/ROOT/${3}
        if zfs list -H -o name ${POOL}/ROOT/${4} 1> /dev/null 2> /dev/null
        then
          echo "ERROR: Boot environment '${4}' already exists"
          exit 1
        fi
        __be_new ${POOL}/ROOT/${3} ${POOL}/ROOT/${4}
        ;;
      (2)
        if __be_snapshot ${2}
        then
          if ! zfs snapshot -r ${POOL}/ROOT/${2} 1> /dev/null 2> /dev/null
          then
            echo "ERROR: Cannot create '${2}' recursive snapshot"
            exit 1
          fi
        else
          __be_new ${ROOTFS} ${POOL}/ROOT/${2}
        fi
        ;;
      (*)
        __usage
        ;;
    esac
    echo "Created successfully"
    ;;

  (activate) # ----------------------------------------------------------------
    if [ ${#} -ne 2 ]
    then
      __usage
    fi
    __be_exist ${POOL}/ROOT/${2}
    if [ "${BOOTFS}" = "${POOL}/ROOT/${2}" ]
    then
      echo "Already activated"
      exit 0
    else
      if __be_mounted ${POOL}/ROOT/${2}
      then
        MNT=$( mount | grep -E "^${POOL}/ROOT/${2} " | awk '{print $3}' )
        if [ "${MNT}" != "/" ]
        then
          # boot environment is not current root and its mounted
          echo "ERROR: Boot environment '${2}' is mounted at '${MNT}'"
          echo "ERROR: Cannot activate manually mounted boot environment"
          exit 1
        fi
      fi
      # do not change root (/) mounted boot environment mountpoint
      if [ "${ROOTFS}" != "${POOL}/ROOT/${2}" ]
      then
        TMPMNT=$( mktemp -d /tmp/tmp.XXXXXX )
        if ! mkdir -p ${TMPMNT} 2> /dev/null
        then
          echo "ERROR: Cannot create '${TMPMNT}' directory"
          exit 1
        fi
        MOUNT=0
        while read FS MNT TYPE OPTS DUMP FSCK;
        do
          if [ "${FS}" = "${POOL}/ROOT/${2}" ]
          then
            MOUNT=${MNT}
            break
          fi
        done << EOF
$( mount -p )
EOF
        if [ ${MOUNT} -eq 0 ]
        then
          zfs set canmount=noauto ${POOL}/ROOT/${2}
          zfs set mountpoint=${TMPMNT} ${POOL}/ROOT/${2}
          zfs mount ${POOL}/ROOT/${2}
        else
          TMPMNT=${MOUNT}
        fi
        cp /boot/zfs/zpool.cache ${TMPMNT}/boot/zfs/zpool.cache
        LOADER_CONFIGS=${TMPMNT}/boot/loader.conf
        if [ -f ${TMPMNT}/boot/loader.conf.local ]
        then
          LOADER_CONFIGS="${LOADER_CONFIGS} ${TMPMNT}/boot/loader.conf.local"
        fi
        sed -i '' -E s/"^vfs.root.mountfrom=.*$"/"vfs.root.mountfrom=\"zfs:${POOL}\/ROOT\/${2##*/}\""/g ${LOADER_CONFIGS}
        if [ ${MOUNT} -eq 0 ]
        then
          zfs umount ${POOL}/ROOT/${2}
          zfs set mountpoint=legacy ${POOL}/ROOT/${2}
        fi
      fi
      if ! zpool set bootfs=${POOL}/ROOT/${2} ${POOL} 1> /dev/null 2> /dev/null
      then
        echo "ERROR: Failed to activate '${2}' boot environment"
        exit 1
      fi
    fi
    # disable automatic mount on all inactive boot environments
    zfs list -H -o name -r ${POOL}/ROOT \
      | grep -v "${POOL}/ROOT/${2}" \
      | while read I
        do
          zfs set canmount=noauto ${I}
        done
    # enable automatic mount for active boot environment and promote it
    zfs list -H -o name,origin -t filesystem -r ${POOL}/ROOT/${2} \
      | while read I ORIGIN
        do
          zfs set canmount=on ${I}
          if [ "${ORIGIN}" != "-" ]
          then
            zfs promote ${I}
          fi
        done
    echo "Activated successfully"
    ;;

  (destroy) # -----------------------------------------------------------------
    if [ "${2}" != "-F" ]
    then
      DESTROY=${2}
    else
      DESTROY=${3}
    fi
    __be_exist ${POOL}/ROOT/${DESTROY}
    case ${#} in
      (2)
        echo "Are you sure you want to destroy '${2}'?"
        echo -n "This action cannot be undone (y/[n]): "
        read CHOICE
        ;;
      (3)
        if [ "${2}" != "-F" ]
        then
          __usage
        fi
        CHOICE=Y
        ;;
      (*)
        __usage
        ;;
    esac
    if [ "${BOOTFS}" = "${POOL}/ROOT/${DESTROY}" ]
    then
      echo "ERROR: Cannot destroy active boot environment"
      exit 1
    fi
    case ${CHOICE} in
      (Y|y|[Yy][Ee][Ss])
        # destroy snapshot or boot environment
        if __be_snapshot ${POOL}/ROOT/${DESTROY}
        then
          # destroy desired snapshot
          if ! zfs destroy -r ${POOL}/ROOT/${DESTROY} 1> /dev/null 2> /dev/null
          then
            echo "ERROR: Snapshot '${2}' is origin for other boot environment"
            exit 1
          fi
        else
          if __be_clone ${POOL}/ROOT/${DESTROY}
          then
            # promote clones dependent on snapshots used by destroyed boot environment
            zfs list -H -t all -o name,origin \
              | while read NAME ORIGIN
                do
                  if echo "${ORIGIN}" | grep -q -E "${POOL}/ROOT/${DESTROY}(/.*@|@)" 2> /dev/null
                  then
                    zfs promote ${NAME}
                  fi
                done
            # get origins used by destroyed boot environment
            ORIGIN_SNAPSHOTS=$( zfs list -H -t all -o origin -r ${POOL}/ROOT/${DESTROY} | grep -v '^-$' | awk -F "@" '{print $2}' | sort -u )
          fi
          # check if boot environment was created from existing snapshot
          ORIGIN=$( zfs list -H -o origin ${POOL}/ROOT/${DESTROY} )
          CREATION=$( zfs list -H -o creation ${POOL}/ROOT/${DESTROY} )
          CREATION=$( date -j -f "%a %b %d %H:%M %Y" "${CREATION}" +"%Y-%m-%d-%H:%M" )
          SNAPSHOT_NAME=$( echo "${ORIGIN}" | cut -d '@' -f 2 | sed -E 's/:[0-9]{2}$//g' )
          if [ "${2}" = "-F" ]
          then
            CHOICE=1
          elif [ "${SNAPSHOT_NAME}" != "${CREATION}" ]
          then
            ORIGIN=$( basename ${ORIGIN} )
            echo "Boot environment '${DESTROY}' was created from existing snapshot"
            echo -n "Destroy '${ORIGIN}' snapshot? (y/[n]): "
            read CHOICE
            case ${CHOICE} in
              (Y|y|[Yy][Ee][Ss])
                CHOICE=1
                ;;
              (*)
                CHOICE=0
                echo "Origin snapshot '${ORIGIN}' will be preserved"
                ;;
            esac
          else
            CHOICE=1
          fi
          # destroy boot environment
          zfs destroy -r ${POOL}/ROOT/${DESTROY}
          # check if boot environment is a clone
          if __be_clone ${POOL}/ROOT/${DESTROY}
          then
            # promote datasets dependent on origins used by destroyed boot environment
            ALL_ORIGINS=$( zfs list -H -t all -o name,origin )
            echo "${ORIGIN_SNAPSHOTS}" \
              | while read S
                do
                  echo "${ALL_ORIGINS}" \
                    | grep "${S}" \
                    | awk '{print $1}' \
                    | while read I
                      do
                        zfs promote ${I}
                      done
                done
          fi
          # destroy origins used by destroyed boot environment
          SNAPSHOTS=$( zfs list -H -t snapshot -o name )
          echo "${ORIGIN_SNAPSHOTS}" \
            | while read S
              do
                echo "${SNAPSHOTS}" \
                  | grep "@${S}$" \
                  | while read I
                    do
                      if [ ${CHOICE} -eq 1 ]
                      then
                        zfs destroy ${I}
                      fi
                    done
              done
        fi
        echo "Destroyed successfully"
        ;;
      (*)
        echo "Boot environment '${DESTROY}' has not been destroyed"
        ;;
    esac
    ;;

  (rename) # ------------------------------------------------------------------
    if [ ${#} -ne 3 ]
    then
      __usage
    fi
    __be_exist ${POOL}/ROOT/${2}
    if [ "${BOOTFS}" = "${POOL}/ROOT/${2}" ]
    then
      echo "ERROR: Renaming active boot environment is not supported"
      exit 1
    fi
    if zfs list -H -o name ${POOL}/ROOT/${3} 2> /dev/null
    then
      echo "ERROR: Boot environment '${3}' already exists"
      exit 1
    fi
    zfs rename ${POOL}/ROOT/${2} ${POOL}/ROOT/${3}
    echo "Renamed successfully"
    ;;

  (mount) # -------------------------------------------------------------------
    if [ ${#} -eq 1 ]
    then
      zfs list -H -o name -d 1 -r ${POOL}/ROOT \
        | grep "${POOL}/ROOT/" \
        | while read NAME
          do
            NAME=${NAME##*/}
            if mount | grep -q -E "^${POOL}/ROOT/${NAME}" 2> /dev/null
            then
              echo ${NAME}
              mount \
                | grep -E "^${POOL}/ROOT/${NAME}" \
                | awk '{print $1 " " $3}' \
                | column -t \
                | awk '{print "  " $0}'
              echo
            fi
          done
      exit 0
    elif [ ${#} -eq 2 ]
    then
      TARGET=$( mktemp -d /tmp/tmp.XXXXXX )
    elif [ ${#} -eq 3 ]
    then
      TARGET=${3}
    else
      __usage
    fi
    __be_exist "${POOL}/ROOT/${2}"
    if __be_mounted "${POOL}/ROOT/${2}"
    then
      MNT=$( mount | grep -E "^${POOL}/ROOT/${2} " | awk '{print $3}' )
      echo "Boot environment '${2}' is already mounted at '${MNT}'"
      exit 1
    fi
    if ! mkdir -p ${TARGET} 2> /dev/null
    then
      echo "ERROR: Cannot create '${TARGET}' mountpoint"
      exit 1
    fi
    if ! mount -t zfs ${POOL}/ROOT/${2} ${TARGET}
    then
      echo "ERROR: Cannot mount '${2}' at '${TARGET}' mountpoint"
      exit 1
    fi
    PREFIX=$( echo ${POOL}/ROOT/${2}/ | sed 's/\//\\\//g' )
    zfs list -H -o name,mountpoint -r ${POOL}/ROOT/${2} \
      | grep -v "legacy$" \
      | sort -n \
      | grep -E "^${POOL}/ROOT/${2}/" \
      | while read FS MOUNTPOINT
        do
          if [ "{FS}" != "${POOL}/ROOT/${2}" ]
          then
            INHERIT=$( zfs get -H -o source mountpoint ${FS} )
            if [ "${INHERIT}" = "local" ]
            then
              if [ "${MOUNTPOINT}" = "legacy" ]
              then
                continue
              else
                MOUNTPOINT="/$( echo "${FS}" | sed s/"${PREFIX}"//g )"
              fi
            fi
          fi
          if ! mkdir -p ${TARGET}${MOUNTPOINT} 1> /dev/null 2> /dev/null
          then
            echo "ERROR: Cannot create '${TARGET}${MOUNTPOINT}' mountpoint"
            exit 1
          fi
          if ! mount -t zfs ${FS} ${TARGET}${MOUNTPOINT} 1> /dev/null 2> /dev/null
          then
            echo "ERROR: Cannot mount '${FS}' at '${TARGET}${MOUNTPOINT}' mountpoint"
            exit 1
          fi
        done
    echo "Mounted successfully on '${TARGET}'"
    ;;

  (umount|unmount) # ----------------------------------------------------------
    if [ ${#} -eq 2 ]
    then
      # we need this empty section for argument checking
      :
    elif [ ${#} -eq 3 -a "${2}" = "-f" ]
    then
      OPTS="-f"
      shift
    else
      __usage
    fi
    __be_exist "${POOL}/ROOT/${2}"
    if ! __be_mounted "${POOL}/ROOT/${2}"
    then
      echo "Boot environment '${2}' is not mounted"
      exit 1
    fi
    mount \
      | grep "^${POOL}/ROOT/${2}" \
      | awk '{print $1}' \
      | sort -n -r \
      | while read FS
        do
          if ! umount ${OPTS} ${FS} 1> /dev/null 2> /dev/null
          then
            echo "ERROR: Cannot umount '${FS}' dataset"
            exit 1
          fi
        done
    echo "Unmounted successfully"
    ;;

  (*) # -----------------------------------------------------------------------
    __usage
    ;;

esac
