#!/bin/sh -e

# Copyright 2012 Slawomir Wojciech Wojtczak (vermaden). All rights reserved.
# Copyright 2012 Bryan Drewery (bdrewery). 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} subcommand cmd_options"
  echo
  echo "  subcommands:"
  echo
  echo "  ${NAME} activate beName"
  echo "  ${NAME} create [-e nonActiveBe | -e beName@snapshot] beName"
  echo "  ${NAME} create beName@snapshot"
  echo "  ${NAME} destroy [-F] beName | beName@snapshot"
  echo "  ${NAME} list"
  echo "  ${NAME} mount"
  echo "  ${NAME} mount beName [mountpoint]"
  echo "  ${NAME} umount | unmount [-f] beName"
  echo "  ${NAME} rename origBeName newBeName"
  exit 1
}

# check if BE 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 "@"
}

# create new BE
__be_new() { # 1=SOURCE 2=TARGET
  local SOURCE=$( echo ${1} | cut -d '@' -f 1 )
  if __be_snapshot ${1}
  then
    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 exists"
            exit 1
          fi
        done
  else
    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
### if ! zfs snapshot -r ${1}@${2##*/} 1> /dev/null 2> /dev/null        # old #
    FMT=$( date "+%Y-%m-%d-%H:%M:%S" )                                  # NEW #
    if ! zfs snapshot -r ${1}@${FMT} 1> /dev/null 2> /dev/null          # NEW #
    then
##### echo "ERROR: Cannot create snapshot '${1}@${2##*/}'"              # old #
      echo "ERROR: Cannot create snapshot '${1}@${FMT}'"                # NEW #
      exit 1
    fi
  fi
  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} | grep -v -E "(canmount)" )
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}@${2##*/} ${DATASET}   # old #
          zfs clone -o canmount=off ${OPTS} ${FS}@${FMT} ${DATASET}     # NEW #
        fi
      done
  echo "Created successfully"
}

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

if echo ${ROOTFS} | grep -q -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} )

case ${1} in

  (list) # --------------------------------------------------------------------
    if [ ${#} -ne 1 ]
    then
      __usage
    fi
    BENAME_STARTS_WITH="${POOL}/ROOT"
    LIST=$( zfs list -o name,mountpoint,creation -s creation -H -d 1 -r ${POOL}/ROOT | grep -E "^${POOL}/ROOT/" )
    WIDTH_CREATION=$( echo "${LIST}" | awk '{print $5}' | wc -L )
    WIDTH_NAME=$( echo "${LIST}" | awk '{print $1}' | wc -L )
    WIDTH_NAME=$(( ${WIDTH_NAME} - ${#BENAME_STARTS_WITH} - 1 ))
    printf "%-${WIDTH_NAME}s %-6s %-10s %6s %6s %s\n" \
      BE Active Mountpoint Space Policy Created
    echo "${LIST}" \
      | while read NAME MOUNTPOINT Y m d H M
        do
          TOTAL=0
          NAME=${NAME##*/}
          unset ACTIVE
          if [ "${BENAME_STARTS_WITH}/${NAME}" = "${ROOTFS}" ]
          then
            ACTIVE="${ACTIVE}N"
            fi
          if [ "${BENAME_STARTS_WITH}/${NAME}" = "${BOOTFS}" ]
          then
            ACTIVE="${ACTIVE}R"
          fi
          if [ -z "${ACTIVE}" ]
          then
            ACTIVE="-"
          fi
          printf "%-${WIDTH_NAME}s %-6s " ${NAME} ${ACTIVE}
          case ${ACTIVE} in
            (N|NR) MOUNT="/" ;;
            (*)    MOUNT="-" ;;
          esac
          while read I
          do
            USED=$( zfs list -H -o used ${I} )
            if [ ${USED} = "0" ]
            then
              continue
            fi
            case "${USED}" in
              (*K) SIZE=$( echo "${USED} * 1000                  " | tr -c -d '\[0-9]* .\n' | bc -l ) ;;
              (*M) SIZE=$( echo "${USED} * 1000000               " | tr -c -d '\[0-9]* .\n' | bc -l ) ;;
              (*G) SIZE=$( echo "${USED} * 1000000000            " | tr -c -d '\[0-9]* .\n' | bc -l ) ;;
              (*T) SIZE=$( echo "${USED} * 1000000000000         " | tr -c -d '\[0-9]* .\n' | bc -l ) ;;
              (*P) SIZE=$( echo "${USED} * 1000000000000000      " | tr -c -d '\[0-9]* .\n' | bc -l ) ;;
              (*E) SIZE=$( echo "${USED} * 1000000000000000000   " | tr -c -d '\[0-9]* .\n' | bc -l ) ;;
              (*Z) SIZE=$( echo "${USED} * 1000000000000000000000" | tr -c -d '\[0-9]* .\n' | bc -l ) ;;
              (*)  SIZE="${USED}" ;;
            esac
            TOTAL=$( echo "${SIZE} + ${TOTAL}" | bc -l )
          done << EOF
$( zfs list -H -t all -o name,origin -r "${BENAME_STARTS_WITH}/${NAME}" | tr '\t' '\n' | grep -v -E "^-$" )
EOF
          RANGE=$( echo ${TOTAL} | cut -d . -f 1 )
          case $( echo "${RANGE}" | wc -c | tr -c -d '[0-9]\n' ) in
            (5|6|7)       TOTAL="$( echo ${TOTAL} / 1000                   | bc -l | grep -o -E "[0-9]*\.[0-9]{1}" )K" ;;
            (8|9|10)      TOTAL="$( echo ${TOTAL} / 1000000                | bc -l | grep -o -E "[0-9]*\.[0-9]{1}" )M" ;;
            (11|12|13)    TOTAL="$( echo ${TOTAL} / 1000000000             | bc -l | grep -o -E "[0-9]*\.[0-9]{1}" )G" ;;
            (14|15|16)    TOTAL="$( echo ${TOTAL} / 1000000000000          | bc -l | grep -o -E "[0-9]*\.[0-9]{1}" )T" ;;
            (17|18|19)    TOTAL="$( echo ${TOTAL} / 1000000000000000       | bc -l | grep -o -E "[0-9]*\.[0-9]{1}" )P" ;;
            (20|21|22)    TOTAL="$( echo ${TOTAL} / 1000000000000000000    | bc -l | grep -o -E "[0-9]*\.[0-9]{1}" )E" ;;
            (23|24|25)    TOTAL="$( echo ${TOTAL} / 1000000000000000000000 | bc -l | grep -o -E "[0-9]*\.[0-9]{1}" )Z" ;;
          esac
          printf "%-10s %6s %-6s " ${MOUNT} ${TOTAL} "static"
          date -j -f "%a %b %d %H:%M %Y" "${Y} ${m} ${d} ${H} ${M}" +"%Y-%m-%d %H:%M"
        done
####### LIST=$( zfs list -o name,used,mountpoint,creation -s creation -H -d 1 -r ${POOL}/ROOT | grep -E "^${POOL}/ROOT/" )
####### WIDTH_CREATION=$( echo "${LIST}" | awk '{print $5}' | wc -L )
####### WIDTH_NAME=$( echo "${LIST}" | awk '{print $1}' | wc -L )
####### WIDTH_NAME=$(( ${WIDTH_NAME} - ${#BENAME_STARTS_WITH} - 1 ))
####### printf "%-${WIDTH_NAME}s %-6s %-10s %5s %6s %s\n" \
#######   BE Active Mountpoint Space Policy Created
####### echo "${LIST}" \
#######   | while read NAME USED MOUNTPOINT Y m d H M
#######     do
#######       NAME=${NAME##*/}
#######       unset ACTIVE
#######       if [ "${BENAME_STARTS_WITH}/${NAME}" = "${ROOTFS}" ]
#######       then
#######         ACTIVE="${ACTIVE}N"
#######         fi
#######       if [ "${BENAME_STARTS_WITH}/${NAME}" = "${BOOTFS}" ]
#######       then
#######         ACTIVE="${ACTIVE}R"
#######       fi
#######       if [ -z "${ACTIVE}" ]
#######       then
#######         ACTIVE="-"
#######       fi
#######       printf "%-${WIDTH_NAME}s %-6s " ${NAME} ${ACTIVE}
#######       case ${ACTIVE} in
#######         (N|NR) MOUNT="/" ;;
#######         (*)    MOUNT="-" ;;
#######       esac
#######       printf "%-10s %5s %-6s " ${MOUNT} ${USED} "static"
#######       date -j -f "%a %b %d %H:%M %Y" "${Y} ${m} ${d} ${H} ${M}" +"%Y-%m-%d %H:%M"
#######     done
    ;;

  (create) # ------------------------------------------------------------------
    case ${#} in
      (4)
        if ! [ ${2} = "-e" ]
        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
          echo "Created successfully"
        else
          __be_new ${ROOTFS} ${POOL}/ROOT/${2}
        fi
        ;;
      (*)
        __usage
        ;;
    esac
    ;;

  (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 mount | grep -E "^${POOL}/ROOT/${2} " 1> /dev/null 2> /dev/null
      then
        MNT=$( mount | grep -E "^${POOL}/ROOT/${2} " | awk '{print $3}' )
        if [ "${MNT}" != "/" ]
        then
          echo "ERROR: The '${2}' is mounted at '${MNT}'"
          echo "ERROR: Cannot activate mounted boot environment"
          exit 1
        fi
      fi
      if [ "${ROOTFS}" != "${POOL}/ROOT/${2}" ]
      then
        TMPMNT="/tmp/BE"
        if ! mkdir -p ${TMPMNT}
        then
          echo "ERROR: Cannot create '${TMPMNT}' directory"
          exit 1
        fi
        MOUNT=0
        while read FS MNT
        do
          if [ "${FS}" = "${POOL}/ROOT/${2}" ]
          then
            MOUNT=${MNT}
          fi
        done << EOF
$( mount -p | awk '{print $1 " " $2}' )
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} 1> /dev/null 2> /dev/null
        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} 2> /dev/null
        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} 2> /dev/null
      then
        echo "ERROR: Failed to activate '${POOL}/ROOT/${2}'"
        exit 1
      fi
    fi
    # disable automatic mount on all inactive datasets
    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 BE 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) # -----------------------------------------------------------------
    case ${#} in
      (2)
        echo "Are you sure you want to destroy '${2}'?"
        echo -n "This action cannot be undone (y/[n]): "
        read CHOICE
        DESTROY=${2}
        ;;
      (3)
        if [ "${2}" != "-F" ]
        then
          __usage
        fi
        CHOICE=Y
        DESTROY=${3}
        ;;
      (*)
        __usage
        ;;
    esac
    __be_exist ${POOL}/ROOT/${DESTROY}
    if [ "${BOOTFS}" = "${POOL}/ROOT/${DESTROY}" ]
    then
      echo "ERROR: '${POOL}/ROOT/${2}' is current active boot environment"
      exit 1
    fi
    case ${CHOICE} in
      (Y|y|[Yy][Ee][Ss])
        # delete snapshot or delete 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(s)"
            exit 1
          fi
        else
          # 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
          ORIGINS=$( zfs list -H -t all -o origin -r ${POOL}/ROOT/${DESTROY} )
          # destroy boot environment
          zfs destroy -r ${POOL}/ROOT/${DESTROY}
          # destroy origins used by destroyed boot environment
          echo "${ORIGINS}" \
            | while read I
              do
                if [ "${I}" != "-" ]
                then
                  zfs destroy ${I}
                fi
              done
############## # destroy desired boot environment
############## zfs list -r -H -o name ${POOL}/ROOT/${DESTROY} \
##############   | sort -n -r \
##############   | while read DATASET
##############     do
##############       zfs umount ${DATASET} 1> /dev/null 2> /dev/null || true
##############     done
############## # get origins that needs to be deleted
############## ORIGINS=$( zfs list -r -H -o origin ${POOL}/ROOT/${DESTROY} )
############## # promote dependent clones
############## zfs list -H -o name,origin \
##############   | awk -v destroy=${POOL}/ROOT/${DESTROY} '$2 ~ destroy {print $1}' \
##############   | sort -r \
##############   | while read I
##############     do
##############       echo PROMOTE 1: $I
##############       zfs promote ${I} 2> /dev/null
##############     done
############## # destroy desired boot environment
############## if ! zfs destroy ${POOL}/ROOT/${DESTROY} 1> /dev/null 2> /dev/null
############## then
##############   # promote dependent clones when needed
##############   zfs destroy -r ${POOL}/ROOT/${DESTROY} 2>&1 \
##############     | grep "${POOL}/ROOT/" \
##############     | grep -v "@" \
##############     | while read I
##############       do
##############         echo PROMOTE 2: $I
##############         zfs promote ${I} 2> /dev/null
##############       done
############## fi
############## # destroy origins that needs to be deleted
############## if [ "${ORIGINS}" != "-" ]
############## then
##############   echo "${ORIGINS}" \
##############     | while read I
##############       do
##############         zfs destroy -r ${I} 2> /dev/null || true
##############       done
############## fi
        fi
        echo "Destroyed successfully"
        ;;
      (*)
        echo "'${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 the active BE 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) # -------------------------------------------------------------------
    COMPLETE=1
    if [ ${#} -eq 1 -o ${#} -eq 2 ]
    then
      if [ ${2} ]
      then
        BE=${2}
      else
        zfs list -H -o name -d 1 -r ${POOL}/ROOT \
          | grep "${POOL}/ROOT/" \
          | while read NAME
            do
              NAME=${NAME##*/}
              if mount | grep -E "^${POOL}/ROOT/${NAME}" 1> /dev/null 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
      fi
    elif [ ${#} -eq 3 ]
    then
      BE=${2}
      TARGET=${3}
    else
      __usage
    fi
    __be_exist "${POOL}/ROOT/${BE}"
    if mount | grep -E "^${POOL}/ROOT/${BE} " 1> /dev/null 2> /dev/null
    then
      MNT=$( mount | grep -E "^${POOL}/ROOT/${BE} " | awk '{print $3}' )
      echo "The '${BE}' is already mounted at '${MNT}'"
      exit 1
    fi
    if ! [ ${3} ]
    then
      TARGET=$( mktemp -d /tmp/tmp.XXXXXX )
      mkdir -p ${TARGET}
    fi
    if ! mount -t zfs ${POOL}/ROOT/${BE} ${TARGET}
    then
      echo "ERROR: Cannot mount '${POOL}/ROOT/${BE}' at '${TARGET}' mountpoint"
      exit 1
    fi
    PREFIX=$( echo ${POOL}/ROOT/${BE}/ | sed 's/\//\\\//g' )
    zfs list -H -o name,mountpoint -r ${POOL}/ROOT/${BE} \
      | grep -v "legacy$" \
      | sort -n \
      | grep -E "^${POOL}/ROOT/${BE}/" \
      | while read FS MOUNTPOINT
        do
          if [ "{FS}" != "${POOL}/ROOT/${BE}" ]
          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 )
                MOUNTPOINT="/${MOUNTPOINT}"
              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"
            COMPLETE=0
          fi
        done
    if [ ${COMPLETE} -eq 0 ]
    then
      echo "Partially mounted"
    else
      echo "Mounted successfully on '${TARGET}'"
    fi
    ;;

  (umount|unmount) # ------------------------------------------------------------------
    COMPLETE=1
    if [ ${#} -eq 2 ]
    then
      BE=${2}
    elif [ ${#} -eq 3 ]
    then
      BE=${3}
      if [ "${2}" = "-f" ]
      then
        OPTS="-f"
      else
        __usage
      fi
    else
      __usage
    fi
    __be_exist "$POOL/ROOT/$BE"
    if ! mount | grep -E "^${POOL}/ROOT/${BE} " 1> /dev/null 2> /dev/null
    then
      echo "The '${BE}' is not mounted"
      exit 1
    fi
    mount \
      | grep "^${POOL}/ROOT/${BE}" \
      | 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"
            COMPLETE=0
          fi
        done
    if [ ${COMPLETE} -eq 0 ]
    then
      echo "Partially unmounted"
    else
      echo "Unmounted successfully"
    fi
    ;;

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

esac
