aboutsummaryrefslogtreecommitdiff
path: root/src/usr/bin/myautomountd
blob: 1d9370d41dd72dc3febbc398d7bb6c7b2ae60cf6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#!/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
bgstack15