LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   udev rules - how to pass ATTRS{*} values to the RUN command? (http://www.linuxquestions.org/questions/programming-9/udev-rules-how-to-pass-attrs%7B%2A%7D-values-to-the-run-command-834307/)

catkin 09-24-2010 02:11 PM

udev rules - how to pass ATTRS{*} values to the RUN command?
 
Hello :-)

I'm modifying a working udev rule which runs a script that mounts a USB HDD and synchronises files to it.

The USB HDDs have been troublesome, losing many files and even losing file systems a couple of times. To investigate, I want to log the USB HDD product name and serial number so would like to pass ATTRS{product} and ATTRS{serial} values to the script.

This may not be possible; I cannot see anything about how to do it in either the udev man page nor Daniel Drake's "Writing udev rules" Version 0.74 but it seems such an obvious thing to want to do, I'm wondering if I've overlooked something.

udev is version 141 and the OS is Slackware 13.0 32-bit.

Best

Charles

GrapefruiTgirl 09-24-2010 03:00 PM

passing udev RUN arguments to external program
 
Hi catkin,

As per the udev manpage, the RUN+= thingy takes a printf-like syntax, which took me a few whiles to figure out. But, here's an example of what you want.

First, my rule (broken for readability):
Code:

SUBSYSTEMS=="usb",ATTRS{manufacturer}=="Kingston",ATTRS{product}=="DataTraveler 2.0",
NAME{all_partitions}="usb-kingston",GROUP="plugdev",
RUN+="/home/sasha/udevtest.sh %M %m %s{manufacturer}",$major,$minor,$attr{manufacturer}

Here's what the udevtest.sh program contains:
Code:

#!/bin/bash

echo >> /home/sasha/udevtest.out
echo "Major is: $1" >> /home/sasha/udevtest.out
echo "Minor is: $2" >>  /home/sasha/udevtest.out
echo "ATTR{manufacturer} is: $3" >>  /home/sasha/udevtest.out

exit 0

and here's the output resulting from me plugging the USB device into the machine:
Code:

sasha@reactor: tail -f udevtest.out

Major is: 189
Minor is: 18
ATTR{manufacturer} is: Kingston

Major is: 21
Minor is: 5
ATTR{manufacturer} is:

Major is: 254
Minor is: 5
ATTR{manufacturer} is:

Major is: 8
Minor is: 64
ATTR{manufacturer} is:

Notice that there are more than one event generated above, thus the script is called more than once, but only one of the calls to the script actually had the $attr variable available to it.. So, you will probably want to have a more specific rule than the example I used, and/or maybe target your rule differently so that it only executes the script once. Or, make your script have some sanity checking to ensure that it has been given enough parameters to run to completion correctly. I'll leave that fiddling up to you to decide, but if I can help further, I'll try! :)

Good luck!

Oh, and for debugging, you'll want to do one of several things. I do it this way:

- edit my rule.
- make sure the device is unplugged
- /etc/rc.d/rc.udev reload
- connect device to test your rule.
- repeat

..because if the device is still plugged in, reloading the rules doesn't seem sometimes to actually reload. To be sure, I remove the device first.

And if you need/want, read about `udevadm` and its "monitor" command, for if you want to watch the udev events going by on your screen.

catkin 09-25-2010 08:25 AM

Hello Sasha :)

Many thanks for your research and your answer; I would have been stuck without it.

The key information was that the value of ATTRS{<whatever>} is represented by $attr{<whatever>} not $attrs{<whatever>}. After finding this solution I did not explore capitalisation, that is $ATTR{<whatever>}.

As for the "simple printf-like string substitutions" of the udev man page, the accent should be on simple rather than printf-like! Experimentation showed that the %* tokens that do look like printf "conversion specifications" (because they begin with a %) do not work as conversion specifications but as synonyms. An example may make that clearer. I found that using $major was functionally equivalent to your use of %M.

So what is printf-like? Perhaps only that %% must be used to get a % character (and $$ to get a $ character) and that length may be specified. As it say on the man page, "The count of characters to be substituted may be limited by specifying the format length value. For example, %3s{file} will only insert the first three characters of the sysfs attribute". I did not explore this, nor whether it works with the $* tokens as well as the %* tokens.

And what is not printf-like? The usage is not 'format string', value1, value2, . Only the format string is required and it includes the required values. Here's the RUN+= I ended up with.
Code:

RUN+="/lib/udev/local/usb_hdd_for_bacula_sync.sh -d $major $minor '$attr{product}' '$attr{serial}'"
The single quotes were needed in case the product or serial values had embedded whitespace.

If I have understood correctly, your code should work identically without the ",$major,$minor,$attr{manufacturer}"

Best

Charles

GrapefruiTgirl 09-25-2010 08:49 AM

Hey there :)

Glad you got a working solution. And, I agree - the manpage, for one thing, doesn't really go out of its way to explain this "printf-like" thing they describe -- AND the printf-ness they describe is not as printf-like as we might be used to. It does resemble printf though. A couple examples in the man-page would be welcome.

Until your thread/question, I had never had reason to look into this before (passing attrs along to another program from udev), but it looked like a good opportunity to try/learn something else about udev - and I did. And you improved on that with your final RUN+= statement by showing that the %M parts aren't needed, unless maybe one wants that length-limiting or similar, such as %3s{file}. Otherwise just inserting the variables directly into the string should work. I now believe I mis-interpreted the man-page, and incorrectly thought that both the %X and the $xyz were required to produce a given attr in the output (i.e. the %x would be replaced with the $xyz) when in fact, it appears the two are interchangeable. And that said, I wonder now why my rule worked at all! :D

It looks like you were on the right track already :) and just needed the $attrs changed to $attr. But, I can remember some time ago when the man-page said to use ATTR in the matching rules themselves, but in reality, ATTRS was what worked (maybe a bug/oversight??).

Compared to say, basic scripting for example, which you/I could throw something together and be pretty confident it will basically work, udev rules are always (for me at least) something that one can't just write and save the file and expect it to work; the rules need to be tested to make sure not only that we created a syntactically correct rule, but that the syntax that worked on udev version $ABC is still the right syntax for udev version $TODAY. It's that moving target thing. :)

Thanks for your feedback. Later on today, I plan to do a little more testing on this, so may post a few variations of the RUN+= thing to compare %X to $XYZ to see what works (and what doesn't).

Cheerios :)

GrapefruiTgirl 09-25-2010 08:53 AM

P.S. -

Quote:

And what is not printf-like? The usage is not 'format string', value1, value2, … . Only the format string is required and it includes the required values. Here's the RUN+= I ended up with.
I'm not big into C programming, but I seem to recall, maybe wrongly, seeing strings printed in C by doing something like:
Code:

printf ("Hello there %s, my name is %s.\n",name1,name2)
So that's what led me down the path I took.

catkin 09-25-2010 03:54 PM

Yes, I vaguely recall something like that and, given the man page's "printf-like", I thought you had got it; only experimentation revealed something different.

GrapefruiTgirl 09-25-2010 05:30 PM

Well I have tried a dozen or so different printf-like ways of writing the RUN statement, and no way no how can I make anything occur other than a standard substitution; %x works identically to $xyzzz, i.e. the % method and the $ method both work, and both produce the same result. Formatting, such as the '%3s{file}', does not work.

I have noted that my (udev version 153) manpage for `udev` does not have that final piece:
Quote:

The count of characters to be substituted may be limited by specifying the format length value. For example, '%3s{file}' will only insert the first three characters of the sysfs attribute.
I quoted the above from http://linux.die.net/man/7/udev but I see no version number there, nor a revision date on the page.

catkin 09-26-2010 02:28 AM

It might be a typo in the man page; %s3<whatever> would be more printf-like.

GrapefruiTgirl 09-26-2010 06:43 AM

I did try mixing it up as you suggested; still no go. Either way I get a literal string of the %??{file}.

A 'typo' is possible, but I feel it isn't a typo since the entire clause is not there; I figure it was removed. It *might* (still?) work in your version of udev though, if/since it is present in your man-page.

Oh well - either way, you got your bit working now; and fiddling with this has learned me a couple new little things about udev rules, and was a good refresher/update opportunity: my udev tends to go un-fiddled-with until something stops working in some new version-- and the research begins to figure out what has changed :)

Best regards,
Sasha


All times are GMT -5. The time now is 10:25 PM.