从 udev 规则和 shell 脚本自动挂载 USB 驱动器

Auto mount usb drive from udev rules and shell script

我目前正在尝试自动安装连接到我的计算机的任何 USB 驱动器。 我的目标是挂载 usb 设备,如果有,则使用标签;如果没有,则使用 uuid。

为此,我在 /etc/udev/rules.d/10-usb-detect.rules 中编写了一个 udev 规则:

ACTION=="add", KERNEL=="sd?[0-9]", SUBSYSTEM=="block", RUN+="/usr/local/bin/add.sh"

每次在块子系统上追加添加事件时都会调用该脚本。

udev 规则工作正常,但是当我尝试从脚本挂载文件系统时它不起作用。 奇怪的是,脚本中的挂载命令总是 return $?=0,所以逻辑上应该挂载文件系统,但实际上没有挂载。

这是我的脚本:

#!/bin/bash

LOG_FILE=<path_to_file>

echo "New usb device detected at $DEVNAME" >> $LOG_FILE

echo "mount $DEVNAME /media/usb/test" >> $LOG_FILE

mount $DEVNAME /media/usb/test &>> $LOG_FILE

ret=$?
echo "$ret" >> $LOG_FILE

if [ $ret == "0" ]; then
    echo "$DEVNAME mounted at /media/usb/test"  >> $LOG_FILE
else
    echo "Failed to mount $DEVNAME at /media/usb/test"  >> $LOG_FILE
fi

echo "" >> $LOG_FILE

我尝试使用 /media/usb/test 不存在,并且我从 mount 命令中得到了预期的错误。 但是,当文件夹存在时,即使未安装文件系统,他也会安装命令 returns 0。

这是日志文件的输出:

New usb device detected at /dev/sdc1
mount /dev/sdc1 /media/usb/test
mount: mount point /media/usb/test does not exist
32
Failed to mount /dev/sdc1 at /media/usb/test

New usb device detected at /dev/sdc1
mount /dev/sdc1 /media/usb/test
0
/dev/sdc1 mounted at /media/usb/test

/dev/sdc1 即使 mount returns 0.

也没有挂载

我准确地说,当我从命令行挂载文件系统时,绝对没有问题,并且文件系统已按预期挂载。

有人知道我该如何调试吗?

我认为问题是因为脚本是从 udev 调用的,因为如果我从命令行调用它也可以。

如果您通过在命令中添加 -t FILESYSTEMTYPE 参数来指定文件系统类型,则系统类型问题可能会更好。 mount -t FILESYSTEMTYPE /device_name /mount_point.

同时尝试改变记录事件的方式,使用 exec 命令记录信息,无需每次都继续重定向命令输出。 exec > $LOG_FILE 2>&1

你也可以替换

mount $DEVNAME /media/usb/test &>> $LOG_FILE
ret=$?
echo "$ret" >> $LOG_FILE
if [ $ret == "0" ]; then
echo "$DEVNAME mounted at /media/usb/test"  >> $LOG_FILE
else
echo "Failed to mount $DEVNAME at /media/usb/test"  >> $LOG_FILE
fi

mount -t vfat $DEVNAME /media/usb/test
if [ $? -eq 0 ]; then
echo " $DEVNAME Mounted"
else
echo " $DEVNAME not Mounted"
fi

我不确定为什么即使您获得退出状态为成功,设备仍未安装。只是尝试优化代码以解决真正的问题。

我想我发现了问题所在。 显然,udev 使用特定的命名空间,实际上我可以通过打印 /proc/<daemon_pid>/mountinfo 的内容来查看挂载点,其中 systemd-udevd 服务的 pid 在哪里。

$ cat /proc/240/mountinfo
[...]
228 43 8:17 / /media/usb/test rw,relatime - vfat /dev/sdb1 rw,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro

$ df
Sys. de fichiers blocs de 1K  Utilisé Disponible Uti% Monté sur
udev                 1975740        0    1975740   0% /dev
tmpfs                 397376     5916     391460   2% /run
/dev/sda2           75733088 69473400    2389532  97% /
tmpfs                1986868   111860    1875008   6% /dev/shm
tmpfs                   5120        4       5116   1% /run/lock
tmpfs                1986868        0    1986868   0% /sys/fs/cgroup
tmpfs                 397372       28     397344   1% /run/user/112
tmpfs                 397372       24     397348   1% /run/user/1001

所以解决办法应该是强制udev在root用户空间执行脚本。 我尝试了在这里找到的解决方案 https://unix.stackexchange.com/questions/330094/udev-rule-to-mount-disk-does-not-work

但是,我的系统没有 /usr/lib/systemd/system/systemd-udevd.service 文件。我创建了一个文件 /etc/systemd/system/systemd-udevd.service,内容为

MountFlags=shared 

但是使用这个解决方案,我的系统无法再启动了。

有人知道我如何在 root 用户空间中执行脚本或与用户共享挂载点吗?

PS : 我准确地说我是 运行 64 位 Debian 9

已解决编辑: 最后文件位于 /lib/systemd/system/systemd-udevd.service。我在 /etc/systemd/system/systemd-udevd.service 中复制了它 并将 MountFlags=slave 更改为 MountFlags=shared,现在它完美运行了:)

我希望我的 Raspberrypi Pico 微控制器板能够自动安装和卸载,这与最初的问题非常相似,因为当您插入时按下 bootsel 按钮时,RPi Pico 被识别为 USB 存储。 所以这是我在 /lib/udev/rules.d/10-usb-storage.rules 中输入的内容(确切路径可能取决于分布)

root@darkstar:/lib/udev/rules.d# cat 10-usb-storage.rules
ACTION=="add", KERNEL=="sd?[0-9]", SUBSYSTEM=="block", RUN+="usb_automount"
ACTION=="remove", KERNEL=="sd?[0-9]", SUBSYSTEM=="block", RUN+="usb_automount"
root@darkstar:/lib/udev/rules.d#

这是名为的帮助脚本:

root@darkstar:/lib/udev/rules.d# cat /lib/udev/usb_automount
#!/bin/bash 
#this will automatically mount and umount th RPi Pico on /mnt/pico
Name=$(basename [=11=])
Logger="/usr/bin/logger -p local3.info -t $Name "
#logger -p local3.info -t aoutomount -- testing
Message="$* $DEVNAME $ACTION $ID_FS_LABEL"
$Logger <<< $Message

pico_add ()
{ Message="automounting  $DEVNAME $ID_FS_LABEL"
  $Logger <<< $Message
  /sbin/mount $DEVNAME /mnt/pico && $Logger <<< "mounted" || $Logger <<< "failed"
}

pico_remove ()
{ Message="umounting  $DEVNAME $ID_FS_LABEL"
  $Logger <<< $Message
  /sbin/umount -f /mnt/pico && $Logger <<< "umounted" || $LOGGER "failed"
}

case $ID_FS_LABEL in
  RPI-RP2) pico_$ACTION ;;
  *) $Logger <<< "$ID_FS_LABEL is not configured for any automatic action"
esac
root@darkstar:/lib/udev/rules.d#

要重新加载 udev 规则:https://unix.stackexchange.com/questions/39370/how-to-reload-udev-rules-without-reboot/39371

udevadm control --reload-rules && udevadm trigger

顺便说一句:udev 似乎忽略了 /etc/fstab

的内容