In udev rules, the %k, %b, %n variables are nice and all, but you can also use the variables you’re comparing and setting such as ID_FS_TYPE, KERNEL, SUBSYSTEM, PHYSDEVPATH, etc.
Within a rule, you can compare against them with ENV{VARIABLE} without a dollar sign. And within a RUN or PROGRAM statement, you can access them with the dollar sign.
When you run a command in a udev rule, there’s nothing stopping you from calling a shell and executing a few commands without actually calling a standalone script to do the dirty work like the example above. This makes it more portable as you only need the rule file. No external programs necessary.
SUBSYSTEM==”usb”, $ENV{ID_FS_LABEL}==”vfat”, RUN+=”sh -c ‘if [ ! -d /media/$ENV{ID_FS_LABEL} ]; then mkdir /media$ENV{ID_FS_LABEL}; fi’”
Depending on your version of udev (and if you’re running in verbose mode), you may get warnings about unknown keys. If you get this, it might be because you’re comparing against DEVTYPE instead of ENV{DEVTYPE}. The rule is completely ignoring your comparison, and will match regardless of what you thought the variable should have equaled.
[2511] add_to_rules: unknown key ‘ID_FS_USAGE’ in /etc/udev/rules.d/51-rootninja-storage.rules:2
[2511] add_to_rules: unknown key ‘DEVNAME’ in /etc/udev/rules.d/51-rootninja-storage.rules:2
[2511] add_to_rules: unknown key ‘ID_TYPE’ in /etc/udev/rules.d/51-rootninja-storage.rules:3
[2511] add_to_rules: unknown key ‘PHYSDEVBUS’ in /etc/udev/rules.d/51-rootninja-storage.rules:3
This is bad because although you may continue to match with the rule, the behavior is not as expected. If you were relying on the unknown key to filter out unwanted matches, you fail.
Try killing udevd and run it in the foreground with –debug or –verbose depending on your version of udev. This can help with problems especially in the external program. A misplaced quote or missing semi-colon in a perl script will screw you up.
# ps -ef | grep udevd
root 364 1 0 May17 ? 00:00:00 /sbin/udevd -d
# kill -9 364
# udevd –debug
udev_device_new_from_syspath: device 0×86cc900 has devpath ‘/devices…
udev_watch_restore: restoring old watch on ‘/dev/sdb5′
udev_watch_begin: adding watch on ‘/dev/sdb5′
main: initialize max_childs to 375
In addition to telling you whats going on each step of the way, it will also increase the messages written to syslog.
If you write out the array of environment variables from inside an external program, you can get a better understanding of just which part of the device discovery is matching your rule and getting processed. It also gives you an idea of just what other data is out there for you to interact with so you can pick and choose what to do in your custom perl script.
#!/usr/local/bin/perl
open( FILE, “>>/tmp/udevout” );
#open( FILE, “>>/dev/null”);foreach $key (sort keys(%ENV))
{
print FILE “$key=$ENV{$key}\n”;
}
Try executing the program above in a udev rule with a match on SUBSYSTEM==”usb” and you’ll see how it changes. The rule is pretty simple:
SUBSYSTEM==”usb”, PROGRAM=”/usr/local/bin/printenv.pl”
Plug in a usb drive with one partition on it and you’ll match that rule for the device and again for each partition. If you follow up with another rule matching ACTION==”add”, you’ll see you’re matching multiple times too.
Each time the rule matches, the set of environment variables will change.
# udevadmn monitor –environment
# udevinfo -a -p /sys/class/net/eth0
# udevinfo -a -p /sys/block/sdb
# udevinfo -a -p $(udevinfo -q path -n /dev/sdb)
Good!
In my debian Perl found #!/usr/bin/perl, change or comment the PROGRAM first line:
#!/usr/local/bin/perl OR #!/usr/bin/perl
9:51 am
My dear good man,
Yours is the best udev post out there. I have been googling for the past 3 days non-stop 14 hrs a day. Well, the pain has finally paid off thanks to your post.
Keep it up man.
~Philby