10

I'm having trouble with udev rules not running. Here's an example:

I have a rule /etc/udev/rules.d/99-test.rules which contains:

ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x8086", RUN+="/sayhi"

And sayhi just has:

#!/bin/bash
date +"%Y-%m-%d %H:%M:%S,%3N" >> /saidhi

This being an Intel machine, I obviously have many vendor 0x8086 PCI devices:

root@imtrobot:~# lspci -n |grep 8086
00:00.0 0600: 8086:2770 (rev 02)
00:02.0 0300: 8086:2772 (rev 02)
00:1d.0 0c03: 8086:27c8 (rev 01)
[ etc. 12 lines total ]

And yet, when I boot, /saidhi will either not be created at all, or will have 1 or 2 date lines in it.

If, after booting, I run udevadm trigger --action=add --subsystem-match=pci then /saidhi will get exactly the right number of dates added to it.

Why doesn't this work during the boot process?

Braiam
  • 67,791
  • 32
  • 179
  • 269
Daniel
  • 460
  • 1
    My guess is that udev is running so quickly/early that the root filesystem isn't mounted readwrite yet. If so, is there a way to ask a rule not to run until filesystems are ready? (Obviously, the above example is a contrived one; I have a real case where I need to do something to the filesystem when a certain device is detected on boot.) – Daniel Apr 10 '14 at 01:40
  • 1
    You could either hardcode in a time to wait, e.g. with sleep 30 or how long is appropriate. Or you could (possibly?) poll to see if the directory exists with [ -e / ]. I'm not sure if you can look at /, so maybe [ -e /tmp ] instead. – Sparhawk Apr 10 '14 at 01:44
  • Adding sleep 30 before the date line in the sayhi script had no effect; so maybe that's not the problem. – Daniel Apr 10 '14 at 01:55
  • Oh, actually, now I think about it, my comments don't make any sense at all. If / isn't mounted, then the udev script would never be called at all. Do you boot into x? Perhaps it'd be better to run scripts when the GUI loads up? – Sparhawk Apr 10 '14 at 02:02
  • Not sure what you mean "when the GUI loads up". This is something that I need to have run when a certain PCI device is enumerated. (Specifically, a pci4e card). – Daniel Apr 10 '14 at 02:05
  • udev rules act immediately after startup, possibly too early to act as you want. (I'm not sure why this is really, as they should.) As a workaround, you could use an autostart file instead, that activates later, when the X server (e.g. Unity) starts up. It's not ideal, as udev should work, but it's a workaround. – Sparhawk Apr 10 '14 at 02:12
  • 1
    The really interesting thing is this works fine on the exact same system, cloned to a slower (spinning, instead of SSD) disk. – Daniel Apr 10 '14 at 03:09
  • Ah, very interesting. I wonder if there is some kind of race condition occurring here. I still can't propose a proper fix though, beyond the autostart one above. – Sparhawk Apr 10 '14 at 03:11

3 Answers3

1

As mentioned by others, the processes started by udev's RUN= directive should be short-running. I would like to suggest another simpler way of decoupling long-running process from udev by using system scheduler at command:

ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x8086", RUN+="/usr/bin/at -M -f /sayhi now"

Just make sure that your /sayhi script is /bin/sh compatible - this is the shell that at uses.

Alex P.
  • 111
1

I actually have a way that will wait just the right amount of time, not an arbitrary 30sec. I did it on Raspberry Pi to automatically mount all connected USB disks upon connection but also on boot time.

The rule is similar to yours:

$ sudo cat /etc/udev/rules.d/10-usb_automount.rules 
KERNEL=="sd*", RUN+="/home/pi/bin/usb-automount"

Now the script is actually a recursive call (and I know this is evil):

$ cat /home/pi/bin/usb-automount
#!/bin/sh

ROOT_RW=`mount | grep 'dev/root' | grep -E '\(.*rw.*\)'`

if [ -z "$ROOT_RW" ]; then
 sleep 3 
 /home/pi/bin/usb-automount & disown
else
 /home/pi/bin/usb-automount.sh
fi

Note that the "grep 'dev/root'" is specific to Raspbian OS, so on Ubuntu you will need to design your own grep to detect the rootfs (or even better design some universal grep). Notice that the script will call itself in the background and exit and only if the rootfs is "rw" will call the right mounting script. The script "/home/pi/bin/usb-automount.sh" does the actual mounting or in your case the logging.

Note this script still takes 3 seconds to execute, so you may further optimize by changing to:

if [ -z "$ROOT_RW" ]; then
 ( sleep 3; /home/pi/bin/usb-automount ) & disown
else
 /home/pi/bin/usb-automount.sh
fi

However I never checked that and do not know if this will work as expected (I am no scripting guru).

Fëamarto
  • 111
0

I taught of same cause as @dmd, PCI uevents come before filesystem re-mount as rw. (But sometimes, some of PCI uevents come after, race condition, working in parallel)

dmesg | grep -i -e mount -e pci

@Sparhawk sleep idea seems good to me. I think this why it doesn't work (Ref: man udev):

This can only be used for very short-running foreground tasks. Running an event process for a long period of time may block all further events for this or a dependent device.

Starting daemons or other long running processes is not appropriate for udev; the forked processes, detached or not, will be unconditionally killed after the event handling has finished.

So, I created new script that start & disown the script that has sleep command. Actually, It does WORK!

$ ls -l /sa*
-rw-r--r-- 1 root root 1104 Oct 24 12:37 /saidhi
-rwxr-xr-x 1 root root   29 Oct 24 12:31 /sayhi
-rwxr-xr-x 1 root root   62 Oct 24 12:28 /sayhi2

$ cat /sayhi
#!/bin/bash
/sayhi2 & disown

$ cat /sayhi2 
#!/bin/bash
sleep 30
date +"%Y-%m-%d %H:%M:%S,%3N" >> /saidhi

$ cat /etc/udev/rules.d/99-test.rules 
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x8086", RUN+="/sayhi"
user.dz
  • 48,105