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?

8
  • 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, 2014 at 1: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, 2014 at 1: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, 2014 at 1: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, 2014 at 2:02
  • 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, 2014 at 3:09

3 Answers 3

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).

1
  • Can't you just remove the whole else... part and let only the if...fi?
    – DrBeco
    May 4, 2020 at 12:46
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.

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"

You must log in to answer this question.

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