Udev rule mount usb drive automatically - nutthawit/alpine-dotfile GitHub Wiki

In this tutorial, we will configure eudev to automatically mount the USB drive to /mnt/btr_backup whenever it is plugged in.

Install eudev

apk add eudev eudev-doc

Start by write the simple script for udev that triggers a custom event

udev stands for Userspace Device Management. udev is now integrated into systemd, while eudev is a fork of udev created primarily to decouple it from systemd.

Create file on /usr/local/bin/simple-script

touch /usr/local/bin/simple-script && chmod +x /usr/local/bin/simple-script
vi /usr/local/bin/simple-script

Add following content:

#!/bin/ash

/bin/date >> /tmp/udev.log

Save and test the script

trigger.sh

cat /tmp/udev.log
Tue Oct 31 01:05:28 NZDT 2035

Next step is to make udev trigger the script

Install eudev by the setup script

apk add alpine-conf
setup-devd udev

# add eudev man pages
apk add eudev-doc

Read more on https://wiki.alpinelinux.org/wiki/Eudev#Setup_script

With the udevadm monitor command, you can tap into udev in real time and see what it sees when you plug in different devices

udevadm monitor

The monitor function prints received events for:

  • UDEV: the event udev sends out after rule processing
  • KERNEL: the kernel uevent

You will notice that the type of event is an add event.

If you don't know where your thumb drive is plugged in, you can use this command:

dmesg | tail | grep -i sd*

If that command returned sda: sda1, for instance, you know the kernel has assigned you thumb drive the sdb label.

Or you can use lsblk command.

Now you can view udev information about the device using:

udevadm info -a -n /dev/sda | less

The udevadm info process reports on a device (specified by the device path), then "walks" up the chain of parent devices.

  looking at device '/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2:1.0/host2/target2:0:0/2:0:0:0/block/sda':
    KERNEL=="sda"
    SUBSYSTEM=="block"
    DRIVER==""
    ATTR{ext_range}=="256"
    ATTR{range}=="16"
    ATTR{partscan}=="1"
    ATTR{alignment_offset}=="0"
    ATTR{diskseq}=="26"
    ATTR{ro}=="0"

Device hierarchy

The Linux kernel actually represents devices in a tree-like structure, and this information is exposed through sysfs and useful when writing rules. For example, the device representation of my hard disk device is a child of the SCSI disk device, which is in turn a child of the Serial ATA controller device, which is in turn a child of the PCI bus device. It is likely that you will find yourself needing to refer to information from a parent of the device in question, for example the serial number of my hard disk device is not exposed at the device level, it is exposed by its direct parent at the SCSI disk level

Your job is to pick out parts of udev's report about a device that are most unique to that device, then tell udev to trigger your script when those unique attributes are detected.

Now create a custom udev rule to trigger simple-script

vi /etc/udev/rules.d/10-local.rules

Files in /etc/udev/rules.d/ are parsed in lexical order, and in some circumstances, the order in which rules are parsed is important. In general, you want your own rules to be parsed before the defaults, so I suggest you create a file at /etc/udev/rules.d/10-local.rules and write all your rules into this file.

Add following content:

SUBSYSTEM=="block", ACTION=="add", RUN+="/usr/local/bin/simple-script"

Save the file and run test using udevadm test /dev/sda. Your output should look like this:

calling: test
version 3.2.14
This program is for debugging only, it does not run any program
specified by a RUN key. It may show incorrect results, because
some values may be different, or not available at a simulation run.

 does not exist, please run udevadm hwdb --update
Load module index
timestamp of '/etc/udev/rules.d' changed
Reading rules file: /etc/udev/rules.d/10-local.rules
Reading rules file: /usr/lib/udev/rules.d/50-udev-default.rules
Reading rules file: /usr/lib/udev/rules.d/60-autosuspend.rules
Reading rules file: /usr/lib/udev/rules.d/60-block.rules

Counting backward from the end of the output to line 4, you will see that your rule is being read without error.

If you encounter an error, the output will look like this:

invalid key/value pair in file /etc/udev/rules.d/10-local.rules on line 1, starting at character 59 (',')

This occurred because I removed the double quotation mark (") at the end of the line.

SUBSYSTEM=="block", ATTRS{idVendor}=="0951", ACTION=="add", RUN+="/usr/local/bin/simple-script

Now unplug your thumb drive, and reboot a Linux machine.

Theoretically, you can just issue udevadm control --reload, which should load all rules, but at this stage in the game, it's best to eliminate all variables. Udev is complex enough, and you don't want to be lying in bed all night wondering if that rule didn't work because of a syntax error or if you just should have rebooted. So reboot regardless of what your POSIX pride tells you.

When your system is back online, plug in your thumb drive and run following command:

cat /tmp/udev.log

Tue Oct 31 01:35:28 NZDT 2035

If you see a very recent date and time returned from /tmp/udev.log, udev has successfully triggered your script.

Since the KERNEL label of sdb can change depending upon how many other drives were plugged in before you plugged that thumb drive in, that's not the optimal parent attribute for a udev rule.

For more specific, we can use Device - Product Vendor ID. Run following command:

lsusb

Bus 001 Device 001: ID 1d6b:0002 Linux 6.12.49-0-lts xhci-hcd xHCI Host Controller
Bus 001 Device 003: ID 13d3:5a11 Azurewave USB2.0 VGA UVC WebCam
Bus 001 Device 004: ID 13d3:3529 Realtek Bluetooth Radio
Bus 002 Device 001: ID 1d6b:0003 Linux 6.12.49-0-lts xhci-hcd xHCI Host Controller
Bus 001 Device 002: ID 0bda:0129 Generic USB2.0-CRW
Bus 001 Device 007: ID 0951:1666 Kingston DataTraveler 3.0

In this example, the 0951:1666 before Kingston DataTraveler 3.0. denotes the idVendor and idProduct attributes.

Now you can now include these attributes in your rule.

SUBSYSTEM=="block", ATTRS{idVendor}=="0951", ACTION=="add", RUN+="/usr/local/bin/simple-script"

The ATTRS{idVendor} is a parent attribute (retrieved by: udevadm info -a -n /dev/sda | less). If an attribute used to specify your device is not exposed at the device level, you can also use it from its parent level.

Test this (yes, you should still reboot, just to make sure you're getting fresh reactions from udev), and it should work the same as before.

This tutorial is inspried by this article, with added information relevant to Alpine Linux.


References: