0

I'd like to flash SD cards with a custom script (writes partition table, then copies over a rootfs, etc.) whenever an SD card is inserted.

At first glance this seemed straightforward -- I'd just use a udev rule to detect the SD card then call the script. The first problem is that since the reader already exists, it doesn't trigger an "add" just a "change", and not only that, it would cause multiple events and trigger the script multiple times. After some more filters I was able to get a simple script to trigger only once (/etc/udev/rules.d/99-sd-detect.rules):

ACTION=="change", KERNEL=="sd[b-z]", SUBSYSTEM=="block", ENV{DISK_MEDIA_CHANGE}=="1", ENV{DEVTYPE}=="disk", ATTRS{idVendor}=="8564", ATTRS{idProduct}=="4000", ENV{ID_DRIVE_FLASH_CF}=="1", RUN+="/bin/sh -c '/root/udev_flash_sd.sh %E{DEVNAME}'"

However, when I actually have the script write data to the SD card it is killed after a few seconds. Apparently in 2012 udev made changes that kill processes that don't return after a few seconds. I tried various forking/detaching/nohup etc. trying to keep it running, but to no avail.

It seems the proper solution is to have it call a systemd service to run anything that takes longer, e.g., something like:

ACTION=="change", KERNEL=="sd[b-z]", SUBSYSTEM=="block", ENV{DISK_MEDIA_CHANGE}=="1", ENV{DEVTYPE}=="disk", ATTRS{idVendor}=="8564", ATTRS{idProduct}=="4000", ENV{ID_DRIVE_FLASH_CF}=="1", TAG+="systemd", PROGRAM="/bin/systemd-escape -p --template=flash_sd@.service $env{DEVNAME}", ENV{SYSTEMD_WANTS}+="%c"

Where /etc/systemd/system/flash_sd@.service has:

[Unit]
BindTo=%i.device
After=%i.device

[Service]
Type=oneshot
TimeoutStartSec=360
ExecStart=/root/udev_flash_sd.sh /%I

This works if you call "systemctl start flash_sd@dev-sde.service", which is also what the PROGRAM part of the udev rule outputs (at least for /dev/sde). After much searching it looks like udev will not call the service on a "change" event, only an "add". ("udevadm monitor -p" shows the SYSTEMD_WANTS and tag correctly, not to mention testing a simple add rule that calls a systemd service works fine.)

So, how do I call a custom flashing script automatically upon insertion of an SD card?

0

Edit: It seems the best method is to pipe your command to "at now" to keep udev from killing it. E.g., "echo mycommand.sh | at now".

Originally it seemed that "& disown" would work, but it actually encounters the same problem as udev killing it, just after 300s (5m) rather than ~2-3s.

0

Not an answer, but the reason your rules only work for add and not for change is that systemd has chosen to implement that limitation. E.g. see the systemd.device manpage, which says:

Note that systemd will only act on Wants= dependencies when a device first becomes active. It will not act on them if they are added to devices that are already active. Use SYSTEMD_READY= (see below) to configure when a udev device shall be considered active, and thus when to trigger the dependencies.

IOW the SYSTEMD_WANTS is not an instruction for systemd to start a service whenever it occurs, it just adds a Wants directive to the autogenerated device unit, and Wants directives only take effect when a unit is activated.

The manpage also suggests using SYSTEMD_READY to control when a device is made active, but I think that would require setting it to 0 first and then back to 1, which probably needs 2 separate udev events (not sure if your device gives an event when the SD card is unplugged).

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.