3

Background: I want to start a log script when my usb-uart device connects.

My /etc/udev/rules.d/10-local.rules:

SUBSYSTEM=="tty", ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1015", ATTRS{serial}=="000621000000", SYMLINK+="ttymkw", TAG+="systemd", ENV{SYSTEMD_USER_WANTS}+="offnet-uart-log@$env{ID_SERIAL_SHORT}.service"

My ~/.config/systemd/user/offnet-uart-log@.service:

[Unit]
Description=Start log of UART

[Service]
ExecStart=sh -c "echo %I >> /tmp/systemd.test"

This does not give me the expected value of ID_SERIAL_SHORT. Instead, I get a long sys path:

sys/devices/pci0000:00/0000:00:1c.0/0000:01:00.0/0000:02:02.0/0000:39:00.0/usb3/3-1/3-1.7/3-1.7.2/3-1.7.2:1.0/tty/ttyACM0

When I try to get the properties for this path (I need to remove the leading sys), I can see ID_SERIAL_SHORT:

$ udevadm info --query=property --path /devices/pci0000:00/0000:00:1c.0/0000:01:00.0/0000:02:02.0/0000:39:00.0/usb3/3-1/3-1.7/3-1.7.2/3-1.7.2:1.0/tty/ttyACM0DEVPATH=//devices/pci0000:00/0000:00:1c.0/0000:01:00.0/0000:02:02.0/0000:39:00.0/usb3/3-1/3-1.7/3-1.7.2/3-1.7.2:1.0/tty/ttyACM0
DEVNAME=/dev/ttyACM0
MAJOR=166
MINOR=0
SUBSYSTEM=tty
USEC_INITIALIZED=1633350773062
SYSTEMD_USER_WANTS=offnet-uart-log@.service
ID_BUS=usb
ID_VENDOR_ID=1366
ID_MODEL_ID=1015
ID_PCI_CLASS_FROM_DATABASE=Serial bus controller
ID_PCI_SUBCLASS_FROM_DATABASE=USB controller
ID_PCI_INTERFACE_FROM_DATABASE=XHCI
ID_VENDOR_FROM_DATABASE=SEGGER
ID_MODEL_FROM_DATABASE=DSL6340 USB 3.1 Controller [Alpine Ridge]
ID_VENDOR=SEGGER
ID_VENDOR_ENC=SEGGER
ID_MODEL=J-Link
ID_MODEL_ENC=J-Link
ID_REVISION=0100
ID_SERIAL=SEGGER_J-Link_000621000000
ID_SERIAL_SHORT=000621000000                 ### <--- here
ID_TYPE=generic
ID_USB_INTERFACES=:020201:0a0000:ffffff:080650:
ID_USB_INTERFACE_NUM=00
ID_USB_DRIVER=cdc_acm
ID_USB_CLASS_FROM_DATABASE=Miscellaneous Device
ID_USB_PROTOCOL_FROM_DATABASE=Interface Association
ID_PATH=pci-0000:39:00.0-usb-0:1.7.2:1.0
ID_PATH_TAG=pci-0000_39_00_0-usb-0_1_7_2_1_0
ID_MM_CANDIDATE=1
DEVLINKS=/dev/ttymkw /dev/serial/by-id/usb-SEGGER_J-Link_000621000000-if00 /dev/serial/by-path/pci-0000:39:00.0-usb-0:1.7.2:1.0
TAGS=:systemd:

$env{ID_SERIAL_SHORT} in my udev rule does not seem to be replaced with the value of the property.

The man page for udev says that the $env{key} substitution is only available for the NAME, SYMLINK, PROGRAM, OWNER, GROUP, MODE, SECLABEL, and RUN fields.

However, I've seen examples of people using it in ENV{SYSTEMD_USER_WANTS}. It doesn't work for me, apparently.

How can I pass the serial number of my device to the systemd template?


EDIT: I've also tried this, but nope:

SUBSYSTEM=="tty", ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1015", ATTRS{serial}=="000621000000", SYMLINK+="ttymkw", PROGRAM="/bin/systemd-escape -p --template=offnet-uart-log@.service $env{ID_SERIAL_SHORT}", ENV{SYSTEMD_WANTS}+="%c"
  • If your systemd service starts a script, you could call udevadm info inside your script and use grep to extract the ID_SERIAL_SHORT. Would that be an option or are there other boundary conditions which prevent this approach? – AdminBee Nov 4 at 13:27
  • @AdminBee This is a possible work-around, thanks. At the same time, it feels like there should be an actual solution. Seeing people using $env{ID_SERIAL} in their solutions frustrates me. – Gauthier Nov 4 at 13:47
  • Yes, I can very much relate to that ... If you agree, I will also post it as a regular solution, although you are of course right in that it is only a workaround. – AdminBee Nov 4 at 13:51
2

The parameter I am looking for is $attr{serial}. I'm not sure why other solutions didn't work when it worked for others, I guess they are obsolete (EDIT: it's probably because my rule file, starting with 10-, is read before the rule file that creates the environment variable ID_SERIAL, starting with 60-). This is working:

udev rule:

SUBSYSTEM=="tty", ATTRS{idVendor}=="1366", SYMLINK+="ttymkw", ENV{SYSTEMD_WANTS}+="offnet-uart-log@$attr{serial}"

Systemd template:

[Unit]
Description=Start log of UART for a Offnet unit

[Service]
ExecStart=/bin/sh -c "/bin/echo %i >> /tmp/asdf.log"

Apparently I don't need the TAG, and I need to use $attr instead of $env.

systemd version is 241.

The Q/A that helped me.


EDIT: a reason for $env not working could be that ID_SERIAL_SHORT is created on a rule on level 60, while my file is 10-local.rules. Thanks @yuwata. (Not verified.)

1

As another workaround, if the systemd service is calling a script in its ExecStart statement, the same udevadm call shown in the question could be included in that script to extract the ID_SERIAL_SHORT via grep.

0

As a workaround, I can create my own environment variable in the udev rule:

SUBSYSTEM=="tty", ATTRS{idVendor}=="1366", ATTRS{idProduct}=="1015", \
ATTRS{serial}=="000621000000", SYMLINK+="ttymkw", TAG+="systemd", \ 
ENV{MY_ID}="000621000000", \
ENV{SYSTEMD_USER_WANTS}+="offnet-uart-log@$env{MY_ID}.service"

(backslashes for readability, this should be on a single line.)

Or really, just write the string directly after @.

These should not be needed though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.