I want to execute a script on connecting a specific keyboard. Here's my attempt and the data I've gathered.
After cooking it down, this is the minimal problem I am still having:
/etc/udev/rules.d/99-kinesis-testing-high-number.rules:
ACTION=="add", RUN+="/bin/sh -c '/bin/echo UDEV > /tmp/layout_kinesis.log'"
Reload and trigger:
sudo udevadm control --reload-rules && sudo udevadm trigger
Nothing happens in the file /tmp/layout_kinesis.log upon connecting a USB device.
What is wrong with this minimal rule?
Ubuntu 20.04.
This is from /var/log/syslog:
Mar 30 08:24:25 ionian mtp-probe: checking bus 2, device 96: "/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.1/2-1.1.2"
Mar 30 08:24:25 ionian mtp-probe: bus: 2, device: 96 was not an MTP device
Mar 30 08:24:25 ionian systemd-udevd[59515]: 2-1.1.2: /etc/udev/rules.d/99-kinesis-testing-high-number.rules:1 Failed to write ATTR{/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.1/2-1.1.2/idProduct}, ignoring: Permission denied
Mar 30 08:24:25 ionian systemd-udevd[59515]: 2-1.1.2: Process '/bin/sh -c '/bin/echo UDEV > /tmp/layout_kinesis.log'' failed with exit code 2.
Mar 30 08:24:25 ionian systemd-udevd[59515]: 2-1.1.2:1.0: /etc/udev/rules.d/99-kinesis-testing-high-number.rules:1 Failed to write ATTR{/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.1/2-1.1.2/2-1.1.2:1.0/idProduct}, ignoring: No such file or directory
Mar 30 08:24:25 ionian systemd-udevd[59513]: 2-1.1.2:1.1: /etc/udev/rules.d/99-kinesis-testing-high-number.rules:1 Failed to write ATTR{/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.1/2-1.1.2/2-1.1.2:1.1/idProduct}, ignoring: No such file or directory
Mar 30 08:24:25 ionian systemd-udevd[59515]: 2-1.1.2:1.0: Process '/bin/sh -c '/bin/echo UDEV > /tmp/layout_kinesis.log'' failed with exit code 2.
Mar 30 08:24:25 ionian systemd-udevd[59513]: 2-1.1.2:1.1: Process '/bin/sh -c '/bin/echo UDEV > /tmp/layout_kinesis.log'' failed with exit code 2.
The rule seems to trigger (although I'm not sure why it pops up three times). I've found a number of issues online about read-only file systems for udev.
All these links seem to have trouble with the file system mounted as read-only for udev. But I'm not sure it's the case for me too:
$ ps aux|grep udev
root 61004 0.0 0.0 23816 7416 ? Ss 09:00 0:00 /lib/systemd/systemd-udevd
$ less /proc/61004/mounts
/dev/sda1 / ext4 rw,relatime,errors=remount-ro 0 0
It says rw, but it also says errors=remount-ro...
Below are details of how I got there:
lsusb gives me Bus and Device (002 and 048):
$ lsusb
Bus 002 Device 008: ID 046d:c52b Logitech, Inc. Unifying Receiver
Bus 002 Device 007: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
Bus 002 Device 010: ID 045e:0b12 Microsoft Corp.
Bus 002 Device 048: ID 05f3:0007 PI Engineering, Inc. Kinesis Advantage PRO MPC/USB Keyboard
Bus 002 Device 047: ID 05f3:0081 PI Engineering, Inc. Kinesis Integrated Hub
From there, udevadm gives me attributes:
$ sudo udevadm info --attribute-walk /dev/bus/usb/002/048
Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.
looking at device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.1/2-1.1.2':
KERNEL=="2-1.1.2"
SUBSYSTEM=="usb"
DRIVER=="usb"
ATTR{devpath}=="1.1.2"
ATTR{bcdDevice}=="0320"
ATTR{devnum}=="48"
ATTR{bMaxPower}=="64mA"
ATTR{bMaxPacketSize0}=="8"
ATTR{quirks}=="0x0"
ATTR{tx_lanes}=="1"
ATTR{bNumInterfaces}==" 2"
ATTR{idProduct}=="0007"
ATTR{speed}=="12"
ATTR{bConfigurationValue}=="1"
ATTR{configuration}==""
ATTR{busnum}=="2"
ATTR{bDeviceClass}=="00"
ATTR{maxchild}=="0"
ATTR{bNumConfigurations}=="1"
ATTR{idVendor}=="05f3"
ATTR{ltm_capable}=="no"
ATTR{bDeviceSubClass}=="00"
ATTR{avoid_reset_quirk}=="0"
ATTR{bmAttributes}=="a0"
ATTR{urbnum}=="427"
ATTR{bDeviceProtocol}=="00"
ATTR{removable}=="fixed"
ATTR{version}==" 1.10"
ATTR{rx_lanes}=="1"
ATTR{authorized}=="1"
looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.1':
KERNELS=="2-1.1"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{authorized}=="1"
ATTRS{devnum}=="77"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{bcdDevice}=="0320"
ATTRS{idVendor}=="05f3"
ATTRS{urbnum}=="31"
ATTRS{manufacturer}=="PI Engineering"
ATTRS{devpath}=="1.1"
ATTRS{bmAttributes}=="a0"
ATTRS{bMaxPower}=="50mA"
ATTRS{idProduct}=="0081"
ATTRS{ltm_capable}=="no"
ATTRS{configuration}==""
ATTRS{bConfigurationValue}=="1"
ATTRS{maxchild}=="4"
ATTRS{bNumInterfaces}==" 1"
ATTRS{tx_lanes}=="1"
ATTRS{version}==" 1.10"
ATTRS{busnum}=="2"
ATTRS{rx_lanes}=="1"
ATTRS{speed}=="12"
ATTRS{bMaxPacketSize0}=="8"
ATTRS{bNumConfigurations}=="1"
ATTRS{bDeviceClass}=="09"
ATTRS{bDeviceProtocol}=="00"
ATTRS{removable}=="unknown"
ATTRS{bDeviceSubClass}=="00"
ATTRS{product}=="Kinesis Keyboard Hub"
ATTRS{quirks}=="0x0"
...
And so, my resulting udev rule in /etc/udev/rules.c/90-kinesis-advantage.rules:
SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="05f3", ATTR{idProduct}=="0007", RUN+="/bin/echo aaa >> /tmp/layout_kinesis.log"
Then reload the rules:
$ sudo udevadm control --reload-rules && sudo udevadm trigger
And monitor the output file:
$ tail -f /tmp/layout_kinesis.log
But disconnecting and reconnecting the keyboard gives no reaction.
I've tried matching the parent as well, but got no luck:
SUBSYSTEMS=="usb", ACTION=="add", ATTRS{idVendor}=="05f3", RUN+="/bin/sh -c 'echo aaa >> /tmp/layout_kinesis.log'"
Also tried to remove sh out and tried this, but nope: RUN+="/bin/echo aaa >> /tmp/layout_kinesis.log"
The last add entry in udevadm monitor -e is:
UDEV [51347.305368] add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.1/2-1.1.2/2-1.1.2:1.1/0003:05F3:0007.003C/input/input112/event6 (input)
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.1/2-1.1.2/2-1.1.2:1.1/0003:05F3:0007.003C/input/input112/event6
SUBSYSTEM=input
DEVNAME=/dev/input/event6
SEQNUM=26402
USEC_INITIALIZED=51347305171
ID_INPUT=1
ID_INPUT_KEY=1
ID_VENDOR=05f3
ID_VENDOR_ENC=05f3
ID_VENDOR_ID=05f3
ID_MODEL=0007
ID_MODEL_ENC=0007
ID_MODEL_ID=0007
ID_REVISION=0320
ID_SERIAL=05f3_0007
ID_TYPE=hid
ID_BUS=usb
ID_USB_INTERFACES=:030101:030000:
ID_USB_INTERFACE_NUM=01
ID_USB_DRIVER=usbhid
ID_PATH=pci-0000:00:1d.0-usb-0:1.1.2:1.1
ID_PATH_TAG=pci-0000_00_1d_0-usb-0_1_1_2_1_1
XKBMODEL=pc105
XKBLAYOUT=us
XKBVARIANT=
XKBOPTIONS=
BACKSPACE=guess
LIBINPUT_DEVICE_GROUP=3/5f3/7:usb-0000:00:1d.0-1.1
MAJOR=13
MINOR=70
DEVLINKS=/dev/input/by-path/pci-0000:00:1d.0-usb-0:1.1.2:1.1-event /dev/input/by-id/usb-05f3_0007-event-if01
TAGS=:power-switch:
So I tried this, because of some recollection I had:
ACTION=="add", ENV{ID_SERIAL}=="05f3_0007", RUN+="/bin/echo aaa >> /tmp/layout_kinesis.log"
Still nothing.
udevadm test shows that run is populated, at least (this output with the ENV{ID_SERIAL} version just above):
$ udevadm test $(udevadm info -q path -n /dev/bus/usb/002/062)
# ... the end here:
Reading rules file: /etc/udev/rules.d/90-kinesis-advantage.rules
Reading rules file: /lib/udev/rules.d/90-libgpod.rules
Reading rules file: /lib/udev/rules.d/90-libinput-fuzz-override.rules
Reading rules file: /lib/udev/rules.d/90-nm-thunderbolt.rules
Reading rules file: /lib/udev/rules.d/90-pulseaudio.rules
Reading rules file: /lib/udev/rules.d/95-cd-devices.rules
Reading rules file: /lib/udev/rules.d/95-dm-notify.rules
Reading rules file: /lib/udev/rules.d/95-upower-csr.rules
Reading rules file: /lib/udev/rules.d/95-upower-hid.rules
Reading rules file: /lib/udev/rules.d/95-upower-hidpp.rules
Reading rules file: /lib/udev/rules.d/95-upower-wup.rules
Reading rules file: /lib/udev/rules.d/96-e2scrub.rules
Reading rules file: /lib/udev/rules.d/97-hid2hci.rules
Reading rules file: /lib/udev/rules.d/99-systemd.rules
Invalid inotify descriptor.
DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.1/2-1.1.2
DEVNAME=/dev/bus/usb/002/062
DEVTYPE=usb_device
DRIVER=usb
PRODUCT=5f3/7/320
TYPE=0/0/0
BUSNUM=002
DEVNUM=062
MAJOR=189
MINOR=189
ACTION=add
SUBSYSTEM=usb
ID_VENDOR=05f3
ID_VENDOR_ENC=05f3
ID_VENDOR_ID=05f3
ID_MODEL=0007
ID_MODEL_ENC=0007
ID_MODEL_ID=0007
ID_REVISION=0320
ID_SERIAL=05f3_0007
ID_BUS=usb
ID_USB_INTERFACES=:030101:030000:
ID_VENDOR_FROM_DATABASE=PI Engineering, Inc.
ID_MODEL_FROM_DATABASE=Kinesis Advantage PRO MPC/USB Keyboard
ID_PATH=pci-0000:00:1d.0-usb-0:1.1.2
ID_PATH_TAG=pci-0000_00_1d_0-usb-0_1_1_2
USEC_INITIALIZED=51523126321
run: '/bin/echo aaa >> /tmp/layout_kinesis.log'
Unload module index
Unloaded link configuration context.
I've also tried to combine attributes of the device and attributes of one parent:
SUBSYSTEMS=="usb", ATTRS{idVendor}=="05f3", ATTR{idProduct}="0007", ACTION=="add", RUN+="/bin/sh -c '/bin/echo UDEV > tmp/layout_kinesis.log'"
This is still not working.
About sandboxing:
$ systemctl cat systemd-udevd.service
# /lib/systemd/system/systemd-udevd.service
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=udev Kernel Device Manager
Documentation=man:systemd-udevd.service(8) man:udev(7)
DefaultDependencies=no
After=systemd-sysusers.service systemd-hwdb-update.service
Before=sysinit.target
ConditionPathIsReadWrite=/sys
[Service]
Type=notify
# Note that udev also adjusts the OOM score internally and will reset the value internally for its workers
OOMScoreAdjust=-1000
Sockets=systemd-udevd-control.socket systemd-udevd-kernel.socket
Restart=always
RestartSec=0
ExecStart=/lib/systemd/systemd-udevd
ExecReload=udevadm control --reload --timeout 0
KillMode=mixed
TasksMax=infinity
PrivateMounts=yes
ProtectHostname=yes
MemoryDenyWriteExecute=yes
RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6
RestrictRealtime=yes
RestrictSUIDSGID=yes
LockPersonality=yes
IPAddressDeny=any
WatchdogSec=3min
OPTIONS="log_level=debug"to the rule (ACTION=="add", OPTIONS="...", ...etc...) if you want to see debug information injournalctlordmesgand to see if your rule even matches correct device(s). You can also try to use onlyATTRSinstead ofATTRso that the whole tree gets matched.