udev调用时mount不执行

udev调用时mount不执行

我尝试创建一些 udev 规则来挂载和卸载我的 USB 闪存驱动器;目前的规则非常简单:

ACTION=="add",KERNEL=="sd[b-z]",RUN+="/root/scripts/plug_flash_drive.sh %k"
ACTION=="remove",KERNEL=="sd[b-z]",RUN+="/root/scripts/unplug_flash_drive.sh %k"

Plug_flash_drive.sh也很简单:

device_name=$1
mount_options="umask=000,utf8"
if [ ! -e "/media/$device_name" ]; then
    mkdir "/media/$device_name"
fi
sleep 1
/usr/bin/mount "/dev/$device_name" "/media/$device_name" -o "$mount_options"

unplug_flash_drive.sh:

device_name=$1

umount "/dev/$device_name"
rmdir "/media/$device_name"

我做了一些测试,所以我可以确定:

  • 插入时,会检测到我的闪存驱动器;在 /dev 中创建一个文件
  • Plug_flash_drive.sh 由 udev 调用
  • 脚本的 mkdir 部分有效
  • 但是,似乎脚本的“安装”部分没有执行,所以我的驱动器没有安装
  • 当我在命令行上调用我的脚本时,它们完美地工作

有谁知道为什么 udev 调用 mount 时不执行?

编辑 28/08/14:我在脚本末尾添加了“grep -q /proc/mounts && echo success || echo failure”,以检查我的调试日志是否在脚本结束之前实际安装了设备。看来该设备即使 udev 调用该脚本,也会在此时安装。所以现在真正的问题是“通过 udev 调用时,在挂载脚本结束后,我的块设备似乎已被卸载”:s

答案1

systemd-udevd 在其自己的文件系统命名空间中运行,默认情况下,在 udev 中完成的挂载。规则不会传播到主机。要使旧脚本正常工作,您可以在以下位置设置MountFlags=shared/usr/lib/systemd/system/systemd-udevd.service(更好)创建和编辑其副本:/etc/systemd/system/

请参阅 参考资料,了解man 5 systemd.exec更多信息,MountFlags选项。

答案2

截至撰写本文时,其他答案不正确(或已过时)。

您不应该mount从 Systemd 服务运行。即使在注释了MountFlagsPrivateMounts中的行之后systemd-udevd.service,您的规则也不适用于 FUSE 文件系统(如 NTFS 或 exFAT),因为 FUSE 进程将被 Systemd 有效地杀死。

这个 ArchWiki 页面其中列出了几个更好的选择。我更喜欢 GitHub 上的一个小项目,名为udev 媒体自动挂载,它只是从 Udev 规则重新启动 Systemd 服务。这是绕过 Udev 对命名空间和子进程的各种繁琐限制的便捷方法。

也可以看看这个答案,它展示了如何使用SYSTEMD_WANTSUdev 变量来启动 Systemd 单元。

答案3

您可以使用systemd-mountudev 规则来挂载块设备。自动挂载 Raspberry Pi Pico 的示例源自ArchWiki 页面@Metamorphic 提到(请注意,您需要提前进行/mnt/pico

ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0003", RUN+="/usr/bin/logger --tag rpi-pico-mount Mounting what seems to be a Raspberry Pi Pico", RUN+="/usr/bin/systemd-mount --no-block --collect -o gid=users,fmask=113,dmask=002 $devnode /mnt/pico"

该帖子提到添加 flag --automount=yes,但这给我带来了重新安装问题。

确保重新加载 udev 规则,以便您的更改生效:

sudo udevadm control --reload

将消息添加logger到规则有助于调试。您可以通过观看看到它被打印出来journalctl -f。从通用匹配模式开始,然后构建更具体的匹配模式很有用。

答案4

您可以尝试在规则 RUN 分配中使用:=而不是使用。+=

操作:=员设置列表值并不允许进一步更改。

相关内容