#!/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-14 add floppy disk support
# 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
}

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 _type
   # _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|ID_TYPE)=' )"
   unset ID_FS_TYPE ID_MODEL ID_VENDOR ID_FS_LABEL ID_CDROM_MEDIA_TRACK_COUNT_AUDIO ID_FS_VERSION ID_TYPE
   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}"
   _type="${ID_TYPE}"
   test -n "${DEBUG}" && echo "fs=${_fs} model=${_model} vendor=${_vendor} label=${_label} atracks=${_atracks} _type=${_type}" 1>&2
   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;" )"
   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})"
      if test "${_type}" = "floppy" ;
      then
         echo "Icon=system-floppy"
      else
         case "${_fs}" in
            "cd9600") echo "Icon=media-optical" ;;
            "udf") echo "Icon=media-optical-dvd" ;;
            "") echo "Icon=media-optical-audio" ;;
            *) echo "Icon=media-removable" ;;
         esac
      fi
   } > "${_filepath}"
}

# 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
