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/[email protected]:

[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 [email protected] 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 [email protected] $env{ID_SERIAL_SHORT}", ENV{SYSTEMD_WANTS}+="%c" 
4
  • 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? Commented Nov 4, 2019 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. Commented Nov 4, 2019 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. Commented Nov 4, 2019 at 13:51
  • TAG+="systemd", ENV{SYSTEMD_USER_WANTS}+="<unit>" is triggered only once per boot or something like that. man systemd.device Commented Mar 13, 2021 at 17:07

3 Answers 3

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.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.