我正在尝试实现一个自定义函数,该函数在连接 USB 驱动器时扫描它包含的所有文件系统,然后根据检测到的文件系统类型执行操作。我走“推荐”的道路编写了一条udev
规则,该规则为设备节点触发了一个实例化的systemd
“oneshot”服务,该服务反过来执行“发挥所有魔力(TM)”的 shell 脚本(出于平台独立性的原因,编译程序在这里不被视为一个选项)。
ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", RUN{program}="/bin/systemctl start usb-drive-manager@$devnode.service"
和
[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/usr/local/bin/usb_drive_manager.sh attach %I
ExecStop=/usr/local/bin/usb_drive_manager.sh detach %I
在 shell 脚本中,我ls /sys/.../sdX/sdX*
在驱动器的设备路径上执行一个来定位任何分区,然后通过调用查询这些分区的信息
udevadm info /dev/sdXn
(其中n
是分区号)每个已处理的分区。
现在的问题udev
是,虽然这在 shell 脚本的“冷插拔”测试期间有效,但当从规则触发脚本时它不起作用,因为在处理驱动器udev
的事件时,有关驱动器上的分区的信息是内核尚未收集,即调用仅返回基本信息:udevadm info
P: /devices/.../block/sdb/sdb1
N: sdb1
E: DEVNAME=/dev/sdb1
E: DEVPATH=/devices/.../block/sdb/sdb1
E: DEVTYPE=partition
E: MAJOR=8
E: MINOR=17
E: SUBSYSTEM=block
以及所有相关信息,特别是ID_FS_TYPE
和ID_FS_LABEL
环境变量(仍然)缺失。udevadm settle
由于在处理事件时调用udev
是一个坏主意(也没有帮助),甚至 0.5 秒的轮询循环在调用之间休眠udevadm info
也不起作用(直到信息最终可用大约需要 1 分钟),我我在这里有点不知所措。
不幸的是,重写udev
规则以使其适用于分区而不是驱动器也是不可取的,因为在某些情况下,人们在整个 USB 设备上创建文件系统,而不是创建跨越整个设备的单个分区,然后包含文件系统。
现在的问题是是否
- 可以延迟
udev
对给定设备的规则处理,直到该设备的所有子设备都已处理完毕,或者 - 我可以在 shell 脚本中使用一个系统调用,它“等待”所有子事件(如果有的话!)在继续查询
udev
数据之前完成
我认为现在这是一个相当长的问题。非常感谢所有帮助。
在进行了一些研究后,我发现了
blkid
in udev规则的使用(参见例如这篇ArchLinux-Wiki 文章,不幸的是只有德语版本),我发现通过调用代替
在
systemd
-triggered 脚本中,甚至可以检索有关正在处理“添加”规则的 USB 记忆棒的子设备的完整信息。似乎
-p
这里的选项是关键,因为它切换到实际读出设备的主动探测模式,而不是依赖于缓存的信息(例如,参见手册页或 的源代码blkid
)。该
-o udev
选项仅用于以类似于udevadm
调用的方式格式化输出,尽管它不是 100% 的直接替换,因为此处缺少udevadm
输出的前导标识符标签(例如E:
、等)。P: