3

Linux newbie on Gentoo here. I am trying to write a udev rule that would run a Python script and pass some information whenever a usb device (specifically a usb modem) is inserted. I have:

SUBSYSTEM == "usb", ACTION == "add", $ATTRS{vendor} = "?*", RUN += "/home/.../notify.py %k '$attr{vendor}'"

as a starting point.

Right now, notify.py is an executable trying to help me debug and looks like:

#!/usr/bin/python
import sys
log = open("log.txt", 'a')
for a in sys.argv:
    log.write(a + "\n")
fi.close()

I cannot figure out how to get "$attr{vendor}" to pass; right now, only %k (the kernel of the device) is passed and printed, along with any other string arguments I feel like adding. I've been all over the internet, I've tried "$attr{vendor}" (outputs nothing), "$attrs{vendor}" (outputs "s{vendor}"), and "%s{vendor}"(outputs nothing). I've tried changing the priority of this rule, in case variables weren't being defined yet or something. I've looked at other rules files, and none of them do quite what I'm doing, but they do manage to use "$attr{[something]}".

Still confusing is, if I write something like

GOTO+="$attr{vendor}"

vi highlights it as a string, but

RUN+="$attr{vendor}"

and vi highlights everything differently. I feel like the bug has something to do with the way RUN works, or with my improper usage of "$attr", but I'm totally lost.

These posts seem to do something similar to what I am trying to do. I'd appreciate any help or input on this problem.

2 Answers 2

3

It is somewhat complicated, because the rules are evaluated for each node in the device tree and because some informations are available in some parts of the tree but cannot be referenced from another part of the tree.

Most easily you have to combine at least two rules (this can be expanded to more rules if you want to filter on more than one ancestor).

  1. Specify (as you correctly wrote) some parent device which has the necessary information that you want to use (like a name or a vendorId/productId that is specific to your device), store any needed information into environment variables and raise a flag for the second rule to be able to be run only on ascendents of this device.
  2. Filter on the previous flag (and any other needed attribute) and use the environment variables set up previously (those values normally will not be available to this script at this point).

Mock up code, but shows the concept:

ACTION == "add", SUBSYSTEM == "usb", ATTRS{idProduct}=="0123", ATTRS{idVendor}=="4567" ENV{SEARCHED_DEVICE}="YES", ENV{VENDORID}="$attr{idVendor}", ENV{PRODUCTID}="$attr{idProduct}",
ACTION == "add", ENV{SEARCHED_DEVICE}=="YES", RUN+="/path/to/script.sh '$env{VENDORID}' '$env{PRODUCTID}'"
  • ENV{SEARCHED_DEVICE} is the flag used to indicate the matched device
  • ENV{VENDORID} and ENV{PRODUCTID} contain the data that should be saved over to the second rule.
  • '$env{VENDORID}' '$env{PRODUCTID}' is the reference to these values.

Watch out for the single (assignment) and double (test value) equals signs.

2

In case it helps someone one day, I found two steps that helped me solve the problem.

The first was to ensure that the rule had selected a parent device to pull attribute information from, so I added a

ATTRS{bDeviceClass} == "02"

to have the rule link to the desired network device.

The second step, which might have been unnecessary after the first step, was to set an environment variable and call it as such:

ENV{var} = ATTRS{bDeviceClass}, RUN+="/home/.../notify.py '$env{var}'"

This successfully passed the variable. In the end, it seemed like $attr and %s still did not work. I'd been stuck on this so long I lack the motivation right now to play around with things.

You must log in to answer this question.

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