#! /bin/sh

# Copyright (c) 2012-2019 Slawomir Wojciech Wojtczak (vermaden)
# 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.

BOOTTIME=$( sysctl -n kern.boottime | awk '{print $4}' | tr -d ',' )
CURRTIME=$( date +%s )
DIFFTIME=$(( ${CURRTIME} - ${BOOTTIME} ))
if [ ${DIFFTIME} -lt 45 ]
then
  exit 0
fi

PATH=${PATH}:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

__usage() {
    cat << EOF
AUTOMOUNT is a devd(8) based automounter for FreeBSD.

It supports following file systems:
UFS/FAT/exFAT/NTFS/EXT2/EXT3/EXT4/MTP/HFS

Add these to mount NTFS/exFAT/EXT4/MTP/HFS/XFS respectively:
 o sysutils/fusefs-ntfs
 o sysutils/fusefs-exfat
 o sysutils/fusefs-ext4fuse
 o sysutils/fusefs-simple-mtpfs
 o sysutils/fusefs-hfsfuse
 o sysutils/fusefs-lkl

By default it mounts/unmounts all removable media but
it is possible to set some additional options at the
/usr/local/etc/automount.conf config file.

Below is a list of possible options with description.

MNTPREFIX (set to /media by default)
  With this options You can alter the default root
  for mounting the removable media, for example to
  the /mnt directory.

  example: MNTPREFIX="/media"

ENCODING (set to en_US.ISO8859-1 by default)
  Only used with FAT32 mounts, specifies which
  encoding to use at the mount.

  example: ENCODING="pl_PL.ISO8859-2"

CODEPAGE (set to cp437 by default)
  Only used with FAT32 mounts, specifies which
  code page to use at the mount.

  example: CODEPAGE="cp852"

USER (unset by default)
  If set to some username, the mount command will
  chown(1) the mount directory with the user and
  its primary user group. If used with FM option
  allows to launch the specified file manager after
  a successful mount.

  example: USER="vermaden"

FM (unset by default)
  If set to file manager command, the mount will
  launch the specified command after successful
  mount. Works only if USER parameter is also set.

  example: FM="nautilus --browser --no-desktop"

USERUMOUNT (set to NO by default)
  When set to YES it will 'chmod +s /sbin/umount'
  which would allow an USER to unmount the file
  system with their selected file manager.

  example: USERUMOUNT="YES"

ATIME (set to YES by default)
  When set to NO it will mount filesystems with
  noatime options when possible.

  example: ATIME="NO"

REMOVEDIRS (set to NO by default)
  When set to YES it will remove empty directories
  under the used ${MNTPREFIX} after device detach.

  example: REMOVEDIRS="YES"

BLACKLIST (unset by default)
  The automount will ignore devices defined here.

  example: BLACKLIST="da0 da3s1a"

TIMEOUT (set to 8 by default)
  Do not wait longer then the specified timeout for
  the device node to appear in /dev and be accessible.

  example: TIMEOUT="8"

DELAY (set to 1 second by default)
  How often to check for device availability.

  example: DELAY="2.5"

BOOTDELAY (set to 45 seconds by default)
  How long to wait for boot process to complete.

  example: BOOTDELAY="30"

NOTIFY (set to NO by default)
  Use 'notify-send' and 'libnotify' to show notifications
  of mounting and unmounting devices on the desktop.
  Note that you have to call 'xhost +local:' command in
  your '~/.xinitrc' file for this to work.

  example: NOTIFY="YES"

WALL (set to NO by default)
  Use wall(1) to show notifications of mounting and
  unmounting devices on terminals of logged in users.

  example: WALL="YES"

EOF
  exit 0
}

if [ "${1}" = "--version" -o "${1}" = "-version" -o "${1}" = "version" ]
then
  echo "automount 1.6.0 2018/12/10"
  exit 0
fi

if [ "${1}" = "-h" -o "${1}" = "--help" -o ${#} -eq 0 -o ${#} -eq 1 ]
then
  __usage
fi

if [ -f /usr/local/etc/automount.conf ]
then
  . /usr/local/etc/automount.conf
fi

: ${MNTPREFIX="/media"}               # mount prefix
: ${LOG="/var/log/automount.log"}     # log file
: ${STATE="/var/run/automount.state"} # current state file
: ${ENCODING="en_US.ISO8859-1"}       # US/Canada
: ${CODEPAGE="cp437"}                 # US/Canada
: ${DATEFMT="%Y-%m-%d %H:%M:%S"}      # 2012-02-20 07:49:09
: ${USERUMOUNT="NO"}                  # when YES add suid bit to umount(8)
: ${ATIME="YES"}                      # when NO mount with noatime
: ${REMOVEDIRS="NO"}                  # remove empty dirs under ${MNTPREFIX}
: ${USER="0"}                         # which user to use for popup
: ${FM="0"}                           # which file manager to use
: ${TIMEOUT="8"}                      # stop waiting for device after that time
: ${DELAY="0.1"}                      # check for the device node that often
: ${BOOTDELAY="45"}                   # wait for boot process to complete
: ${NOTIFY="NO"}                      # use 'notify-send' and 'libnotify'
: ${WALL="NO"}                        # use 'wall(1)'

if [ "${USERUMOUNT}" = YES ]
then
  chmod u+s /sbin/umount 1> /dev/null 2> /dev/null # WHEEL group member
  chmod u+s /sbin/mount* 1> /dev/null 2> /dev/null # WHEEL group member
  sysctl vfs.usermount=1 1> /dev/null 2> /dev/null # allow USER to mount
fi

__create_mount_point() { # 1=DEV
  local DEVICE=${1##*/}
  mkdir -p ${MNTPREFIX}/${DEVICE}
  if [ "${USER}" != 0 ]
  then
    chown ${USER}:$( id -g -n ${USER} ) ${MNTPREFIX}/${DEVICE}
    UID=$( id -u ${USER} )
    GID=$( id -g ${USER} )
  else
    UID=0
    GID=0
  fi
}

__state_add() { # 1=DEV 2=PROVIDER 3=MNT
  if [ -f ${STATE} ]
  then
    if grep -E "${3}$" ${STATE} 1> /dev/null 2> /dev/null
    then
      __log "${1}: duplicated '${STATE}'"
      exit 0
    fi
  fi
  echo "${1} ${2} ${3}" >> ${STATE}
  if [ "${NOTIFY}" = YES ]
  then
    env DISPLAY=:0 notify-send automount "Device '${1}' mounted on '${3}' directory."
  fi
  if [ "${WALL}" = YES ]
  then
    echo "automount: Device '${1}' mounted on '${3}' directory." | wall
  fi
}

__state_remove() { # 1=MNT
  if [ -f ${STATE} ]
  then
    BSMNT=$( echo ${1} | sed 's/\//\\\//g' ) # backslash the slashes ;)
    sed -i '' "/${BSMNT}\$/d" ${STATE}
    if [ "${NOTIFY}" = YES ]
    then
      env DISPLAY=:0 notify-send automount "Device '${1}' unmounted from '${3}' directory."
    fi
    if [ "${WALL}" = YES ]
    then
      echo "automount: Device '${1}' unmounted from '${3}' directory." | wall
    fi
  fi
}

__remove_dir() { # 1=TARGET
  if [ "${REMOVEDIRS}" = YES ]
  then
    find "${1}" -type d -empty -maxdepth 1 -exec rm -r {} '+' 2> /dev/null
  fi
}

__log() { # @=MESSAGE
  echo $( date +"${DATEFMT}" ) "${@}" >> ${LOG}
}

__check_already_mounted() { # 1=(-d|-m) 2=(DEV|MNT)
  local MOUNT="$( mount )"
  case ${1} in
    (-d)
      if echo "${MOUNT}" | grep -q "^${2} on "
      then
        local MOUNT="$( echo "${MOUNT}" | grep "^${2} on " | cut -d ' ' -f 3-255 | cut -d '(' -f 1 | sed s/.$// )"
        __log "${DEV}: already mounted on '${MOUNT}' mount point"
        exit 0
      fi
      ;;
    (-m)
      if echo "${MOUNT}" | grep -q " on ${2} "
      then
        local DEVICE="$( echo "${MOUNT}" | grep " on ${2} " | awk '{print $1}' )"
        __log "${DEVICE}: already mounted on '${2}' mount point"
        exit 0
      fi
      ;;
  esac
}

__wait_for_device() { # 1=DEV
  local COUNT=0
  while ! head -c 1 ${1} 1> /dev/null 2> /dev/null
  do
    sleep ${DELAY}
    local COUNT=$( echo ${COUNT} + ${DELAY} | bc -l )
    if ! echo ${COUNT} | grep -q -E '^[0-9]'
    then
      local COUNT=0${COUNT}
    fi
    local COUNT_INT=$( echo ${COUNT} | cut -d '.' -f 1 )
    if [ ${COUNT_INT} -gt ${TIMEOUT} ]
    then
      __log "${DEV}: device node not available"
      exit 0
    fi
  done
}

__wait_for_boot() {
  local BOOTTIME=$( sysctl -n kern.boottime | awk -F',' '{print $1}' | awk '{print $NF }' )
  local CURRTIME=$( date +%s )
  local UPTIME=$(( ${CURRTIME} - ${BOOTTIME} ))
  local WAIT=0
  while [ ${UPTIME} -lt ${BOOTDELAY} ]
  do
    sleep 1
    local WAIT=1
    local CURRTIME=$( date +%s )
    local UPTIME=$(( ${CURRTIME} - ${BOOTTIME} ))
  done
  if [ ${WAIT} -eq 1 ]
  then
    __log "${DEV}: done waiting '${BOOTDELAY}' seconds for boot process to complete"
  fi
}

# __random_wait() {
#   RANDOM=$( head -c 256 /dev/urandom | env LC_ALL=C tr -c -d '1-9' )
#   MODULO=$(( ${RANDOM} % 24 ))
#   WAIT=$( echo ${MODULO} / 10 | bc -l )
#   WAIT_TEST=$( echo ${WAIT} | awk -F'.' '{print $1}' )
#   if [ "${WAIT_TEST}" = "" ]
#   then
#     WAIT="0${WAIT}"
#   fi
#   WAIT=$( printf "%.1f" ${WAIT} )
#   sleep ${WAIT}
#   __log "${DEV}: random wait for '${WAIT}' seconds before 'attach' action"
# }

__fstype() { # 1=DEV
  TYPE=$( dd < ${DEV} count=1 2> /dev/null | strings | head -1 )
  if echo "${TYPE}" | grep -q 'EXFAT'
  then
    TYPE=EXFAT
    return
  fi
  TYPE=''
  TYPE=$( file -r -b -L -s ${DEV} | sed -E 's/label:\ \".*\"//g' )
  if echo "${TYPE}" | grep -q 'Unix Fast File'
  then
    TYPE=UFS
    return
  fi
  if echo "${TYPE}" | grep -q 'ext2'
  then
    TYPE=EXT2
    return
  fi
  if echo "${TYPE}" | grep -q 'ext3'
  then
    TYPE=EXT3
    return
  fi
  if echo "${TYPE}" | grep -q 'ext4'
  then
    TYPE=EXT4
    return
  fi
  if echo "${TYPE}" | grep -q 'SGI XFS'
  then
    TYPE=XFS
    return
  fi
  if echo "${TYPE}" | grep -q 'Macintosh HFS'
  then
    TYPE=HFS
    return
  fi
  if echo "${TYPE}" | grep -q 'boot sector'
  then
    TYPE=$( file -r -k -b -L -s ${DEV} | sed -E 's/label:\ \".*\"//g' )
    if echo "${TYPE}" | grep -q 'Unix Fast File'
    then
      TYPE=UFS
      return
    fi
    if echo "${TYPE}" | grep -q 'NTFS'
    then
      TYPE=NTFS
      return
    fi
    if echo "${TYPE}" | grep -q 'MSDOS'
    then
      TYPE=FAT
      return
    fi
    if echo "${TYPE}" | grep -q 'FAT (32 bit)'
    then
      TYPE=FAT
      return
    fi
    if echo "${TYPE}" | grep -q 'FAT'
    then
      TYPE=FAT
      return
    fi
  fi
  TYPE=-1
  return
}

DEV=/dev/${1}
__wait_for_boot
case ${1} in

  (ugen*)
    case ${2} in

      (attach)
#       __random_wait
        __log "${DEV}: attach"
        if [ "${BLACKLIST}" != "" ]
          then
          __log "${DEV}: using BLACKLIST='${BLACKLIST}'"
          for I in ${BLACKLIST}
          do
            if [ ${1} = "${I}" ]
            then
              __log "${DEV}: device blocked by BLACKLIST option"
              exit 0
            fi
          done
        fi
        ADD=0
        MNT="${MNTPREFIX}/${1}"
        __check_already_mounted -d ${DEV}
        __check_already_mounted -m ${MNT}
        __wait_for_device ${DEV}
        PHONEDEV=$( simple-mtpfs --list-devices -d ${DEV} 2>&1 )
        if [ "${PHONEDEV}" = "No raw devices found." ]
        then
          __log "${DEV}: no raw devices found"
          exit 0
        else
          PHONEDEV=$( echo "${PHONEDEV}" | awk '{print $1}' | tr -d ':' )
        fi
        __create_mount_point ${DEV}
        simple-mtpfs --device ${PHONEDEV} ${MNT} -o uid=${UID} -o gid=${GID} -o allow_other
        if [ ${?} -ne 0 ]
        then
          su - ${USER} -c "env DISPLAY=:0 zenity --info --text 'Allow on the Phone.\n\nThen click OK.' --no-wrap"
          exit 0
        else
          # simple-mtpfs --device ${PHONEDEV} ${MNT} -o uid=${UID} -o gid=${GID} -o allow_other
          PROVIDER=$( mount | grep -m 1 " ${MNT} " | awk '{printf $1}' )
          __state_add ${DEV} ${PROVIDER} ${MNT}
          if [ "${USER}" != 0 -a "${FM}" != 0 ]
          then
            su - ${USER} -c "env DISPLAY=:0 ${FM} ${MNT} &"
          fi
        fi
        ;;

      (detach)
        __log "${DEV}: detach"
        if [ -f ${STATE} ]
        then
          grep -E "${MNTPREFIX}/${1}$" ${STATE} \
            | while read DEV PROVIDER MNT
              do
                TARGET=$( mount | grep -v \.gvfs | grep -m 1 -E "^${PROVIDER} " | awk '{print $3}' )
                __state_remove ${MNT}
                if [ -z ${TARGET} ]
                then
                  continue
                fi
                ( # put entire umount/find/rm block into background
                  umount -f ${TARGET}
                  __remove_dir "${TARGET}"
                  __log "${DEV}: removed '${TARGET}'"
                ) &
                unset TARGET
                __log "${DEV}: umount"
              done
          __remove_dir "${MNTPREFIX}/${1}"
          __log "${DEV}: mount point '${MNTPREFIX}/${1}' removed"
        fi
        ;;

    esac
    ;;

  (da*|mmcsd*)
    case ${2} in

      (attach)
#       __random_wait
        __log "${DEV}: attach"
        if [ "${BLACKLIST}" != "" ]
          then
          __log "${DEV}: using BLACKLIST='${BLACKLIST}'"
          for I in ${BLACKLIST}
          do
            if [ ${1} = "${I}" ]
            then
              __log "${DEV}: device blocked by BLACKLIST option"
              exit 0
            fi
          done
        fi
        ADD=0
        MNT="${MNTPREFIX}/${1}"
        __check_already_mounted -d ${DEV}
        __check_already_mounted -m ${MNT}
        if [ "${ATIME}" = NO ]
        then
          OPTS="-o noatime"
        fi
        __wait_for_device ${DEV}
        __fstype ${DEV}
        case ${TYPE} in

          (UFS)
            __create_mount_point ${DEV}
            __wait_for_device ${DEV}
            fsck_ufs -C -y ${DEV} \
              | while read LINE
                do
                  __log "${DEV}: fsck_ufs ${LINE}"
                done
            __wait_for_device ${DEV}
            if mount -t ufs ${OPTS} ${DEV} ${MNT}
            then
              ADD=1
            else
              __log "${DEV}: mount failed (ufs) 'mount -t ufs ${OPTS} ${DEV} ${MNT}'"
              exit 1
            fi
            __log "${DEV}: mount (ufs) 'mount -t ufs ${OPTS} ${DEV} ${MNT}'"
            ;;

          (FAT) # must be before NTFS section because: newfs_msdos -O NTFS -L NTFS
            __create_mount_point ${DEV}
            __wait_for_device ${DEV}
            fsck_msdosfs -C -y ${DEV} \
              | while read LINE
                do
                  __log "${DEV}: fsck_msdosfs ${LINE}"
                done
            __wait_for_device ${DEV}
            if [ "${USER}" != 0 ]
            then
              USEROPTS="-u ${UID} -g ${GID}"
            else
              USEROPTS=""
            fi
            FATCMD="mount_msdosfs ${OPTS} -o longnames -m 644 -M 755 -D ${CODEPAGE} -L ${ENCODING} ${USEROPTS} ${DEV} ${MNT}"
            if ${FATCMD}
            then
              ADD=1
            else
              FATOUT=16
              FATCUR=0
              while sleep 1
              do
                FATCUR=$(( ${FATCUR} + 1 ))
                if [ ${FATCUR} -gt ${FATOUT} ]
                then
                  __log "${DEV}: mount failed (fat) '${FATCMD}'"
                  break
                fi
                ${FATCMD}
                if [ ${?} -eq 0 ]
                then
                  ADD=1
                  break
                else
                  continue
                fi
              done
              exit 1
            fi
            if [ ${ADD} -eq 1 ]
            then
              __log "${DEV}: mount (fat) '${FATCMD}'"
            else
              __log "${DEV}: mount failed (fat) '${FATCMD}'"
            fi
            ;;

          (NTFS) # must be after FAT section: newfs_msdos -O NTFS -L NTFS
            __create_mount_point ${DEV}
            __wait_for_device ${DEV}
            if which ntfs-3g 1> /dev/null 2> /dev/null # sysutils/fusefs-ntfs
            then
              __wait_for_device ${DEV}
              if ntfs-3g -o recover -o remove_hiberfile ${OPTS} ${DEV} ${MNT}
              then
                ADD=1
              else
                # make nested mount try because sometimes second mount works
                if ntfs-3g -o recover -o remove_hiberfile ${OPTS} ${DEV} ${MNT}
                then
                  ADD=1
                else
                  __log "${DEV}: mount failed (ntfs) 'ntfs-3g ${OPTS} ${DEV} ${MNT}'"
                  exit 1
                fi
              fi
            else
              if ! [ "${USER}" = 0 ]
              then
                OPTS="${OPTS} -u ${USER} -g $( id -g -n ${USER} )"
              fi
              if mount_ntfs ${OPTS} ${DEV} ${MNT}
              then
                ADD=1
              else
                __log "${DEV}: mount failed (ntfs) 'mount_ntfs ${OPTS} ${DEV} ${MNT}'"
                exit 1
              fi
            fi
            __log "${DEV}: mount (ntfs) 'mount_ntfs ${OPTS} ${DEV} ${MNT}'"
            ;;

          (EXT2)
            __create_mount_point ${DEV}
            __wait_for_device ${DEV}
            e2fsck -y ${DEV} \
              | while read LINE
                do
                  __log "${DEV}: fsck.ext2 ${LINE}"
                done
            __wait_for_device ${DEV}
            if mount -t ext2fs ${OPTS} ${DEV} ${MNT}
            then
              ADD=1
            else
              __log "${DEV}: mount failed (ext2) 'mount -t ext2fs ${OPTS} ${DEV} ${MNT}'"
              exit 1
            fi
            __log "${DEV}: mount (ext2) 'mount -t ext2fs ${OPTS} ${DEV} ${MNT}'"
            ;;

          (EXT3)
            __create_mount_point ${DEV}
            __wait_for_device ${DEV}
            e2fsck -y ${DEV} \
              | while read LINE
                do
                  __log "${DEV}: fsck.ext3 ${LINE}"
                done
            __wait_for_device ${DEV}
            if mount -t ext2fs ${OPTS} ${DEV} ${MNT}
            then
              ADD=1
            else
              __log "${DEV}: mount failed (ext3) 'mount -t ext2fs ${OPTS} ${DEV} ${MNT}'"
              exit 1
            fi
            __log "${DEV}: mount (ext3) 'mount -t ext2fs ${OPTS} ${DEV} ${MNT}'"
            ;;

          (EXT4)
            __create_mount_point ${DEV}
            __wait_for_device ${DEV}
            e2fsck -y ${DEV} \
              | while read LINE
                do
                  __log "${DEV}: fsck.ext4 ${LINE}"
                done
            __wait_for_device ${DEV}
            if ext4fuse ${DEV} ${MNT} # sysutils/fusefs-ext4fuse
            then
              ADD=1
            else
              __log "${DEV}: mount failed (ext4) 'ext4fuse ${DEV} ${MNT}'"
              exit 1
            fi
            __log "${DEV}: mount (ext4) 'ext4fuse ${DEV} ${MNT}'"
            ;;

          (EXFAT)
            __create_mount_point ${DEV}
            __wait_for_device ${DEV}
            if [ "${USER}" != 0 ]
            then
              USEROPTS="-o uid=${UID} -o gid=${GID}"
            else
              USEROPTS=""
            fi
            # sysutils/fusefs-exfat
            if mount.exfat ${OPTS} ${USEROPTS} -o dmask=022 -o fmask=133 \
               -o noatime ${DEV} ${MNT}
            then
              ADD=1
            else
              __log "${DEV}: mount failed (exfat) 'mount.exfat ${OPTS} ${USEROPTS} -o dmask=022 -o fmask=133 -o noatime ${DEV} ${MNT}'"
              exit 1
            fi
            __log "${DEV}: mount (exfat) 'mount.exfat ${OPTS} ${USEROPTS} -o dmask=022 -o fmask=133 -o noatime ${DEV} ${MNT}'"
            ;;

          (XFS)
            __create_mount_point ${DEV}
            __wait_for_device ${DEV}
            xfs_repair -d ${DEV} \
              | while read LINE
                do
                  __log "${DEV}: xfs_repair ${LINE}"
                done
            __wait_for_device ${DEV}
            if lklfuse -o type=xfs -o allow_other -o uid=${UID} -o gid=${GID} ${DEV} ${MNT} # sysutils/fusefs-lkl
            then
              ADD=1
            else
              __log "${DEV}: mount failed (xfs) 'lklfuse -o type=xfs -o allow_other -o uid=${UID} -o gid=${GID} ${DEV} ${MNT}'"
              exit 1
            fi
            __log "${DEV}: mount (xfs) 'lklfuse -o type=xfs -o allow_other -o uid=${UID} -o gid=${GID} ${DEV} ${MNT}'"
            ;;

          (HFS)
            __create_mount_point ${DEV}
            __wait_for_device ${DEV}
            if hfsfuse --force -o noatime ${DEV} ${MNT} # sysutils/fusefs-hfsfuse
            then
              ADD=1
            else
              __log "${DEV}: mount failed (hfs) 'hfsfuse --force -o noatime ${DEV} ${MNT}'"
              exit 1
            fi
            __log "${DEV}: mount (hfs) 'hfsfuse --force -o noatime ${DEV} ${MNT}'"
            ;;

          (*)
            __log "${DEV}: filesystem not supported or no filesystem"
            exit 0
            ;;

        esac
        if [ ${ADD} -eq 1 ]
        then
          ADD=0
          PROVIDER=$( mount | grep -m 1 " ${MNT} " | awk '{printf $1}' )
          __state_add ${DEV} ${PROVIDER} ${MNT}
          if [ "${USER}" != 0 -a "${FM}" != 0 ]
          then
            su - ${USER} -c "env DISPLAY=:0 ${FM} ${MNT} &"
          fi
        fi
        ;;

      (detach)
        __log "${DEV}: detach"
        if [ -f ${STATE} ]
        then
          grep -E "${MNTPREFIX}/${1}$" ${STATE} \
            | while read DEV PROVIDER MNT
              do
                TARGET=$( mount | grep -v \.gvfs | grep -m 1 -E "^${PROVIDER} " | awk '{print $3}' )
                __state_remove ${MNT}
                if [ -z ${TARGET} ]
                then
                  continue
                fi
                ( # put entire umount/find/rm block into background
                  umount -f ${TARGET}
                  __remove_dir "${TARGET}"
                  __log "${DEV}: removed '${TARGET}'"
                ) &
                unset TARGET
                __log "${DEV}: umount"
              done
          __remove_dir "${MNTPREFIX}/${1}"
          __log "${DEV}: mount point '${MNTPREFIX}/${1}' removed"
        fi
        ;;

    esac
    ;;

esac
