我尝试创建一些 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 服务运行。即使在注释了MountFlags
和PrivateMounts
中的行之后systemd-udevd.service
,您的规则也不适用于 FUSE 文件系统(如 NTFS 或 exFAT),因为 FUSE 进程将被 Systemd 有效地杀死。
看这个 ArchWiki 页面其中列出了几个更好的选择。我更喜欢 GitHub 上的一个小项目,名为udev 媒体自动挂载,它只是从 Udev 规则重新启动 Systemd 服务。这是绕过 Udev 对命名空间和子进程的各种繁琐限制的便捷方法。
也可以看看这个答案,它展示了如何使用SYSTEMD_WANTS
Udev 变量来启动 Systemd 单元。
答案3
您可以使用systemd-mount
udev 规则来挂载块设备。自动挂载 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 分配中使用:=
而不是使用。+=
操作:=
员设置列表值并不允许进一步更改。