使用udev实现插入U盘自动挂载的一些记录

2019-06-10 遇到的一点小问题
新需求是在U盘插入设备时实现自动挂载功能,一般都是推荐使用udev。记录一下第一次使用出现的问题。
. 刚开始先按网上找的方法
,在/etc/udev/rules.d/创建个.rules文件,再根据插入动作调用.sh文件来执行mount操作:

KERNEL=="sd[a-z]*",ACTION=="add",RUN+="/srv/wannoo.sh %k"

语法挺简单的,就是容易遇坑:有一次KERNELACTION顺序弄反,然后就执行失败;还有一U盘只能读到sdd,所以KERNEL=="sd[a-z][1-9]"读不到,为了兼容只能改成KERNEL=="sd[a-z]"*;然后换行也要注意;还有就是一行命令数限制五个,多了后面的不生效。
不过虽然把语法弄懂了,但mount还是出错了:
mount: /tmp/sdc1: permission denied. echo $? == 32#分区不支持挂载是返回这个,随便输个地址也返回这个,服了。FUSE exfat 1.3.0#在命令行mount也有提示这句,返回值为0,能正常mount。 fusermount: mount failed: Operation not permitted echo $? ==1#这边多了上面那句返回,然后返回值是1,挂载失败。WARN: volume was not unmounted cleanly.#偶尔出现这句,可以忽略了。

. 测了几次,依然没有解决。只好再到ArchLinux的wiki上面仔细看看udev (简体中文)。按说明修改了/etc/systemd/system/systemd-udevd.service文件,也按要求把挂载动作放在 udev 规则内部,可惜测试了还是不行。也按这篇Auto-mounting USB storage with udev的示例试了一下,依旧失败返回fusermount: mount failed: Operation not permitted
KERNEL=="sd[a-z]*",ACTION=="add",RUN+="/bin/mkdir /tmp/%k",RUN+="bin/mount -r /dev/%k /tmp/%k"

. 因为udev (简体中文)写的翻译时间是2017-10-19,有点旧了,所以又仔细看了看udev英文文档。发现里面使用的示例不是bin/mount而是使用/usr/bin/systemd-mount去挂载。
ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem", RUN{program}+="/usr/bin/systemd-mount --no-block --automount=yes --collect $devnode /media"

在控制台试了下systemd-mount命令。
[root@archlinux ~]# /usr/bin/systemd-mount /dev/sdb2 /media/sdb2 Failed to start transient mount unit: Unit media-sdb2.mount already exists.#之前未卸载 # echo $? == 1 [root@archlinux ~]# systemd-mount -u /media/sdb2 Stopped unit media-sdb2.mount for mount point: /media/sdb2#卸载成功 # echo $? == 0 [root@archlinux ~]# systemd-mount /dev/sdb2 /media/sdb2 Started unit media-sdb2.mount for mount point: /media/sdb2#任务执行成功,不一定mount成功。 # echo $? == 0 [root@archlinux ~]# systemctl status media-sdb2.mount * media-sdb2.mount - /media/sdb2 Loaded: loaded (/run/systemd/transient/media-sdb2.mount; transient) Transient: yes Active: active (mounted) since Tue 2019-06-11 08:55:28 UTC; 32s ago Where: /media/sdb2 What: /dev/sdb2 Tasks: 1 (limit: 4915) Memory: 2.5M CGroup: /system.slice/media-sdb2.mount `-10153 /usr/bin/mount.exfat /dev/sdb2 /media/sdb2 -o rwJun 11 08:55:27 archlinux systemd[1]: Mounting /media/sdb2... Jun 11 08:55:28 archlinux systemd[1]: Mounted /media/sdb2. # echo $? == 0

测试中发现加上--automount=yes选项之后,如果使用umount 命令去卸载,df能看出成功,但是再cd进入之前挂载的文件夹又会自动挂载起来,所以卸载动作需要使用systemd-umount 命令systemd-mount -u 命令去卸载。
最后,在.rules文件里使用systemd-mount命令试一下挂载U盘。
ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", RUN{program}+="/bin/mkdir /media/%k" ,RUN{program}+="/usr/bin/systemd-mount --no-block --collect $devnode /media/%k"

有一个U盘成功了,但有一个U盘一直没看到挂载成功,所以又用控制台试了一下。
[root@archlinux ~]# /usr/bin/systemd-mount --no-block --collect /dev/sdb2 /media/sdb2 Started unit media-sdb2.mount for mount point: /media/sdb2#任务执行成功,不一定mount成功。 [root@archlinux ~]# systemd-mount /dev/sdb2 /media/sdb2 Job for media-sdb2.mount failed.#不使用--no-block选项能等到结果出现 See "systemctl status media-sdb2.mount" and "journalctl -xe" for details.#根据提示去看状态 [root@archlinux media]# systemctl status media-sdb2.mount * media-sdb2.mount - /media/sdb2 Loaded: loaded (/run/systemd/transient/media-sdb2.mount; transient) Transient: yes Active: failed (Result: exit-code) since Tue 2019-06-11 08:48:38 UTC; 5s ago Where: /media/sdb2 What: /dev/sdb2Jun 11 08:48:38 archlinux systemd[1]: Mounting /media/sdb2... Jun 11 08:48:38 archlinux mount[5851]: mount: /media/sdb2: unknown filesystem type 'exfat'. Jun 11 08:48:38 archlinux systemd[1]: media-sdb2.mount: Mount process exited, code=exited, status=32/n/a Jun 11 08:48:38 archlinux systemd[1]: media-sdb2.mount: Failed with result 'exit-code'. Jun 11 08:48:38 archlinux systemd[1]: Failed to mount /media/sdb2. [root@archlinux ~]# pacman -Sy exfat-utils ...#成功安装 exfat-utils

加上--no-block可以异步等待结果,但现在并不需要,所以去掉后重试。马上返回失败信息了,然后根据提示使用systemctl status media-sdb2.mount查看状态及记录,才知道是缺少exfat支持,这个问题之前在其他设备上monut时有遇到过,使用pacman -Sy exfat-utils安装后,重新拔插U盘再试了一次:
[root@archlinux media]# systemctl status media-sdb2.mount * media-sdb2.mount - /media/sdb2 Loaded: loaded (/run/systemd/transient/media-sdb2.mount; transient) Transient: yes Active: activating (mounting) since Tue 2019-06-11 08:50:36 UTC; 93ms ago Where: /media/sdb2 What: /dev/sdb2 Cntrl PID: 7177 (mount) Tasks: 2 (limit: 4915) Memory: 2.5M CGroup: /system.slice/media-sdb2.mount |-7177 /usr/bin/mount /dev/sdb2 /media/sdb2 `-7178 /usr/bin/mount.exfat /dev/sdb2 /media/sdb2 -o rwJun 11 08:50:36 archlinux systemd[1]: Mounting /media/sdb2... # echo $? == 3

不懂为什么返回值是3。使用df看了下,已经正常挂载了。先不理会。
. 网上随便搜了几篇文章参考,这边记录一下:
使用 udev 高效、动态地管理 Linux 设备文件
在 Linux 中如何编写基本的 udev 规则
An introduction to Udev: The Linux subsystem for managing device events
udev学习笔记汇总
关于udevadm命令,有用到几个先记录一下:
#实时监听U盘拔插,在控制台显示动态: udevadm monitor #模拟插拔动作: udevadm test --action="add" /devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.3/1-2.3:1.0/host3/target3:0:0/3:0:0:0/block/sdd #规则修改后,重载生效: udevadm control --reload

然后有几个会用到的位置也记一下:
/usr/lib/udev/rules.d#系统定义的规则 /etc/udev/rules.d/#自定义的规则 /usr/lib/systemd/system/systemd-udevd.service#系统定义的配置文件 /etc/systemd/system/systemd-udevd.service#将系统定义的配置文件复制过来修改

【使用udev实现插入U盘自动挂载的一些记录】https://wiki.archlinux.org/index.php/Udisks_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)

    推荐阅读