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 --template=offnet-uar[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?
    – AdminBee
    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.
    – Gauthier
    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.
    – AdminBee
    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 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.

Not the answer you're looking for? Browse other questions tagged .