From 438ea3818e551807ca1adb3de298cba1dd3487b6 Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Wed, 10 Jul 2024 09:56:14 +0200 Subject: [PATCH] board/common: add support for auto-mounting USB sticks Fixes #497 Signed-off-by: Joachim Wiberg --- board/common/rootfs/etc/fstab | 1 + .../etc/udev/rules.d/90-media-mount.rules | 5 + board/common/rootfs/libexec/infix/media | 107 ++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 board/common/rootfs/etc/udev/rules.d/90-media-mount.rules create mode 100755 board/common/rootfs/libexec/infix/media diff --git a/board/common/rootfs/etc/fstab b/board/common/rootfs/etc/fstab index e94fdcf3..502c1865 100644 --- a/board/common/rootfs/etc/fstab +++ b/board/common/rootfs/etc/fstab @@ -7,6 +7,7 @@ tmpfs /dev/shm tmpfs mode=0777 0 0 proc /proc proc defaults 0 0 tmpfs /tmp tmpfs mode=1777,nosuid,nodev 0 0 tmpfs /run tmpfs mode=0755,nosuid,nodev 0 0 +tmpfs /media tmpfs mode=1755,nosuid,nodev 0 0 sysfs /sys sysfs defaults 0 0 debugfs /sys/kernel/debug debugfs nofail 0 0 cfgfs /config configfs nofail,noauto 0 0 diff --git a/board/common/rootfs/etc/udev/rules.d/90-media-mount.rules b/board/common/rootfs/etc/udev/rules.d/90-media-mount.rules new file mode 100644 index 00000000..b387daf7 --- /dev/null +++ b/board/common/rootfs/etc/udev/rules.d/90-media-mount.rules @@ -0,0 +1,5 @@ +KERNEL=="sd[a-z]", SUBSYSTEMS=="usb", ACTION=="add|change", RUN+="/libexec/infix/media add %k" +KERNEL=="sd[a-z]", SUBSYSTEMS=="usb", ACTION=="remove", RUN+="/libexec/infix/media del %k" + +KERNEL=="sd[a-z][0-9]", SUBSYSTEMS=="usb", ACTION=="add|change", RUN+="/libexec/infix/media add %k" +KERNEL=="sd[a-z][0-9]", SUBSYSTEMS=="usb", ACTION=="remove", RUN+="/libexec/infix/media del %k" diff --git a/board/common/rootfs/libexec/infix/media b/board/common/rootfs/libexec/infix/media new file mode 100755 index 00000000..528ed1b2 --- /dev/null +++ b/board/common/rootfs/libexec/infix/media @@ -0,0 +1,107 @@ +#!/bin/sh +# Mounts and unmounts external media + +ACTION=$1 +DEVBASE=$2 +DEVICE="/dev/${DEVBASE}" + +log() +{ + logger -sk -I $$ -p user.notice -t "media" "$1" +} + +usage() +{ + echo "Usage: $0 {add|start|del|remove|stop} DEV (e.g. sdb1)" + exit 1 +} + +if [ $# -ne 2 ]; then + usage +fi + +# See if this drive is already mounted, and if so where +MOUNT_POINT=$(mount | grep "${DEVICE}" | awk '{ print $3 }') + +do_mount() +{ + if [ -n "${MOUNT_POINT}" ]; then + log "skipping ${DEVICE}, already mounted at ${MOUNT_POINT}" + exit 1 + fi + + # Get info for this drive: $ID_FS_LABEL, $ID_FS_UUID, and $ID_FS_TYPE + eval $(udevadm info --query=property --name="${DEVICE}") + + # Figure out a mount point to use + LABEL=${ID_FS_LABEL} + if [ -z "${LABEL}" ]; then + LABEL=${DEVBASE} + elif grep -q " /media/${LABEL} " /etc/mtab; then + # Already in use, make a unique one + LABEL="${LABEL}-${DEVBASE}" + fi + MOUNT_POINT="/media/${LABEL}" + + umask 007 + mkdir -p "${MOUNT_POINT}" + + OPTS="rw,relatime,noexec,nodev,uid=0,gid=10" + case ${ID_FS_TYPE} in + vfat) + OPTS="${OPTS},umask=007,shortname=mixed,utf8=1,flush" + ;; + exfat) + OPTS="${OPTS},sync" + ;; + *) + log "unsupported filesystem ${ID_FS_TYPE}, skipping." + rmdir "${MOUNT_POINT}" + exit 1 + ;; + esac + + log "mount -o ${OPTS} ${DEVICE} ${MOUNT_POINT}" + if ! mount -t "${ID_FS_TYPE}" -o ${OPTS} "${DEVICE}" "${MOUNT_POINT}"; then + log "failed mounting ${DEVICE}" + rmdir "${MOUNT_POINT}" + exit 1 + fi + + log "mounted ${DEVICE} at ${MOUNT_POINT} for root:wheel with 770 permissions" +} + +do_unmount() +{ + if [ -z "${MOUNT_POINT}" ]; then + log "cannot unmount ${DEVICE}, is not mounted." + else + umount -l "${DEVICE}" + log "unmounted ${DEVICE}" + fi + + # Delete all empty dirs in /media that aren't being used as mount + # points. This is kind of overkill, but if the drive was unmounted + # prior to removal we no longer know its mount point, and we don't + # want to leave it orphaned... + for f in /media/* ; do + if [ -n "$(find "$f" -maxdepth 0 -type d -empty)" ]; then + if ! grep -q " $f " /etc/mtab; then + log "removing mount point $f" + rmdir "$f" + fi + fi + done +} + +case "${ACTION}" in + add|start) + do_mount + ;; + del|remove|stop) + do_unmount + ;; + *) + usage + ;; +esac