devd based AUTOMOUNTER

vermaden vermaden at interia.pl
Mon Feb 20 08:44:03 UTC 2012


Hi,

new version with new features (and BUGs ;p)

Added check if ntfsfix from sysutils/ntfsprogs is available, if Yes then
try to fix the NTFS filesystem before mouting it.

Added GPL3 License ... just joking ;) ... added FreeBSD License to the file.

Added 'noatime' as a default mount option when possible.

Added TIMEOUT so when an 'orphan' STATE file lock remains, it will be deleted after a TIMEOUT.

Added /usr/local/etc/devd/automount.devd file instead of messing with the base system config at /etc/devd.conf.

Added config file to be used from /usr/local/etc/automount.conf file, possible options are (these are defaults):
  MNTPREFIX="/media"
  LOG="/var/log/automount.log"
  STATE="/var/run/automount.state"
  ENCODING="en_US.ISO8859-1"
  CODEPAGE="cp437"
  DATEFMT="%Y-%m-%d %H:%M:%S"
  USERUMOUNT="NO"

Mine config currently has only these:
  ENCODING="pl_PL.ISO8859-2"
  CODEPAGE="cp852"
  USERUMOUNT="YES"

The USERMOUNT otions if set to YES (default to NO) will 'chmod +s /sbin/umount',
so You can click the ^ button on the devices list in NAUTILUS.

These newly mounted devices appear on NAUTILUS sidebar (only with /media prefix).

But THUNAR and PCMANFM does not do that, You know any other FMs that display mounted thumb drives/devices?

EXAMPLE: http://i.imgur.com/qdKdl.png

First BUG: (not fixed yet, but workaround already is working)

TEST/BUG/CASE:
Plug in FAT32 and NTFS drives at the same time, when FAT32 device will be detected first, it will get mounted and the NTFS drive will be mounted TWICE, so I added __check_already_mounted function to check if it is not already mounted.



Below are current script and config files.

/usr/local/etc/devd/automount.devd
-------------------------------------------------------------------------------
notify 0 {
  match "system" "DEVFS";
	match "type" "CREATE";
	match "cdev" "(da|mmcsd)[0-9]+";
	action "/usr/local/sbin/automount.sh $cdev attach";
};

notify 0 {
	match "system" "DEVFS";
	match "type" "DESTROY";
	match "cdev" "(da|mmcsd)[0-9]+";
	action "/usr/local/sbin/automount.sh $cdev detach";
};
-------------------------------------------------------------------------------

/usr/local/etc/automout.conf (can be empty)
-------------------------------------------------------------------------------
MNTPREFIX="/media"
LOG="/var/log/automount.log"
STATE="/var/run/automount.state"
ENCODING="en_US.ISO8859-1"
CODEPAGE="cp437"
DATEFMT="%Y-%m-%d %H:%M:%S"
USERUMOUNT="NO"
-------------------------------------------------------------------------------

/usr/local/sbin/automount.sh
-------------------------------------------------------------------------------
#! /bin/sh

# Copyright (c) 2011 Slawomir Wojciech Wojtczak (vermaden)
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the 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.

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

[ -f /usr/local/etc/automount.conf ] && . /usr/local/etc/automount.conf

: ${MNTPREFIX="/media"}
: ${LOG="/var/log/automount.log"}
: ${STATE="/var/run/automount.state"}
: ${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) */

[ "${USERUMOUNT}" = "YES" ] && chmod u+s /sbin/umount # /* WHEEL group member */

__create_mount_point() { # /* 1=DEV */
  MNT="${MNTPREFIX}/$( basename ${1} )"
  mkdir -p ${MNT}
  chown 1000 ${MNT}
}

__check_already_mounted() { # /* 1=MNT */
  mount | grep " ${1} " 1> /dev/null 2> /dev/null && {
    __log "${I}:already mounted (ntfs)"
    continue
  }
}

__state_lock() {
  TIMEOUT=60
  COUNT=0
  while [ -f ${STATE}.lock ]
  do
    sleep 0.5
    [ ${COUNT} -gt ${TIMEOUT} ] && break
    COUNT=$(( ${COUNT} + 1 ))
  done
  :> ${STATE}.lock
}

__state_unlock() {
  rm ${STATE}.lock
}

__state_add() { # /* 1=DEV 2=PROVIDER 3=MNT */
  __state_lock
  grep -E "${3}" ${STATE} 1> /dev/null 2> /dev/null && {
    __log "${1}:duplicated '${STATE}'"
    return 1
  }
  echo "${1} ${2} ${3}" >> ${STATE}
  __state_unlock
}

__state_remove() { # /* 1=MNT 2=STATE 3=LINE */
  BSMNT=$( echo ${1} | sed 's/\//\\\//g' ) # /* backslash the slashes ;) */
  sed -i '' "/${BSMNT}\$/d" ${2}
}

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

case ${2} in
  (attach)
    for I in /dev/${1}*
    do
      case $( file -b -L -s ${I} | sed -E 's/label:\ \".*\"//g' ) in
        (*NTFS*)
          dd < ${I} count=1 2> /dev/null | strings | head -1 | grep -q "NTFS" && {
              __create_mount_point ${I}
              which ntfsfix 1> /dev/null 2> /dev/null && {
                ntfsfix ${I} # /* sysutils/ntfsprogs */
              }
              __check_already_mounted ${MNT}
              which ntfs-3g 1> /dev/null 2> /dev/null && {
                ntfs-3g -o noatime ${I} ${MNT} # /* sysutils/fusefs-ntfs */
              } || {
                mount_ntfs -o noatime ${I} ${MNT}
              }
              __log "${I}:mount (ntfs)"
          }
          ;;
        (*FAT*)
          dd < ${I} count=1 2> /dev/null | strings | grep -q "FAT32" && {
              __create_mount_point ${I}
              fsck_msdosfs -y ${I}
              __check_already_mounted ${MNT}
              mount_msdosfs -o large -L ${ENCODING} -D ${CODEPAGE} ${I} ${MNT}
              __log "${I}:mount (fat)"
          }
          ;;
        (*ext2*)
          __create_mount_point ${I}
          fsck.ext2 -y ${I}
          mount -t ext2fs -o noatime ${I} ${MNT}
          __check_already_mounted ${MNT}
          __log "${I}:mount (ext2)"
          ;;
        (*ext3*)
          __create_mount_point ${I}
          fsck.ext3 -y ${I}
          __check_already_mounted ${MNT}
          mount -t ext2fs -o noatime ${I} ${MNT}
          __log "${I}:mount (ext3)"
          ;;
        (*ext4*)
          __create_mount_point ${I}
          fsck.ext4 -y ${I}
          __check_already_mounted ${MNT}
          ext4fuse ${I} ${MNT} # /* sysutils/fusefs-ext4fuse */
          __log "${I}:mount (ext4)"
          ;;
        (*Unix\ Fast\ File*)
          __create_mount_point ${I}
          fsck_ufs -y ${I}
          __check_already_mounted ${MNT}
          mount -o noatime ${I} ${MNT}
          __log "${I}:mount (ufs)"
          ;;
        (*)
          case $( dd < ${I} count=1 2> /dev/null | strings | head -1 ) in
            (EXFAT)
              __create_mount_point ${I}
              __check_already_mounted ${MNT}
              mount.exfat -o noatime ${I} ${MNT} # /* sysutils/fusefs-exfat */
              __log "${I}:mount (ufs)"
              ;;
            (*) continue ;;
          esac
          ;;
      esac
      __state_add ${I} $( mount | grep -m 1 " ${MNT} " | awk '{printf $1}' ) ${MNT}
    done
    ;;

  (detach)
    MOUNT=$( mount )
    __state_lock
    grep ${1} ${STATE} \
      | while read DEV PROVIDER MNT
        do
          TARGET=$( echo "${MOUNT}" | grep -E "^${PROVIDER} " | awk '{print $3}' )
          [ -z ${TARGET} ] && {
            __state_remove ${MNT} ${STATE} ${LINE}
            continue
          }
          umount -f ${TARGET} &
          unset TARGET
          __state_remove ${MNT} ${STATE} ${LINE}
          __log "${DEV}:umount"
        done
    __state_unlock
    __log "/dev/${1}:detach"
    find ${MNTPREFIX} -type d -empty -delete
    ;;

esac

-------------------------------------------------------------------------------


More information about the freebsd-hackers mailing list