0

I have a udev rule that will run a shell script to create a directory and mount a device in read-only mode. The problem is that when the rule runs (when I insert the device), it creates the directory but doesn't mount the device.

Naturally, something must be wrong with the script then. However, I can run the script (I insert the device, delete the directory that is created by the udev rule manually, then run the script manually as well) and it creates the directory and mounts the device just fine.

Relevant section of udev rule (filename = '10-magicusb.rules'):

ENV{MYMOUNT}=="1", RUN+="/etc/udev/scripts/romount.sh"

romount.sh:

#!/bin/bash
mkdir /media/sdb1
/bin/mount /dev/sdb1 -o ro,noatime /media/sdb1

Technically the device name comes from further up in the udev rule (its not hardcoded, trust me). I run a script that creates romount.sh and I pass that script the device with %k. However, that shouldn't be related since the script runs from udev, but stops halfway through execution.

My guess is there is some timing issue going on here. When the rule runs, for some reason it cannot mount the device, but when I do it later manually the system has had time to sort things out I guess. I added a sleep 10 to the top of the bash script to no avail.

Thank you in advance.

EDIT 1

Based on what David G. has posted, I did some testing with the improved script so now romount.sh looks like this:

#!/bin/bash
mkdir /media/sdb1
(
    echo 'before while iteration' > /etc/udev/scripts/iteration.txt
    while [[ ! -b /dev/sdb1 ]]
    do
        sleep 1
        echo 'iteration performed' > /etc/udev/scripts/iteration.txt
    done
    /bin/mount /dev/sdb1 -o ro,noatime /media/sdb1
) &

and the resulting iteration.txt file has: before while iteration only. Which means the condition for the while loop is never triggered. This means the device node is available at time of execution, right?

EDIT 2

I finally got it to work with the second answer here: Udev rule to mount disk does not work

Adding PrivateMounts=No to the systemd-udevd.service worked for me.

  • It looks like it's on the same lines. When I look into /proc/<systemd-udev PID>/mountinfo, I see the following: 377 81 8:17 / /media/sdb1 ro, noatime shared:200 - vfat /dev/sdb1 ro,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro. So this seems to be saying that the device has been mounted through systemd-udev, correct? I tried to follow the proposed solution of creating the .service or .conf files for systemd-udev but even after reloading it still doesn't seem to work. – Christopher Sinclair Jul 06 '20 at 17:34

1 Answers1

0

I suspect that the issue is that the script is run before the device node is created. Try something like (i.e. without the hardcoding):

#!/bin/bash
mkdir /media/sdb1
(
    while [[ ! -b /dev/sdb1 ]]
    do
        sleep 1
    done
    /bin/mount /dev/sdb1 -o ro,noatime /media/sdb1
) &

The important part is the backgrounded subshell.

Depending on what udev does, you might have issues with needing to do something with stdin, stdout, and stderr. You might also need to ignore SIGHUP or some other signal (though probably not).

David G.
  • 1,369
  • This is a good suggestion. I did this and left it plugged in for about 30 seconds before trying to mount manually.

    Therefore, it still doesn't work. I tried to add some custom logging in the udev rule:

    ENV{MYMOUNT}=="1", RUN+="/etc/udev/scripts/romount.sh 2> /etc/udev/scripts/romount-output.txt" but that file doesn't get created either.

    – Christopher Sinclair Jul 06 '20 at 12:42
  • Please see my edits above. I did some testing with the improved script you have and it seems the while loop is never triggered - thus the device should be ready by time of execution. – Christopher Sinclair Jul 06 '20 at 15:18
  • @ChristopherSinclair Well it is a matter of timing. The echo actually slows things down a lot, compared to the time needed to make the node. If you removed the early echo in the subprocess and added an echo in the main process after the subprocess is created, then I think you would see it do an iteration. I would recommend keeping the loop, though you might make it do sleep 0.05 instead of sleep 1 – David G. Jul 11 '20 at 00:07