diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..528a570 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = tab +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..741518f --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# Swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ diff --git a/debian/control b/debian/control index 68ea40a..3bc0d13 100644 --- a/debian/control +++ b/debian/control @@ -12,7 +12,9 @@ Homepage: http://github.com/rbrito/usbmount Package: usbmount Architecture: all Depends: + util-linux, lockfile-progs, + systemd, udev, ${misc:Depends} Recommends: diff --git a/usbmount b/usbmount index f3ba6b7..fb5fd24 100755 --- a/usbmount +++ b/usbmount @@ -22,9 +22,9 @@ exec > /dev/null 2>&1 # Log a string via the syslog facility. log() { - if [ $1 != debug ] || expr "$VERBOSE" : "[yY]" > /dev/null; then - logger -p user.$1 -t "usbmount[$$]" -- "$2" - fi + if [ "${1}" != "debug" ] || expr "${VERBOSE}" : "[yY]" > /dev/null; then + logger -p "user.${1}" -t "usbmount[$$]" -- "${2}" + fi } @@ -32,10 +32,10 @@ log() # parameter. in_list() { - for v in $2; do - [ "$1" != "$v" ] || return 0 - done - return 1 + for v in ${2}; do + [ "${1}" != "${v}" ] || return 0 + done + return 1 } @@ -48,167 +48,174 @@ MOUNTPOINTS= FILESYSTEMS= MOUNTOPTIONS= FS_MOUNTOPTIONS= -VERBOSE=no +VERBOSE="no" + +BLKID="/sbin/blkid" +UDEVADM="/bin/udevadm" +USBMOUNT_CONF="/etc/usbmount/usbmount.conf" +USBMOUNT_VAR="/var/run/usbmount/" -if [ -r /etc/usbmount/usbmount.conf ]; then - . /etc/usbmount/usbmount.conf - log debug "loaded usbmount configurations" +if [ -r "${USBMOUNT_CONF}" ]; then + # shellcheck source=usbmount.conf + . "${USBMOUNT_CONF}" + log debug "loaded usbmount configurations" fi if [ "${ENABLED:-1}" -eq 0 ]; then - log info "usbmount is disabled, see /etc/usbmount/usbmount.conf" - exit 0 + log info "usbmount is disabled, see ${USBMOUNT_CONF}" + exit 0 fi -if [ ! -x /sbin/blkid ]; then - log err "cannot execute /sbin/blkid" - exit 1 +if [ ! -x "${BLKID}" ]; then + log err "cannot execute '${BLKID}'" + exit 1 +fi + +if [ ! -x "${UDEVADM}" ]; then + log err "cannot execute '${UDEVADM}'" + exit 1 fi # Per Policy 9.3.2, directories under /var/run have to be created # after every reboot. -if [ ! -e /var/run/usbmount ]; then - mkdir -p /var/run/usbmount - log debug "creating /var/run/usbmount directory" +if [ ! -e "${USBMOUNT_VAR}" ]; then + mkdir -p "${USBMOUNT_VAR}" + log debug "creating ${USBMOUNT_VAR} directory" fi umask 022 -if [ "$1" = add ]; then +if [ "${1}" = "add" ]; then - # Acquire lock. - log debug "trying to acquire lock /var/run/usbmount/.mount.lock" - lockfile-create --retry 3 /var/run/usbmount/.mount || \ - { log err "cannot acquire lock /var/run/usbmount/.mount.lock"; exit 1; } - trap '( lockfile-remove /var/run/usbmount/.mount )' 0 - log debug "acquired lock /var/run/usbmount/.mount.lock" + # Acquire lock. + log debug "trying to acquire lock ${USBMOUNT_VAR}/.mount.lock" + lockfile-create --retry 3 "${USBMOUNT_VAR}/.mount" || \ + { log err "cannot acquire lock ${USBMOUNT_VAR}/.mount.lock"; exit 1; } + trap '( lockfile-remove "${USBMOUNT_VAR}/.mount" )' 0 + log debug "acquired lock ${USBMOUNT_VAR}/.mount.lock" - # Query udev for the expected device information (as we are now running in - # a service's context and the env variables have been lost) - eval $(udevadm info --query=env --export "$DEVNAME" | grep -v '^[^=]*\..*=') + # Query udev for the expected device information (as we are now running in + # a service's context and the env variables have been lost) + eval $("${UDEVADM}" info --query=env --export "${DEVNAME}") - # Grab device information from device and "divide it" - # FIXME: improvement: implement mounting by label (notice that labels - # can contain spaces, which makes things a little bit less comfortable). - DEVINFO=$(/sbin/blkid -p $DEVNAME) - FSTYPE=$(echo "$DEVINFO" | sed 's/.*[[:blank:]]TYPE="\([^"]*\)".*/\1/g; s/[[:blank:]]*//g;') - UUID=$(echo "$DEVINFO" | sed 's/.*[[:blank:]]UUID="\([^"]*\)".*/\1/g; s/[[:blank:]]*//g;') - USAGE=$(echo "$DEVINFO" | sed 's/.*[[:blank:]]USAGE="\([^"]*\)".*/\1/g; s/[[:blank:]]*//g;') + # Grab device information from device + # FIXME: improvement: implement mounting by label (notice that labels + # can contain spaces, which makes things a little bit less comfortable). + eval "$("${BLKID}" -o value -p -s TYPE -s USAGE -s UUID "${DEVNAME}")" - if ! echo $USAGE | egrep -q "(filesystem|disklabel)"; then - log info "$DEVNAME does not contain a filesystem or disklabel" - exit 0 - fi - - # Try to use specifications in /etc/fstab first. - if egrep -q "^[[:blank:]]*$DEVNAME" /etc/fstab; then - log info "executing command: mount $DEVNAME" - mount $DEVNAME || log err "mount by DEVNAME with $DEVNAME wasn't successful; return code $?" - - elif grep -q "^[[:blank:]]*UUID=\"?$UUID\"?" /etc/fstab; then - log info "executing command: mount -U $UUID" - mount -U $UUID || log err "mount by UUID with $UUID wasn't successful; return code $?" - - else - log debug "$DEVNAME contains filesystem type $FSTYPE" - - fstype=$FSTYPE - # Test if the filesystem type is in the list of filesystem - # types to mount. - if in_list "$fstype" "$FILESYSTEMS"; then - # Search an available mountpoint. - for v in $MOUNTPOINTS; do - if [ -d "$v" ] && ! grep -q "^[^ ][^ ]* *$v " /proc/mounts; then - mountpoint="$v" - log debug "mountpoint $mountpoint is available for $DEVNAME" - break - fi - done - if [ -n "$mountpoint" ]; then - # Determine mount options. - options= - for v in $FS_MOUNTOPTIONS; do - if expr "$v" : "-fstype=$fstype,."; then - options="$(echo "$v" | sed 's/^[^,]*,//')" - break - fi - done - if [ -n "$MOUNTOPTIONS" ]; then - options="$MOUNTOPTIONS${options:+,$options}" - fi + if [ "${USAGE}" != "filesystem" ] && [ "${USAGE}" != "disklabel" ]; then + log info "${DEVNAME} does not contain a filesystem or disklabel" + exit 0 + fi - # Mount the filesystem. - log info "executing command: mount -t$fstype ${options:+-o$options} $DEVNAME $mountpoint" - mount "-t$fstype" "${options:+-o$options}" "$DEVNAME" "$mountpoint" - - # Determine vendor and model. - vendor= - if [ -r "/sys$DEVPATH/device/vendor" ]; then - vendor="`cat \"/sys$DEVPATH/device/vendor\"`" - elif [ -r "/sys$DEVPATH/../device/vendor" ]; then - vendor="`cat \"/sys$DEVPATH/../device/vendor\"`" - elif [ -r "/sys$DEVPATH/device/../manufacturer" ]; then - vendor="`cat \"/sys$DEVPATH/device/../manufacturer\"`" - elif [ -r "/sys$DEVPATH/../device/../manufacturer" ]; then - vendor="`cat \"/sys$DEVPATH/../device/../manufacturer\"`" - fi - vendor="$(echo "$vendor" | sed 's/^[[:blank:]]\+//; s/[[:blank:]]\+$//')" - - model= - if [ -r "/sys$DEVPATH/device/model" ]; then - model="`cat \"/sys$DEVPATH/device/model\"`" - elif [ -r "/sys$DEVPATH/../device/model" ]; then - model="`cat \"/sys$DEVPATH/../device/model\"`" - elif [ -r "/sys$DEVPATH/device/../product" ]; then - model="`cat \"/sys$DEVPATH/device/../product\"`" - elif [ -r "/sys$DEVPATH/../device/../product" ]; then - model="`cat \"/sys$DEVPATH/../device/../product\"`" + # Try to use specifications in /etc/fstab first. + if grep -q -E "^[[:blank:]]*${DEVNAME}" "/etc/fstab"; then + log info "executing command: mount ${DEVNAME}" + mount "${DEVNAME}" || log err "mount by DEVNAME with ${DEVNAME} wasn't successful; return code ${?}" + elif grep -q -E "^[[:blank:]]*UUID=\"?${UUID}\"?" "/etc/fstab"; then + log info "executing command: mount -U ${UUID}" + mount -U "${UUID}" || log err "mount by UUID with ${UUID} wasn't successful; return code ${?}" + else + log debug "${DEVNAME} contains filesystem type ${TYPE}" + + fstype="${TYPE}" + # Test if the filesystem type is in the list of filesystem + # types to mount. + if in_list "${fstype}" "${FILESYSTEMS}"; then + # Search an available mountpoint. + for v in ${MOUNTPOINTS}; do + if [ -d "${v}" ] && ! mountpoint -q "${v}"; then + mountpoint="${v}" + log debug "mountpoint ${mountpoint} is available for ${DEVNAME}" + break + fi + done + if [ -n "${mountpoint}" ]; then + # Determine mount options. + options= + for v in ${FS_MOUNTOPTIONS}; do + if expr "${v}" : "-fstype=${fstype},."; then + options="$(echo "${v}" | sed 's/^[^,]*,//')" + break + fi + done + if [ -n "${MOUNTOPTIONS}" ]; then + options="${MOUNTOPTIONS}${options:+,${options}}" + fi + + # Mount the filesystem. + log info "executing command: mount -t${fstype} ${options:+-o${options}} ${DEVNAME} ${mountpoint}" + mount "-t${fstype}" "${options:+-o${options}}" "${DEVNAME}" "${mountpoint}" + + # Determine vendor and model. + vendor= + if [ -r "/sys${DEVPATH}/device/vendor" ]; then + vendor="$(cat \"/sys"${DEVPATH}"/device/vendor\")" + elif [ -r "/sys${DEVPATH}/../device/vendor" ]; then + vendor="$(cat \"/sys"${DEVPATH}"/../device/vendor\")" + elif [ -r "/sys${DEVPATH}/device/../manufacturer" ]; then + vendor="$(cat \"/sys"${DEVPATH}"/device/../manufacturer\")" + elif [ -r "/sys${DEVPATH}/../device/../manufacturer" ]; then + vendor="$(cat \"/sys"${DEVPATH}"/../device/../manufacturer\")" + fi + vendor="$(echo "${vendor}" | sed 's/^[[:blank:]]\+//; s/[[:blank:]]\+$//')" + + model= + if [ -r "/sys${DEVPATH}/device/model" ]; then + model="$(cat \"/sys"${DEVPATH}"/device/model\")" + elif [ -r "/sys${DEVPATH}/../device/model" ]; then + model="$(cat \"/sys"${DEVPATH}"/../device/model\")" + elif [ -r "/sys${DEVPATH}/device/../product" ]; then + model="$(cat \"/sys"${DEVPATH}"/device/../product\")" + elif [ -r "/sys${DEVPATH}/../device/../product" ]; then + model="$(cat \"/sys"${DEVPATH}"/../device/../product\")" + fi + model="$(echo "${model}" | sed 's/^[[:blank:]]\+//; s/[[:blank:]]\+$//')" + + # Run hook scripts; ignore errors. + export UM_DEVICE="${DEVNAME}" + export UM_MOUNTPOINT="${mountpoint}" + export UM_FILESYSTEM="${fstype}" + export UM_MOUNTOPTIONS="${options}" + export UM_VENDOR="${vendor}" + export UM_MODEL="${model}" + log info "executing command: run-parts /etc/usbmount/mount.d" + run-parts "/etc/usbmount/mount.d" || : + else + # No suitable mount point found. + log warning "no mountpoint found for ${DEVNAME}" + exit 1 + fi fi - model="$(echo "$model" | sed 's/^[[:blank:]]\+//; s/[[:blank:]]\+$//')" - - # Run hook scripts; ignore errors. - export UM_DEVICE="$DEVNAME" - export UM_MOUNTPOINT="$mountpoint" - export UM_FILESYSTEM="$fstype" - export UM_MOUNTOPTIONS="$options" - export UM_VENDOR="$vendor" - export UM_MODEL="$model" - log info "executing command: run-parts /etc/usbmount/mount.d" - run-parts /etc/usbmount/mount.d || : - else - # No suitable mount point found. - log warning "no mountpoint found for $DEVNAME" - exit 1 - fi fi - fi -elif [ "$1" = remove ]; then - - # A block or partition device has been removed. - # Test if it is mounted. - while read device mountpoint fstype remainder; do - if [ "$DEVNAME" = "$device" ]; then - # If the mountpoint and filesystem type are maintained by - # this script, unmount the filesystem. - if in_list "$mountpoint" "$MOUNTPOINTS" && - in_list "$fstype" "$FILESYSTEMS"; then - log info "executing command: umount -l $mountpoint" - umount -l "$mountpoint" - - # Run hook scripts; ignore errors. - export UM_DEVICE="$DEVNAME" - export UM_MOUNTPOINT="$mountpoint" - export UM_FILESYSTEM="$fstype" - log info "executing command: run-parts /etc/usbmount/umount.d" - run-parts /etc/usbmount/umount.d || : - fi - break - fi - done < /proc/mounts +elif [ "${1}" = "remove" ]; then + + # A block or partition device has been removed. + # Test if it is mounted. + while read -r device mountpoint fstype _; do + if [ "${DEVNAME}" = "${device}" ]; then + # If the mountpoint and filesystem type are maintained by + # this script, unmount the filesystem. + if in_list "${mountpoint}" "${MOUNTPOINTS}" && + in_list "${fstype}" "${FILESYSTEMS}"; then + log info "executing command: umount -l ${mountpoint}" + umount -l "${mountpoint}" + + # Run hook scripts; ignore errors. + export UM_DEVICE="${DEVNAME}" + export UM_MOUNTPOINT="${mountpoint}" + export UM_FILESYSTEM="${fstype}" + log info "executing command: run-parts /etc/usbmount/umount.d" + run-parts "/etc/usbmount/umount.d" || : + fi + break + fi + done < "/proc/mounts" else - log err "unexpected: action '$1'" - exit 1 + log err "unexpected: action '${1}'" + exit 1 fi log debug "usbmount execution finished" +exit 0 diff --git a/usbmount.conf b/usbmount.conf index 97f7ccc..c4f489f 100644 --- a/usbmount.conf +++ b/usbmount.conf @@ -50,4 +50,4 @@ FS_MOUNTOPTIONS="" # If set to "yes", more information will be logged via the syslog # facility. -VERBOSE=no +VERBOSE="no"