如果我使用 udevadm 触发器,为什么我的 udev 规则会运行,但不会在启动时运行?

Dan*_*iel 7 udev

我遇到了 udev 规则未运行的问题。下面是一个例子:

我有一个规则/etc/udev/rules.d/99-test.rules,其中包含:

ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x8086", RUN+="/sayhi"
Run Code Online (Sandbox Code Playgroud)

并且sayhi只有:

#!/bin/bash
date +"%Y-%m-%d %H:%M:%S,%3N" >> /saidhi
Run Code Online (Sandbox Code Playgroud)

这是一台英特尔机器,我显然有许多供应商 0x8086 PCI 设备:

root@imtrobot:~# lspci -n |grep 8086
00:00.0 0600: 8086:2770 (rev 02)
00:02.0 0300: 8086:2772 (rev 02)
00:1d.0 0c03: 8086:27c8 (rev 01)
[ etc. 12 lines total ]
Run Code Online (Sandbox Code Playgroud)

然而,当我启动时,/saidhi要么根本不创建,要么里面有 1 或 2 个日期行。

如果在启动后,我运行udevadm trigger --action=add --subsystem-match=pci 然后 /saidhi将获得添加到它的正确数量的日期。

为什么这在启动过程中不起作用?

小智 1

实际上我有一种方法可以等待适当的时间,而不是任意的 30 秒。我在 Raspberry Pi 上做到了这一点,以便在连接时以及启动时自动安装所有连接的 USB 磁盘。

该规则与您的类似:

$ sudo cat /etc/udev/rules.d/10-usb_automount.rules 
KERNEL=="sd*", RUN+="/home/pi/bin/usb-automount"
Run Code Online (Sandbox Code Playgroud)

现在脚本实际上是一个递归调用(我知道这是邪恶的):

$ cat /home/pi/bin/usb-automount
#!/bin/sh

ROOT_RW=`mount | grep 'dev/root' | grep -E '\(.*rw.*\)'`

if [ -z "$ROOT_RW" ]; then
 sleep 3 
 /home/pi/bin/usb-automount & disown
else
 /home/pi/bin/usb-automount.sh
fi
Run Code Online (Sandbox Code Playgroud)

请注意,“grep 'dev/root'”特定于 Raspbian 操作系统,因此在 Ubuntu 上,您需要设计自己的 grep 来检测 rootfs(或者甚至更好地设计一些通用 grep)。请注意,该脚本将在后台调用自身并退出,并且仅当 rootfs 为“rw”时才会调用正确的安装脚本。脚本“/home/pi/bin/usb-automount.sh”执行实际安装或在您的情况下进行日志记录。

请注意,此脚本仍需要 3 秒才能执行,因此您可以通过更改为进一步优化:

if [ -z "$ROOT_RW" ]; then
 ( sleep 3; /home/pi/bin/usb-automount ) & disown
else
 /home/pi/bin/usb-automount.sh
fi
Run Code Online (Sandbox Code Playgroud)

但是我从未检查过这一点,也不知道这是否会按预期工作(我不是脚本专家)。


use*_*.dz 0

我教导的原因与@dmd相同,PCI uevents 在文件系统重新挂载之前发生rw。(但有时,一些 PCI uevents 之后,竞争条件,并行工作)

dmesg | grep -i -e mount -e pci
Run Code Online (Sandbox Code Playgroud)

@Sparhawk 的sleep想法对我来说似乎不错。我认为这就是它不起作用的原因(参考man udev:):

这只能用于运行时间非常短的前台任务。长时间运行事件进程可能会阻止该设备或从属设备的所有进一步事件。

启动守护进程或其他长时间运行的进程不适合 udev;分叉的进程,无论是否分离,都将在事件处理完成后被无条件终止。

因此,我创建了启动的新脚本和disown具有命令的脚本sleep。事实上,它确实有效!

$ ls -l /sa*
-rw-r--r-- 1 root root 1104 Oct 24 12:37 /saidhi
-rwxr-xr-x 1 root root   29 Oct 24 12:31 /sayhi
-rwxr-xr-x 1 root root   62 Oct 24 12:28 /sayhi2

$ cat /sayhi
#!/bin/bash
/sayhi2 & disown

$ cat /sayhi2 
#!/bin/bash
sleep 30
date +"%Y-%m-%d %H:%M:%S,%3N" >> /saidhi

$ cat /etc/udev/rules.d/99-test.rules 
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x8086", RUN+="/sayhi"
Run Code Online (Sandbox Code Playgroud)