#!/bin/sh # File: /usr/bin/myautomountd # Location: gitlab # Authors: beanpole135, bgstack15 # Startdate: 2020-09-23 # SPDX-License-Identifier: CC-BY-SA-4.0 # Title: Automount in Shell # Purpose: # History: # 2020-09-23 originally translated by bgstack15 to shell from Go version (reference 1) # 2020-09-25 diverged from original architecture # 2023-10-04 add fs_type to path to make autofs work with exact fs type # 2023-10-05 ATTEMPTED TO ADD lvm autofs support, but STOPPED because autofs does not support lvm. # Usage: # Invoke this at X startup. This can be from the xdg autostart mechanism, or "exec myautomountd &" in ~/fluxbox.startup # This is the backend to myautomount-trayicon # Reference: # https://github.com/project-trident/trident-utilities/blob/master/src-go/automount/main.go # Improve: # Dependencies: # udevadm (from systemd-udev or eudev) # dep-devuan: eudev # FUNCTIONS clean_automount() { rm -f "${AUTOMOUNT_TMPFILE}" kill "${AUTOMOUNT_PID}" } reset_tmpfile() { cat /dev/null > "${AUTOMOUNT_TMPFILE}" } handleEvent() { # call: handleEvent "${STRING}" _line="${1}" test -n "${STACKTRACE}" && echo "handleEvent \"${_line}\"" 1>&2 echo "${_line}" | grep -qvE "^UDEV" && return # not a valid entry - possibly a startup message test $( echo "${_line}" | wc -w ) -ne 5 && return _deviceid= _eventType= for word in ${_line} ; do # no opportunity for the bash for statement to read a blank value here from unquoted variable if echo "${word}" | grep -qE '^(add|remove|change)$' ; then _eventType="${word}" elif echo "${word}" | grep -qE "^\/devices\/" ; then _deviceid="$( echo "${word}" | awk -F'/' '{print $NF}' )" fi done { test "${_deviceid}" = "" || test "${_eventType}" = "" ; } && return test -n "${VERBOSE}" || test -n "${DEBUG}" && echo "Got device event: ${_eventType} ${_deviceid}" 1>&2 _entry="${AUTOMOUNT_BASEDIR}/${_deviceid}.desktop" case "${_eventType}" in "add") createEntry "${_deviceid}" "${_entry}" ;; *) # anything else test -e "${_entry}" && { rm "${_entry}" || : ; } test "${_eventType}" = "change" && createEntry "${_deviceid}" "${_entry}" ;; esac } createEntryFile() { # set these beforehand: _filepath, _device, AUTOMOUNT_BROWSEDIR, _use_fs, _label, _vendor, _model, _fs touch "${_filepath}" ; chmod 0755 "${_filepath}" { echo "[Desktop Entry]" echo "Version=1.1" if test "${_fs}" = "udf" ; then echo "Type=Application" echo "Exec=xdg-open dvd:///dev/${_device}" elif test -n "${_atracks}" ; then test -n "${_label}" && _label="Audio CD" echo "Type=Application" echo "Exec=xdg-open cdda:///dev/${_device}" else echo "Type=Application" echo "Exec=xdg-open ${AUTOMOUNT_BROWSEDIR}${_use_fs}${_device}" echo "Path=${AUTOMOUNT_BROWSEDIR}${_use_fs}${_device}" fi if test -z "${_label}" ; then echo "Name=${_vendor} ${_model}" else echo "Name=${_label}" echo "GenericName=${_vendor} ${_model}" fi echo "Comment=${_device} (${_fs})" case "${_fs}" in "cd9600") echo "Icon=media-optical" ;; "udf") echo "Icon=media-optical-dvd" ;; "") echo "Icon=media-optical-audio" ;; *) echo "Icon=media-removable" ;; esac } > "${_filepath}" } createEntry() { # call: createEntry "{device}" "${filepath}" _device="${1}" _filepath="${2}" test -n "${STACKTRACE}" && echo "STUB createEntry \"${_device}\" \"${_filepath}\"" 1>&2 unset _fs _model _vendor _label _atracks _fs_version _use_fs _vg _lvs _use_lvs=0 # _use_fs simplifies the mount types a little _bytes="$( udevadm info "/dev/${_device}" 2>/dev/null )" _shortbytes="$( printf "%s\n" "${_bytes}" | sed -r -e 's/^E:\s*//;' | grep -E '^(ID_FS_TYPE|ID_MODEL|ID_VENDOR|ID_FS_LABEL|ID_CDROM_MEDIA_TRACK_COUNT_AUDIO|ID_FS_VERSION)=' )" unset ID_FS_TYPE ID_MODEL ID_VENDOR ID_FS_LABEL ID_CDROM_MEDIA_TRACK_COUNT_AUDIO ID_FS_VERSION eval "${_shortbytes}" _fs="${ID_FS_TYPE}" _fs_version="${ID_FS_VERSION}" _model="${ID_MODEL}" _vendor="${ID_VENDOR}" _label="${ID_FS_LABEL}" _atracks="${ID_CDROM_MEDIA_TRACK_COUNT_AUDIO}" test -n "${DEBUG}" && echo "fs=${_fs} model=${_model} vendor=${_vendor} label=${_label} atracks=${_atracks}" 1>&2 # if lvm, then get all the way down to the logical volume mount point type test "${_fs}" = "LVM2_member" && { _use_lvs=1 _vg="$( sudo pvs "/dev/${_device}" --noheadings -o-pv_name,pv_fmt,pv_attr,pv_size,pv_free,vg_name -o+vg_name | xargs )" _lvs="$( sudo lvs "${_vg}" --noheadings -o-vg_name,lv_attr,lv_size,pool_lv,origin,data_percent,metadata_percent,copy_percent,move_pv,mirror_log,convert_lv,lv_name -o+lv_name | xargs )" } test "${_fs}" = "" && test "${_atracks}" = "" && return # if the fs cannot be detected test "${_fs}" = "vfat" && test "${_fs_version}" = "FAT32" && _use_fs="fat32" case "${_fs}" in ntfs|ext4) _use_fs="${_fs}" ;; esac _use_fs="$( echo "/${_use_fs%%/}/" | sed -r -e "s@\/\/@\/@g;" )" if test "${_use_lvs}" = "1" ; then for _thislv in ${_lvs} ; do # get fs type: _device="${_vg}/${_thislv}" _lv_info="$( sudo wipefs "/dev/${_device}" --noheadings --parsable --output TYPE,LABEL )" _fs="$( echo "${_lv_info}" | awk -F',' '{print $1}' )" _label="$( echo "${_lv_info}" | awk -F',' '{print $2}' )" test "${_fs}" = "vfat" && test "${_fs_version}" = "FAT32" && _use_fs="fat32" case "${_fs}" in ntfs|ext4) _use_fs="${_fs}" ;; esac _use_fs="$( echo "/${_use_fs%%/}/" | sed -r -e "s@\/\/@\/@g;" )" createEntryFile done else # not lvm, so regular createEntryFile fi } # INITIALIZE test -z "${UID}" && export UID="$( $( which id ) -u "${USER}" )" . ${MYA_PREFIX}/etc/myautomount.conf trap '__ec=$? ; clean_automount ; trap "" 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 18 19 20 ; exit ${__ec} ;' 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 18 19 20 mkdir -p "${AUTOMOUNT_BASEDIR}" # run initialization script as root $( which sudo 2>/dev/null ) AUTOMOUNT_USER="${USER}" /usr/libexec/myautomount/myautomount-initialize.sh _response="${?}" ; test ${_response} -ne 0 && exit ${_response} # MAIN # start udevadm udevadm monitor -u -s block 1> "${AUTOMOUNT_TMPFILE}" & export AUTOMOUNT_PID="${!}" test -n "${DEBUG}" && env | grep -E '^AUTOMOUNT_' 1>&2 while ! test -e /tmp/kill-myautomount ; do tail -F "${AUTOMOUNT_TMPFILE}" 2>/dev/null | while read line ; do handleEvent "${line}" _length="$( wc -l < "${AUTOMOUNT_TMPFILE}" 2>/dev/null )" ; test -z "${_length}" && _length=0 test "${line}" = "$( tail -n1 "${AUTOMOUNT_TMPFILE}" )" && test ${_length} -gt 200 && reset_tmpfile done # the tail finished for some reason, so clear the file reset_tmpfile done