Major code rework. CD-ROM support. Notifications. Lots of fixes and changes.

This commit is contained in:
vermaden 2019-08-28 14:42:27 +02:00
parent 8ced675ae6
commit 6ad9b18041
5 changed files with 543 additions and 584 deletions

21
README
View File

@ -1,7 +1,7 @@
The 'automount' is a devd(8) based automounter for FreeBSD. The 'automount' is a devd(8) based automounter for FreeBSD.
It supports most popular file systems: It supports most popular file systems:
NTFS/MSDOS/exFAT/EXT2/EXT3/EXT4/UFS/XFS/HFS/MTP NTFS/MSDOS/exFAT/EXT2/EXT3/EXT4/UFS/XFS/HFS/MTP/ISO9660
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -30,7 +30,6 @@ These Ports/packages are neede for all filesystems:
* sysutils/fusefs-hfsfuse // HFS * sysutils/fusefs-hfsfuse // HFS
* sysutils/fusefs-lkl // XFS * sysutils/fusefs-lkl // XFS
* sysutils/fusefs-simple-mtpfs // MTP * sysutils/fusefs-simple-mtpfs // MTP
* x11/zenity // MTP
Regards, Regards,
vermaden vermaden
@ -42,7 +41,23 @@ C H A N G E L O G
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
VERSION 1.6.1 (CURRENT) VERSION 1.7.0 (CURRENT)
The automount has now a new co-author - Rozhuk Ivan.
New options available in automount.conf config file.
Filesystem detection/mounting reworked totally with file(1)/dd(1)/fstyp(8) as backends.
Notifications are now possible with libnitify(8) library.
Automatic detection of DISPLAY variable.
New automatic wait for device appearance.
New detection if device is a block device.
Introduction of CD-ROM support.
Automatic detection of File Manager with exo-open(1).
Option REMOVEDIRS is deprecated now.
Handle '-o large' option for FAT under FreeBSD 11.x and 12.x versions.
-------------------------------------------------------------------------------
VERSION 1.6.1
Fix MBR/msdosfs partition unmount issue. Fix MBR/msdosfs partition unmount issue.

1050
automount
View File

@ -1,6 +1,7 @@
#! /bin/sh #!/bin/sh
# Copyright (c) 2012-2019 Slawomir Wojciech Wojtczak (vermaden) # Copyright (c) 2012-2019 Slawomir Wojciech Wojtczak <vermaden@interia.pl>
# Copyright (c) 2019 Rozhuk Ivan <rozhuk.im@gmail.com>
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@ -22,22 +23,14 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # 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 PATH=${PATH}:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
__usage() { __usage() {
cat << EOF cat << EOF
AUTOMOUNT is a devd(8) based automounter for FreeBSD. AUTOMOUNT is a devd(8) based automounter for FreeBSD.
It supports following file systems: It supports following file systems:
UFS/FAT/exFAT/NTFS/EXT2/EXT3/EXT4/MTP/HFS UFS/FAT/exFAT/NTFS/EXT2/EXT3/EXT4/MTP/HFS/ISO9660
Add these to mount NTFS/exFAT/EXT4/HFS/XFS/MTP respectively: Add these to mount NTFS/exFAT/EXT4/HFS/XFS/MTP respectively:
o sysutils/fusefs-ntfs o sysutils/fusefs-ntfs
@ -46,7 +39,6 @@ Add these to mount NTFS/exFAT/EXT4/HFS/XFS/MTP respectively:
o sysutils/fusefs-hfsfuse o sysutils/fusefs-hfsfuse
o sysutils/fusefs-lkl o sysutils/fusefs-lkl
o sysutils/fusefs-simple-mtpfs o sysutils/fusefs-simple-mtpfs
o x11/zenity
By default it mounts/unmounts all removable media but By default it mounts/unmounts all removable media but
it is possible to set some additional options at the it is possible to set some additional options at the
@ -54,26 +46,86 @@ it is possible to set some additional options at the
Below is a list of possible options with description. Below is a list of possible options with description.
MNTPREFIX (set to /media by default) MNT_PREFIX (set to /media by default)
With this options You can alter the default root With this options You can alter the default root
for mounting the removable media, for example to for mounting the removable media, for example to
the /mnt directory. the /mnt directory.
example: MNTPREFIX="/media" example: MNT_PREFIX='/media'
ENCODING (set to en_US.ISO8859-1 by default) MNT_GROUP (wheel by default)
If set to some group name, the mount command will
chown(1) the mount directory with the group.
example: group='operator'
MNT_MODE (set to 775 by default)
Value for chmod on mount point.
FAT_ENCODING (set to en_US.UTF-8 by default)
Only used with FAT32 mounts, specifies which Only used with FAT32 mounts, specifies which
encoding to use at the mount. encoding to use at the mount.
example: ENCODING="pl_PL.ISO8859-2" example: FAT_ENCODING='en_US.ISO8859-1'
CODEPAGE (set to cp437 by default) FAT_CODEPAGE (set to CP866 by default)
Only used with FAT32 mounts, specifies which Only used with FAT32 mounts, specifies which
code page to use at the mount. code page to use at the mount.
example: CODEPAGE="cp852" example: FAT_CODEPAGE='cp437'
USER (unset by default) ISO9660_CODEPAGE (set to UTF-8 by default)
Only used with cd9660 mounts, specifies which
code page to use at the mount.
ATIME (set to NO by default)
When set to NO it will mount filesystems with
noatime option when possible.
example: ATIME='YES'
RETRY_COUNT (set to 3 by default)
How many times try to get file system type or try to mount.
example: RETRY_COUNT='1'
RETRY_DELAY (set to 1 second by default)
Delay beetwin retry attempt.
example: RETRY_DELAY='2.5'
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'
NOTIFY (set to NO by default)
Use 'notify-send' and 'libnotify' to show notifications
of mounting and unmounting devices on the desktop.
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'
FM ('exo-open --launch FileManager' 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'
BLACKLIST (unset by default)
The automount will ignore devices defined here.
example: BLACKLIST='da0 da3s1a'
USER (root by default)
If set to some username, the mount command will If set to some username, the mount command will
chown(1) the mount directory with the user and chown(1) the mount directory with the user and
its primary user group. If used with FM option its primary user group. If used with FM option
@ -82,119 +134,133 @@ USER (unset by default)
example: USER="vermaden" 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"
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 EOF
exit 0 exit 0
} }
if [ "${1}" = "--version" -o "${1}" = "-version" -o "${1}" = "version" ] # display version if needed
if [ "${1}" = '--version' -o \
"${1}" = '-version' -o \
"${1}" = 'version' -o \
"${1}" = '-v' ]
then then
echo "automount 1.6.1 2019/01/11" echo "automount 1.7.0 2019/08/28"
exit 0 exit 0
fi fi
if [ "${1}" = "-h" -o "${1}" = "--help" -o ${#} -eq 0 -o ${#} -eq 1 ] # display help if needed
if [ "${1}" = "-h" -o \
"${1}" = "--h" -o \
"${1}" = "-help" -o \
"${1}" = "--help" -o \
"${#}" -eq "0" -o \
"${#}" -eq "1" ]
then then
__usage __usage
fi fi
if [ -f /usr/local/etc/automount.conf ] # read configuration file
then if [ -f /usr/local/etc/automount.conf ] ; then
. /usr/local/etc/automount.conf . /usr/local/etc/automount.conf
fi fi
: ${MNTPREFIX="/media"} # mount prefix # default values for global variables
: ${LOG="/var/log/automount.log"} # log file : ${MNT_PREFIX='/media'} # mount prefix
: ${STATE="/var/run/automount.state"} # current state file : ${MNT_GROUP='wheel'} # use WHEEL group for popup
: ${ENCODING="en_US.ISO8859-1"} # US/Canada : ${MNT_MODE='775'} # mount point mode
: ${CODEPAGE="cp437"} # US/Canada : ${FAT_ENCODING='en_US.UTF-8'} # US/Canada
: ${DATEFMT="%Y-%m-%d %H:%M:%S"} # 2012-02-20 07:49:09 : ${FAT_CODEPAGE='cp437'} # US/Canada
: ${USERUMOUNT="NO"} # when YES add suid bit to umount(8) : ${ISO9660_CODEPAGE='UTF-8'} # UTF-8
: ${ATIME="YES"} # when NO mount with noatime : ${ATIME='NO'} # when NO mount with noatime
: ${REMOVEDIRS="NO"} # remove empty dirs under ${MNTPREFIX} : ${RETRY_COUNT='3'} # retry count
: ${USER="0"} # which user to use for popup : ${RETRY_DELAY='1'} # retry delay time
: ${FM="0"} # which file manager to use : ${USERUMOUNT='NO'} # when YES add suid bit to umount(8)
: ${TIMEOUT="8"} # stop waiting for device after that time : ${NOTIFY='NO'} # use notify-send(1) (devel/libnotify)
: ${DELAY="0.1"} # check for the device node that often : ${WALL='NO'} # use wall(1)
: ${NOTIFY="NO"} # use 'notify-send' and 'libnotify' : ${FM='exo-open --launch FileManager'} # which file manager to use
: ${WALL="NO"} # use 'wall(1)' : ${LOG_FILE='/var/log/automount.log'} # log file
: ${LOG_DATEFMT='%Y-%m-%d %H:%M:%S'} # 2012-02-20 07:49:09
: ${STATE="/var/run/automount.state"} # current state file
: ${USER="0"} # which user to use for popup
if [ "${USERUMOUNT}" = YES ] # init of main variables
DEV="/dev/${1}"
MNT="${MNT_PREFIX}/${1}"
UID=$( id -u ${USER} )
GID=$( pw group show -n ${MNT_GROUP} | awk -F':' '{print $3}' )
if [ ${?} -ne 0 ]
then then
chmod u+s /sbin/umount 1> /dev/null 2> /dev/null # WHEEL group member __log "${MNT_GROUP}: invalid group"
chmod u+s /sbin/mount* 1> /dev/null 2> /dev/null # WHEEL group member exit 1
sysctl vfs.usermount=1 1> /dev/null 2> /dev/null # allow USER to mount
fi fi
__create_mount_point() { # 1=DEV # process ${USERUMOUNT} option
local DEVICE=${1##*/} case ${USERUMOUNT} in
mkdir -p ${MNTPREFIX}/${DEVICE} ([Yy][Ee][Ss])
if [ "${USER}" != 0 ] chmod u+s /sbin/umount 1> /dev/null 2>&1 # WHEEL group member
then chmod u+s /sbin/mount* 1> /dev/null 2>&1 # WHEEL group member
chown ${USER}:$( id -g -n ${USER} ) ${MNTPREFIX}/${DEVICE} sysctl -q vfs.usermount=1 1> /dev/null 2>&1 # allow user to mount
UID=$( id -u ${USER} ) ;;
GID=$( id -g ${USER} ) esac
else
UID=0 # read only filesystem types for __guess_fs_type() function
GID=0 readonly FS_TYPE_UNKNOWN=0
fi readonly FS_TYPE_ISO9660=1
readonly FS_TYPE_UFS=8
readonly FS_TYPE_EXT2=9
readonly FS_TYPE_EXT3=10
readonly FS_TYPE_EXT4=11
readonly FS_TYPE_XFS=12
readonly FS_TYPE_HFS=13
readonly FS_TYPE_FAT=32
readonly FS_TYPE_EXFAT=33
readonly FS_TYPE_NTFS=34
readonly FS_TYPE_MTP=128
# FUNCTION: guess filesystemy type from the device
__guess_fs_type() { # 1=DEV
# first time guess with file(1) tool
unset FS_TYPE
local FS_TYPE=$( file -r -b -L -s ${1} 2> /dev/null | sed -E 's/label:\ \".*\"//g' )
case ${FS_TYPE} in
(*ISO\ 9660*) return ${FS_TYPE_ISO9660} ;;
(*Unix\ Fast\ File*) return ${FS_TYPE_UFS} ;;
(*ext2*) return ${FS_TYPE_EXT2} ;;
(*ext3*) return ${FS_TYPE_EXT3} ;;
(*ext4*) return ${FS_TYPE_EXT4} ;;
(*SGI\ XFS*) return ${FS_TYPE_XFS} ;;
(*Macintosh\ HFS*) return ${FS_TYPE_HFS} ;;
esac
# second time guess with file(1) tool with -k option
# (do not stop at the first match and keep going)
unset FS_TYPE
local FS_TYPE=$( file -k -r -b -L -s ${1} 2> /dev/null | sed -E 's/label:\ \".*\"//g' )
case ${FS_TYPE} in
(*Unix\ Fast\ File*) return ${FS_TYPE_UFS} ;;
(*NTFS*) return ${FS_TYPE_NTFS} ;;
(*FAT*|*MSDOS*) return ${FS_TYPE_FAT} ;;
esac
# try with fstyp(8) last (exFAT on UFS issue)
unset FS_TYPE
local FS_TYPE=$( fstyp ${1} 2> /dev/null )
case ${FS_TYPE} in
(cd9660) return ${FS_TYPE_ISO9660} ;;
(ufs) return ${FS_TYPE_UFS} ;;
(ext2fs) return ${FS_TYPE_EXT2} ;;
(msdosfs) return ${FS_TYPE_FAT} ;;
(exfat) return ${FS_TYPE_EXFAT} ;;
(ntfs) return ${FS_TYPE_NTFS} ;;
esac
# magic detection code with dd(8)
unset FS_TYPE
local FS_TYPE=$( dd if="${1}" conv=sync count=1 bs=1k 2> /dev/null | strings | head -1 )
case ${FS_TYPE} in
(*EXFAT*) return ${FS_TYPE_EXFAT} ;;
esac
return ${FS_TYPE_UNKNOWN}
} }
# FUNCTION: add state to the ${STATE} file
__state_add() { # 1=DEV 2=PROVIDER 3=MNT __state_add() { # 1=DEV 2=PROVIDER 3=MNT
if [ -f ${STATE} ] if [ -f ${STATE} ]
then then
@ -207,7 +273,7 @@ __state_add() { # 1=DEV 2=PROVIDER 3=MNT
echo "${1} ${2} ${3}" >> ${STATE} echo "${1} ${2} ${3}" >> ${STATE}
if [ "${NOTIFY}" = YES ] if [ "${NOTIFY}" = YES ]
then then
env DISPLAY=:0 notify-send automount "Device '${1}' mounted on '${3}' directory." __show_message "Device '${1}' mounted on '${3}' directory."
fi fi
if [ "${WALL}" = YES ] if [ "${WALL}" = YES ]
then then
@ -215,14 +281,16 @@ __state_add() { # 1=DEV 2=PROVIDER 3=MNT
fi fi
} }
# FUNCTION: remove state from the ${STATE} file
__state_remove() { # 1=MNT __state_remove() { # 1=MNT
if [ -f ${STATE} ] if [ -f ${STATE} ]
then then
BSMNT=$( echo ${1} | sed 's/\//\\\//g' ) # backslash the slashes ;) # backslash the slashes ;)
BSMNT=$( echo ${1} | sed 's/\//\\\//g' )
sed -i '' "/${BSMNT}\$/d" ${STATE} sed -i '' "/${BSMNT}\$/d" ${STATE}
if [ "${NOTIFY}" = YES ] if [ "${NOTIFY}" = YES ]
then then
env DISPLAY=:0 notify-send automount "Device '${1}' unmounted from '${3}' directory." __show_message "Device '${1}' unmounted from '${3}' directory."
fi fi
if [ "${WALL}" = YES ] if [ "${WALL}" = YES ]
then then
@ -231,502 +299,344 @@ __state_remove() { # 1=MNT
fi fi
} }
# FUNCTION: add message to the ${LOG_FILE} file
__log() { # @=MESSAGE
echo $( date +"${LOG_DATEFMT}" ) "${@}" >> "${LOG_FILE}"
}
# FUNCTION: remove temp mount dir from ${MNT_PREFIX} path (like /media/da0 dir)
__remove_dir() { # 1=TARGET __remove_dir() { # 1=TARGET
if [ "${REMOVEDIRS}" = YES ] if [ "${REMOVEDIRS}" = YES ]
then then
find "${1}" -type d -empty -maxdepth 1 -exec rm -r {} '+' 2> /dev/null if [ -d "${1}" ]
then
find "${1}" -type d -empty -maxdepth 1 -exec rm -r {} '+' 2> /dev/null
fi
fi fi
} }
__log() { # @=MESSAGE # FUNCTION: display wall(1) and/or notify-send(1) message
echo $( date +"${DATEFMT}" ) "${@}" >> ${LOG} __show_message() { # 1=MESSAGE
} case ${WALL} in
([Yy][Ee][Ss])
__check_already_mounted() { # 1=(-d|-m) 2=(DEV|MNT) echo "automount: ${1}" | wall
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) esac
if echo "${MOUNT}" | grep -q " on ${2} " case ${NOTIFY} in
then ([Yy][Ee][Ss])
local DEVICE="$( echo "${MOUNT}" | grep " on ${2} " | awk '{print $1}' )" local __DISPLAY_IDS=$( ps aew | sed -n 's|.*DISPLAY=\([-_a-zA-Z0-9:.]*\).*|\1|p' | sort -u | tr '\n' ' ' )
__log "${DEVICE}: already mounted on '${2}' mount point" for __DISPLAY_ID in ${__DISPLAY_IDS}
exit 0 do
fi local __USER=$( ps aewj | grep "DISPLAY=${__DISPLAY_ID}" | awk '{print $1;}' | sort -u | tr -cd '[:print:]' )
if [ -z "${__USER}" ]
then
continue
fi
su -l "${__USER}" -c "env DISPLAY=${__DISPLAY_ID} notify-send automount '${1}' &" 1> /dev/null 2>&1
done
;; ;;
esac esac
} }
# FUNCTION: check if device or mountpoint not already mounted
__check_already_mounted() { # 1=DEV 2=MNT
local MOUNT=$( mount )
if echo "${MOUNT}" | grep -q "^${1} on "
then
local MOUNT_POINT=$( echo "${MOUNT}" | grep "^${1} on " | cut -d ' ' -f 3-255 | cut -d '(' -f 1 | sed s/.$// )
__log "${DEV}: already mounted on '${MOUNT_POINT}' mount point"
exit 1
fi
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 1
fi
}
# FUNCTION: wait for device to appear (sometimes needed)
__wait_for_device() { # 1=DEV __wait_for_device() { # 1=DEV
# do not wait for MTP and CD-ROM devices
case ${1} in
(*ugen*|iso9660*)
return
;;
esac
# try to read from device to ensure that it alive
local COUNT=0 local COUNT=0
while ! head -c 1 ${1} 1> /dev/null 2> /dev/null while ! dd if="${1}" of=/dev/null conv=sync count=1 bs=256k 1> /dev/null 2>&1
do do
sleep ${DELAY} if [ ! -e "${1}" ]
local COUNT=$( echo ${COUNT} + ${DELAY} | bc -l )
if ! echo ${COUNT} | grep -q -E '^[0-9]'
then then
local COUNT=0${COUNT} __log "${1}: device gone"
exit 1
fi fi
local COUNT_INT=$( echo ${COUNT} | cut -d '.' -f 1 ) COUNT=$(( ${COUNT} + 1 ))
if [ ${COUNT_INT} -gt ${TIMEOUT} ] if [ ${COUNT} -ge ${RETRY_COUNT} ]
then then
__log "${DEV}: device node not available" return
exit 0
fi fi
sleep "${RETRY_DELAY}"
__log "${1}: wait for device retry ${COUNT}/${RETRY_COUNT}"
done done
} }
__fstype() { # 1=DEV # FUNCTION: check if device is a block device
TYPE=$( dd < ${DEV} count=1 2> /dev/null | strings | head -1 ) __check_block_device() { # 1=DEV
if echo "${TYPE}" | grep -q 'EXFAT' # first check if its block device
if ! fstyp ${1} 1> /dev/null 2>&1
then then
TYPE=EXFAT __log "${DEV}: not a block device"
return exit 0
fi 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} # main ATTACH/DETACH block
case ${1} in case ${2} in
(attach)
(ugen*) # check if device still exists
case ${2} in if [ ! -e "${DEV}" ]
then
(attach) __log "${DEV}: device does not exists"
__log "${DEV}: attach" exit 1
if [ "${BLACKLIST}" != "" ] fi
then __log "${DEV}: attach"
__log "${DEV}: using BLACKLIST='${BLACKLIST}'" # blacklist check
for I in ${BLACKLIST} if [ -n "${BLACKLIST}" ]
do then
if [ ${1} = "${I}" ] for I in ${BLACKLIST}
then do
__log "${DEV}: device blocked by BLACKLIST option" if [ "${1}" = "${I}" ]
exit 0 then
fi __log "${DEV}: device blocked by BLACKLIST option"
done exit 0
fi
done
fi
# check is device already mounted
__check_already_mounted "${DEV}" "${MNT}"
# make sure that data can be read from device
__wait_for_device "${DEV}"
# detect filesysytem type
case ${1} in
(iso9660*)
FS_TYPE=${FS_TYPE_ISO9660}
;;
(ugen*)
__check_block_device "${DEV}"
FS_TYPE=${FS_TYPE_MTP}
;;
(cd*|da*|mmcsd*)
__check_block_device "${DEV}"
__guess_fs_type "${DEV}"
FS_TYPE=${?}
;;
esac
# process ATIME option
case ${ATIME} in
([Nn][Oo]) OPTS="-o noatime" ;;
esac
# filesystem options abstraction layer
case ${FS_TYPE} in
(${FS_TYPE_ISO9660})
FS_CHECK_CMD=''
FS_CHECK_ARGS=''
FS_MOUNT_CMD='mount'
FS_MOUNT_ARGS="-t cd9660 -e -C=${ISO9660_CODEPAGE} ${DEV} ${MNT}"
;;
(${FS_TYPE_UFS})
FS_CHECK_CMD='fsck_ufs'
FS_CHECK_ARGS="-C -y"
FS_MOUNT_CMD='mount'
FS_MOUNT_ARGS="-t ufs ${OPTS} ${DEV} ${MNT}"
;;
(${FS_TYPE_EXT2})
FS_CHECK_CMD='fsck.ext2'
FS_CHECK_ARGS="-y"
FS_MOUNT_CMD='mount'
FS_MOUNT_ARGS="-t ext2fs ${OPTS} ${DEV} ${MNT}"
;;
(${FS_TYPE_EXT3})
FS_CHECK_CMD='fsck.ext3'
FS_CHECK_ARGS="-y"
FS_MOUNT_CMD='mount'
FS_MOUNT_ARGS="-t ext2fs ${OPTS} ${DEV} ${MNT}"
;;
(${FS_TYPE_EXT4})
# sysutils/fusefs-ext4fuse
FS_CHECK_CMD='fsck.ext4'
FS_CHECK_ARGS="-y"
FS_MOUNT_CMD='ext4fuse'
FS_MOUNT_ARGS="${DEV} ${MNT}"
;;
(${FS_TYPE_XFS})
# sysutils/fusefs-lkl
FS_CHECK_CMD='xfs_repair'
FS_CHECK_ARGS="-d"
FS_MOUNT_CMD='lklfuse'
FS_MOUNT_ARGS="-o type=xfs -o allow_other -o uid=${UID} -o gid=${GID} ${DEV} ${MNT}"
;;
(${FS_TYPE_HFS})
# sysutils/fusefs-hfsfuse
FS_CHECK_CMD=''
FS_CHECK_ARGS=''
FS_MOUNT_CMD='hfsfuse'
FS_MOUNT_ARGS="--force ${OPTS} ${DEV} ${MNT}"
;;
(${FS_TYPE_FAT})
# FreeBSD 12.x does not support '-o large' option
case $( sysctl -n kern.osrelease ) in
(11*) LARGE="-o large" ;;
(*) LARGE="" ;;
esac
FS_CHECK_CMD='fsck_msdosfs'
FS_CHECK_ARGS="-C -y"
FS_MOUNT_CMD='mount_msdosfs'
FS_MOUNT_ARGS="-o longnames -m 644 -M ${MNT_MODE} -D ${FAT_CODEPAGE} -L ${FAT_ENCODING} -u ${UID} -g ${GID} ${OPTS} ${LARGE} ${DEV} ${MNT}"
;;
(${FS_TYPE_EXFAT})
# sysutils/fusefs-exfat
FS_CHECK_CMD='fsck.exfat'
FS_CHECK_ARGS="-y"
FS_MOUNT_CMD='mount.exfat'
FS_MOUNT_ARGS="-o uid=${UID} -o gid=${GID} -o dmask=022 -o fmask=133 ${OPTS} ${DEV} ${MNT}"
;;
(${FS_TYPE_NTFS})
# sysutils/fusefs-ntfs
FS_CHECK_CMD=''
FS_CHECK_ARGS=''
if /usr/bin/which -s ntfs-3g
then
FS_MOUNT_CMD='ntfs-3g'
FS_MOUNT_ARGS="-o recover ${OPTS} ${DEV} ${MNT}"
else
FS_MOUNT_CMD='mount_ntfs'
FS_MOUNT_ARGS="-u root -g ${MNT_GROUP} ${OPTS} ${DEV} ${MNT}"
fi
;;
(${FS_TYPE_MTP})
# sysutils/fusefs-simple-mtpfs
FS_CHECK_CMD=''
FS_CHECK_ARGS=''
FS_MOUNT_CMD='simple-mtpfs'
if ! /usr/bin/which -s "${FS_MOUNT_CMD}"
then
__log "command '${FS_MOUNT_CMD}' not found"
exit 1
fi 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 ) PHONEDEV=$( simple-mtpfs --list-devices -d ${DEV} 2>&1 )
if [ "${PHONEDEV}" = "No raw devices found." ] if [ "${PHONEDEV}" = "No raw devices found." ]
then then
__log "${DEV}: no raw devices found" __log "${DEV}: no raw devices found"
exit 0 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
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 fi
PHONEDEV=$( echo "${PHONEDEV}" | awk '{print $1}' | tr -d ':' )
FS_MOUNT_ARGS="--device ${PHONEDEV} ${MNT} -o allow_other -o intr -o big_writes -o uid=${UID} -o gid=${GID}"
;; ;;
(*)
(detach) __log "${DEV}: filesystem not supported or no filesystem"
__log "${DEV}: detach" exit 0
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
# create mount point
mkdir -m "${MNT_MODE}" -p "${MNT}"
__log "${DEV}: create '${MNT}' dir"
# check file system before mount
if [ -n "${FS_CHECK_CMD}" ]
then
if ! /usr/bin/which -s "${FS_CHECK_CMD}"
then
__log "command '${FS_CHECK_CMD}' not found"
exit 1
fi
${FS_CHECK_CMD} ${FS_CHECK_ARGS} ${DEV} \
| while read LINE
do
__log "${DEV}: ${FS_CHECK_CMD} ${LINE}"
done
fi
# try to mount
if ! /usr/bin/which -s "${FS_MOUNT_CMD}"
then
__log "command '${FS_MOUNT_CMD}' not found"
exit 1
fi
__wait_for_device "${DEV}"
COUNT=0
while ! ${FS_MOUNT_CMD} ${FS_MOUNT_ARGS}
do
if [ ! -e "${DEV}" ]
then
__log "${DEV}: device gone"
exit 1
fi
COUNT=$(( ${COUNT} + 1 ))
if [ ${COUNT} -gt ${RETRY_COUNT} ]
then
__log "${DEV}: mount FAIL: '${FS_MOUNT_CMD} ${FS_MOUNT_ARGS}'"
exit 1
fi
sleep "${RETRY_DELAY}"
__log "${DEV}: filesystem mount retry: ${COUNT}/${RETRY_COUNT}"
done
__log "${DEV}: mount OK: '${FS_MOUNT_CMD} ${FS_MOUNT_ARGS}'"
# add needed rights
chown "${USER}:${MNT_GROUP}" "${MNT}"
__log "${DEV}: chown '${MNT}' dir with '${USER}:${MNT_GROUP}' rights"
# add state
PROVIDER=$( mount | grep -m 1 " ${MNT} " | awk '{printf $1}' )
__state_add ${DEV} ${PROVIDER} ${MNT}
# open file manager and display message
__show_message "Device '${DEV}' mounted on '${MNT}' directory."
if [ -n "${FM}" ]
then
GROUP_USERS=$( pw group show ${MNT_GROUP} | sed -e 's|.*:||' -e 's|,| |g' )
for I in ${GROUP_USERS}
do
DISPLAY_ID=$( ps aew -U "${I}" | grep -v Xorg | sed -n 's|.*DISPLAY=\([-_a-zA-Z0-9:.]*\).*|\1|p' | sort -u | head -n 1 | tr -cd '[:print:]' )
if [ -z "${DISPLAY_ID}" ]
then
continue
fi
su -l "${I}" -c "env DISPLAY=${DISPLAY_ID} ${FM} ${MNT} &" 1> /dev/null 2>&1
done
fi
;; ;;
(da*|mmcsd*) (detach)
case ${2} in __log "${DEV}: detach"
if [ -f ${STATE} ]
(attach) then
__log "${DEV}: attach" grep -E "${MNT_PREFIX}/${1}$" ${STATE} \
if [ "${BLACKLIST}" != "" ] | while read DEV PROVIDER MNT
then
__log "${DEV}: using BLACKLIST='${BLACKLIST}'"
for I in ${BLACKLIST}
do do
if [ ${1} = "${I}" ] TARGET=$( mount | grep -v \.gvfs | grep -m 1 -E "^${PROVIDER} " | awk '{print $3}' )
__state_remove ${MNT}
if [ -z ${TARGET} ]
then then
__log "${DEV}: device blocked by BLACKLIST option" continue
exit 0
fi fi
( # put entire umount/find/rm block into background
umount -f "${TARGET}" 1> /dev/null 2>&1
__remove_dir "${TARGET}"
__log "${DEV}: (state) umount '${TARGET}'"
__log "${DEV}: (state) mount point '${TARGET}' removed"
) &
unset TARGET
done done
fi umount -f "${MNT_PREFIX}/${1}" 1> /dev/null 2>&1
ADD=0 __log "${DEV}: (direct) umount '${MNT_PREFIX}/${1}'"
MNT="${MNTPREFIX}/${1}" __remove_dir "${MNT_PREFIX}/${1}"
__check_already_mounted -d ${DEV} __log "${DEV}: (direct) mount point '${MNT_PREFIX}/${1}' removed"
__check_already_mounted -m ${MNT} __show_message "Device '${DEV}' unmounted from '${MNT}' directory."
if [ "${ATIME}" = NO ] fi
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}
fsck.ext2 -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}
fsck.ext3 -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}
fsck.ext4 -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}
fsck.exfat ${DEV} \
| while read LINE
do
__log "${DEV}: fsck.exfat ${LINE}"
done
__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
umount -f "${MNTPREFIX}/${1}"
__remove_dir "${MNTPREFIX}/${1}"
__log "${DEV}: mount point '${MNTPREFIX}/${1}' removed"
fi
;;
esac
;; ;;
esac esac

BIN
automount-1.7.0.tar.gz Normal file

Binary file not shown.

View File

@ -1,7 +1,10 @@
USERUMOUNT=YES USERUMOUNT=YES
ATIME=NO ATIME=NO
REMOVEDIRS=YES REMOVEDIRS=YES
FM="caja --browser --no-desktop" FM="caja --no-desktop"
USER=vermaden USER=vermaden
ENCODING=pl_PL.ISO8859-2 FAT_ENCODING=pl_PL.UTF-8
CODEPAGE=cp852 FAT_CODEPAGE=cp852
ISO9660_CODEPAGE=UTF-8

View File

@ -1,14 +1,45 @@
# PENDRIVE/PHONE/SDCARD insert
notify 100 { notify 100 {
match "system" "DEVFS"; match "system" "DEVFS";
match "type" "CREATE"; match "type" "CREATE";
match "cdev" "(ugen|da|mmcsd)[0-9]+.*"; match "cdev" "(da|mmcsd|ugen)[0-9]+.*";
action "/usr/local/sbin/automount $cdev attach"; action "/usr/local/sbin/automount $cdev attach &";
}; };
# PENDRIVE/PHONE/SDCARD remove
notify 100 { notify 100 {
match "system" "DEVFS"; match "system" "DEVFS";
match "type" "DESTROY"; match "type" "DESTROY";
match "cdev" "(ugen|da|mmcsd)[0-9]+.*"; match "cdev" "(da|mmcsd|ugen)[0-9]+.*";
action "/usr/local/sbin/automount $cdev detach"; action "/usr/local/sbin/automount $cdev detach &";
};
# CD-ROM media inject
notify 100 {
match "system" "DEVFS";
match "type" "CREATE|MEDIACHANGE";
match "cdev" "(cd)[0-9]+.*";
action "/usr/local/sbin/automount $cdev attach &";
};
# CD-ROM media eject
notify 100 {
match "system" "DEVFS";
match "type" "DESTROY";
match "cdev" "(cd)[0-9]+.*";
action "/usr/local/sbin/automount $cdev detach &";
};
# CD-ROM no media
notify 100 {
match "system" "CAM";
match "subsystem" "periph";
match "type" "error";
match "cam_status" "0xcc";
match "scsi_status" "2";
match "scsi_sense" "70 02 3a 02";
match "device" "(cd)[0-9]+.*";
action "/usr/local/sbin/automount $device detach &";
}; };