0

I am trying to implement a custom function that upon attachment of a USB drive scans all filesystems it contains and then performs operations based on the file system type detected. I went the "recommended" road to write a udev rule that triggers an instantiated systemd "oneshot" service for the device node, which in turn executes the shell script that "does all the magic (TM)" (for reasons of platform independence, a compiled program was not considered an option here).

ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", RUN{program}="/bin/systemctl start usb-drive-manager@$devnode.service"

with

[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/usr/local/bin/usb_drive_manager.sh attach %I
ExecStop=/usr/local/bin/usb_drive_manager.sh detach %I

Inside the shell script, I perform an ls /sys/<...>/sdX/sdX* on the drive's device path to locate any partitions and then query information on these partitions by calling

udevadm info /dev/sdXn

(where n is the partition number) for every processed partition.

The problem is now that while this works during "coldplug" tests of the shell script, it does not when the script is triggerd from the udev rule because at the time the udev event for the drive is processed, the information concerning the partitions on the drive is not yet gathered, i.e. the call to udevadm info returns only rudimentary information:

P: /devices/< ... >/block/sdb/sdb1
N: sdb1
E: DEVNAME=/dev/sdb1
E: DEVPATH=/devices/< ... >/block/sdb/sdb1
E: DEVTYPE=partition
E: MAJOR=8
E: MINOR=17
E: SUBSYSTEM=block

and all relevant information, in particular the ID_FS_TYPE and ID_FS_LABEL environment variables are (still) missing. Since calling udevadm settle while processing udev events is a bad idea (and didn't help, either), and even a polling loop with 0.5s sleeps betwenn calls to udevadm info didn't work (it took around 1 minute until the information was finally available), I am a bit at a loss here.

Unfortunately, rewriting the udev rule so that it applies to partitions instead of drives is also undesirable since there are cases where people create the file system on the entire USB device instead of creating a single partition that spans the entire device which then contains the file system.

The question is now whether

  • it is possible to delay processing of a udev rule for a given device until all children of that device have been processed, or
  • there is a system call that I could use inside the shell script that "waits" for all child events (if any!) to be finished before going on to query the udev data

I reckon that this is quite a long question now; all help is very much appreciated.

AB

P.S. This is my first post here; I hope it is relevant enough and I did not overlook any trivial solution.

0

After some more research, which pointed me to the use of blkid in udev rules (see e.g. this Wiki article, unfortunately only available in German), I found out that by calling

blkid -o udev -p /dev/sdXn

instead of

udeavdm info /dev/sdXn

inside the systemd-triggered script it is possible to retrieve complete information about even the child devices of the USB stick whose "add" rule is being processed.

It would seem that the -p option here is the key, as it switches to an active probing mode in which the device is actually read out, instead of relying on cached information (cf. e.g. the man page or the source code of blkid).

The -o udev option simply serves to format the output in a way similar to the udevadm call, although it is not a 100% drop-in replacement as the leading identifier labels of the udevadm output (such as E:, P:, etc.) are missing here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.