udev 规则中的无条件 GOTO(和 Medion RC-0617)
Conditionless GOTO in udev rules (and Medion RC-0617)
我一直在某些 Debian 8.8 衍生版本 (antix16) 下对 Medion RC-0617 遥控器(带有 USB 加密狗)进行逆向工程。
它注册了 3 个不同的 HID 设备 (/dev/hidraw*),我希望将它们符号链接到 /dev/mdremote0、1 和 2,而与关联的 hidraw 设备的数量无关(它们是hidraw1、2 和 3 大多数时间,但这取决于插入的输入设备)以便使用脚本查询它们以执行遥控器按钮的自定义操作。
(同时将他们的文件模式设置为 666 以便作为普通用户访问它们)
udevadm info -a /dev/hidraw1 的输出如下所示(缩写):
// The actual hidraw device (top level)
looking at device '/devices/pci0000:00/0000:00:1c.4/0000:05:00.0/usb3/3-1/3-1:1.0/0003:04F2:0618.002B/hidraw/hidraw1':
KERNEL=="hidraw1"
SUBSYSTEM=="hidraw"
DRIVER==""
//...
// The last point at which the 3 individual hidraw devices differed from each other
looking at parent device '/devices/pci0000:00/0000:00:1c.4/0000:05:00.0/usb3/3-1/3-1:1.0':
KERNELS=="3-1:1.0"
SUBSYSTEMS=="usb"
DRIVERS=="usbhid"
//...
ATTRS{bInterfaceProtocol}=="01"
// This entry distinguished the 3 individual hidraw devices from each other
//...
// The dongle itself, parent device of all 3 hidraw devices
looking at parent device '/devices/pci0000:00/0000:00:1c.4/0000:05:00.0/usb3/3-1':
KERNELS=="3-1"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{idVendor}=="04f2"
ATTRS{idProduct}=="0618"
ATTRS{product}=="USB Wireless HID Receiver"
// The dongle can be uniquely identified by idVendor and idProduct
//...
//...
因此,我需要编写的 udev 规则需要:
- 通过 idVendor 和 idProduct 识别一个父设备
- 检查另一个父设备中的 bInterfaceProtocol 属性
- 为设备分配正确的符号链接 /dev/mdremote* 并设置正确的权限
我的第一次尝试是这样的:
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="04f2", ATTRS{idProduct}=="0618", ATTRS{bInterfaceProtocol}=="01", SYMLINK="mdremote0", MODE="0666"
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="04f2", ATTRS{idProduct}=="0618", ATTRS{bInterfaceProtocol}=="00", SYMLINK="mdremote1", MODE="0666"
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="04f2", ATTRS{idProduct}=="0618", ATTRS{bInterfaceProtocol}=="02", SYMLINK="mdremote2", MODE="0666"
(bInterfaceProtocol 属性的顺序是有意的)
简而言之,这不起作用,udev 联机帮助页说:
Some of the keys also match against properties of the parent devices
in sysfs, not only the device that has generated the event. If
multiple keys that match a parent device are specified in a single
rule, all these keys must match at one and the same parent device.
所以,我开始了另一种方法:首先与加密狗进行匹配,然后如果此检查不匹配则跳过个别规则,如下所示:
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="04f2", ATTRS{idProduct}=="0618", GOTO="match"
GOTO="end"
LABEL="match"
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{bInterfaceProtocol}=="01", SYMLINK="mdremote0", MODE="0666"
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{bInterfaceProtocol}=="00", SYMLINK="mdremote1", MODE="0666"
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{bInterfaceProtocol}=="02", SYMLINK="mdremote2", MODE="0666"
LABEL="end"
这在第一学期看起来是正确的。但是,你猜怎么着,它也不起作用,mdremote* 符号链接只是指向任何设置了 bInterfaceProtocol 密钥的设备。
的确,第二行 (GOTO="end") 被忽略了。我花了一些时间才弄清楚,但解决方案实际上非常简单:
如果没有匹配条件,udev 将规则视为 "always not matching",因此根本不执行 GOTO。
我的工作 udev 规则文件如下所示:
# Test if the wanted dongle is a parent device
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="04f2", ATTRS{idProduct}=="0618", GOTO="match"
# If not, skip the next 3 rules. The test against SUBSYSTEM=="hidraw" is there to produce a rule match
SUBSYSTEM=="hidraw", GOTO="end"
LABEL="match"
# Those 3 rules actually assign the right symlink depending on the bInterfaceProtocol property.
# Note that ALL of those rules contain the SUBSYSTEM=="hidraw" check, because the GOTO in the second line
# does not get executed for non-hidraw devices and the rules get evaluated for any non-hidraw device.
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{bInterfaceProtocol}=="01", SYMLINK="mdremote0", MODE="0666"
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{bInterfaceProtocol}=="00", SYMLINK="mdremote1", MODE="0666"
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{bInterfaceProtocol}=="02", SYMLINK="mdremote2", MODE="0666"
LABEL="end"
结果证明效果很好。它仍然可以通过为 GOTO="end" 语句提供更好的匹配规则来改进,但我就那样了。
@orwell 我偶然发现了这个并且有点困惑为什么这对你不起作用。我曾尝试做一些类似的事情,并且在无条件 GOTO 和 debian stretch 以及 Arch Linux 上没有遇到任何问题。检查这个:
[c0d3@z3r0 tmp]$ cat /etc/udev/rules.d/45-test.rules
GOTO="end"
IMPORT{program}=="/bin/touch /tmp/noend"
LABEL="end"
IMPORT{program}=="/bin/touch /tmp/end"
[c0d3@z3r0 tmp]$ sudo udevadm control --reload
[c0d3@z3r0 tmp]$ sudo udevadm trigger
[c0d3@z3r0 tmp]$ ls /tmp/*end
/tmp/end
[c0d3@z3r0 tmp]$
我一直在某些 Debian 8.8 衍生版本 (antix16) 下对 Medion RC-0617 遥控器(带有 USB 加密狗)进行逆向工程。
它注册了 3 个不同的 HID 设备 (/dev/hidraw*),我希望将它们符号链接到 /dev/mdremote0、1 和 2,而与关联的 hidraw 设备的数量无关(它们是hidraw1、2 和 3 大多数时间,但这取决于插入的输入设备)以便使用脚本查询它们以执行遥控器按钮的自定义操作。 (同时将他们的文件模式设置为 666 以便作为普通用户访问它们)
udevadm info -a /dev/hidraw1 的输出如下所示(缩写):
// The actual hidraw device (top level)
looking at device '/devices/pci0000:00/0000:00:1c.4/0000:05:00.0/usb3/3-1/3-1:1.0/0003:04F2:0618.002B/hidraw/hidraw1':
KERNEL=="hidraw1"
SUBSYSTEM=="hidraw"
DRIVER==""
//...
// The last point at which the 3 individual hidraw devices differed from each other
looking at parent device '/devices/pci0000:00/0000:00:1c.4/0000:05:00.0/usb3/3-1/3-1:1.0':
KERNELS=="3-1:1.0"
SUBSYSTEMS=="usb"
DRIVERS=="usbhid"
//...
ATTRS{bInterfaceProtocol}=="01"
// This entry distinguished the 3 individual hidraw devices from each other
//...
// The dongle itself, parent device of all 3 hidraw devices
looking at parent device '/devices/pci0000:00/0000:00:1c.4/0000:05:00.0/usb3/3-1':
KERNELS=="3-1"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{idVendor}=="04f2"
ATTRS{idProduct}=="0618"
ATTRS{product}=="USB Wireless HID Receiver"
// The dongle can be uniquely identified by idVendor and idProduct
//...
//...
因此,我需要编写的 udev 规则需要:
- 通过 idVendor 和 idProduct 识别一个父设备
- 检查另一个父设备中的 bInterfaceProtocol 属性
- 为设备分配正确的符号链接 /dev/mdremote* 并设置正确的权限
我的第一次尝试是这样的:
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="04f2", ATTRS{idProduct}=="0618", ATTRS{bInterfaceProtocol}=="01", SYMLINK="mdremote0", MODE="0666"
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="04f2", ATTRS{idProduct}=="0618", ATTRS{bInterfaceProtocol}=="00", SYMLINK="mdremote1", MODE="0666"
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="04f2", ATTRS{idProduct}=="0618", ATTRS{bInterfaceProtocol}=="02", SYMLINK="mdremote2", MODE="0666"
(bInterfaceProtocol 属性的顺序是有意的)
简而言之,这不起作用,udev 联机帮助页说:
Some of the keys also match against properties of the parent devices in sysfs, not only the device that has generated the event. If multiple keys that match a parent device are specified in a single rule, all these keys must match at one and the same parent device.
所以,我开始了另一种方法:首先与加密狗进行匹配,然后如果此检查不匹配则跳过个别规则,如下所示:
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="04f2", ATTRS{idProduct}=="0618", GOTO="match"
GOTO="end"
LABEL="match"
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{bInterfaceProtocol}=="01", SYMLINK="mdremote0", MODE="0666"
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{bInterfaceProtocol}=="00", SYMLINK="mdremote1", MODE="0666"
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{bInterfaceProtocol}=="02", SYMLINK="mdremote2", MODE="0666"
LABEL="end"
这在第一学期看起来是正确的。但是,你猜怎么着,它也不起作用,mdremote* 符号链接只是指向任何设置了 bInterfaceProtocol 密钥的设备。
的确,第二行 (GOTO="end") 被忽略了。我花了一些时间才弄清楚,但解决方案实际上非常简单:
如果没有匹配条件,udev 将规则视为 "always not matching",因此根本不执行 GOTO。
我的工作 udev 规则文件如下所示:
# Test if the wanted dongle is a parent device
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="04f2", ATTRS{idProduct}=="0618", GOTO="match"
# If not, skip the next 3 rules. The test against SUBSYSTEM=="hidraw" is there to produce a rule match
SUBSYSTEM=="hidraw", GOTO="end"
LABEL="match"
# Those 3 rules actually assign the right symlink depending on the bInterfaceProtocol property.
# Note that ALL of those rules contain the SUBSYSTEM=="hidraw" check, because the GOTO in the second line
# does not get executed for non-hidraw devices and the rules get evaluated for any non-hidraw device.
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{bInterfaceProtocol}=="01", SYMLINK="mdremote0", MODE="0666"
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{bInterfaceProtocol}=="00", SYMLINK="mdremote1", MODE="0666"
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{bInterfaceProtocol}=="02", SYMLINK="mdremote2", MODE="0666"
LABEL="end"
结果证明效果很好。它仍然可以通过为 GOTO="end" 语句提供更好的匹配规则来改进,但我就那样了。
@orwell 我偶然发现了这个并且有点困惑为什么这对你不起作用。我曾尝试做一些类似的事情,并且在无条件 GOTO 和 debian stretch 以及 Arch Linux 上没有遇到任何问题。检查这个:
[c0d3@z3r0 tmp]$ cat /etc/udev/rules.d/45-test.rules
GOTO="end"
IMPORT{program}=="/bin/touch /tmp/noend"
LABEL="end"
IMPORT{program}=="/bin/touch /tmp/end"
[c0d3@z3r0 tmp]$ sudo udevadm control --reload
[c0d3@z3r0 tmp]$ sudo udevadm trigger
[c0d3@z3r0 tmp]$ ls /tmp/*end
/tmp/end
[c0d3@z3r0 tmp]$