Call variable from within udev rule

Viewed 585

I have multiple udev rules that check if ATTRS{name}=="abc123" and invokes various functions if that device is present. These udev rules are located within multiple locations as this is being created within bitbake for a custom embedded OS. Now, if I want to change this device to test different hardware, this is too time consuming to change every ATTR{name} call every time.

My solution would be to define a var, e.g. $UDEVVAR="[device_name]" in some conf file (to be determined), and then change each ATTR{name} call to something like ATTR{name}=="${UDEVVAR}".

I've tested this approach in a local rule written for proof of concept, although the rule didn't invoke. This local rule was a bit different, though followed the same concept. Whatever flash drive I had lying around didn't have an ATTR{name} defined, so I used a usb mouse and that flash drive. This udev rule is:

SUBSYSTEM=="${UDEVVAR}", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"

trigger.sh simply writes the date-time stamp to a log file. When hard coding SUBSYSTEM as =="block", the rule invokes successfully, although when defining UDEVVAR="block", the rule does not get invoked. The idea was, if that worked, then I would define UDEVVAR="hidraw" to test the mouse.

I can't seem to find much documentation on anyone trying to do something like this. I figure I'm making some sort of syntactical mistake, or maybe udev rules don't allow for something like this.

I appreciate any help!

1 Answers

You should be able to use ENV in udev rules.

SUBSYSTEM=="$env{UDEV_SUBSYS}", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"

Or even use it as filter condition (so that to conditionally run a given rule out of N similar):

ENV{UDEV_SUBSYS}=="hidraw", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"

You then have to define the variable in time, like in /etc/environment (or even with u-boot setenv):

UDEV_SUBSYS="hidraw"

If you wish to change this dynamically after boot completed (i.e. from an userland process), this won't suffice; you will have to implement a mechanism that restarts udev as its child after updating the environment.

See udev manual for details.

NOTE: this, as well as the manual, is valid for systemd-udevd. YMMV with other udev flavours.

EDIT: /etc/environment is not quite supported by busybox init. Please see /etc/inittab for whatever init script you may have, and source the environment file (or set/export variables) there.

EDIT 2: sadly, it seems that only NAME, SYMLINK, PROGRAM, OWNER, GROUP, MODE, SECLABEL, and RUN fields support substitutions. :( I overlooked that in the manual previously.

You may have some success with writing a shell script that receives the device data as environment and provide that in the PROGRAM field to do the matching. Just return 0 if it is deemed a match.

Related