Ubuntu – `udevadm test` shows command should run on USB disk add, but it doesn’t

udev

I'd like to have a backup script execute when certain external USB drives get mounted. I'm trying to achieve this with udev.

What I've done so far:

Identified my USB drive using sudo udevadm info --attribute-walk --name /dev/sda, the output of which is:

  looking at device '/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5.2/1-5.2.3/1-5.2.3:1.0/host0/target0:0:0/0:0:0:0/block/sda':
    KERNEL=="sda"
    SUBSYSTEM=="block"
    DRIVER==""
    ATTR{size}=="1953525168"
    ATTR{events_async}==""
    ATTR{ext_range}=="256"
    ATTR{range}=="16"
    ATTR{inflight}=="       0        0"
    ATTR{hidden}=="0"
    ATTR{ro}=="0"
    ATTR{discard_alignment}=="0"
    ATTR{alignment_offset}=="0"
    ATTR{capability}=="50"
    ATTR{events_poll_msecs}=="-1"
    ATTR{removable}=="0"
    ATTR{events}==""
    ATTR{stat}=="     445     7963    19565     3971        7        1       64       21        0     1036     3204        0        0        0        0"

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5.2/1-5.2.3/1-5.2.3:1.0/host0/target0:0:0/0:0:0:0':
    KERNELS=="0:0:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS=="sd"
    ATTRS{state}=="running"
    ATTRS{inquiry}==""
    ATTRS{evt_inquiry_change_reported}=="0"
    ATTRS{evt_capacity_change_reported}=="0"
    ATTRS{device_busy}=="0"
    ATTRS{evt_mode_parameter_change_reported}=="0"
    ATTRS{evt_lun_change_reported}=="0"
    ATTRS{ioerr_cnt}=="0xc"
    ATTRS{iocounterbits}=="32"
    ATTRS{eh_timeout}=="10"
    ATTRS{vendor}=="ST310005"
    ATTRS{queue_depth}=="1"
    ATTRS{device_blocked}=="0"
    ATTRS{blacklist}==""
    ATTRS{evt_media_change}=="0"
    ATTRS{scsi_level}=="3"
    ATTRS{evt_soft_threshold_reached}=="0"
    ATTRS{iodone_cnt}=="0x1f8"
    ATTRS{queue_type}=="none"
    ATTRS{timeout}=="30"
    ATTRS{model}=="20AS            "
    ATTRS{max_sectors}=="240"
    ATTRS{iorequest_cnt}=="0x1f8"
    ATTRS{type}=="0"
    ATTRS{rev}=="    "
    ATTRS{dh_state}=="detached"

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5.2/1-5.2.3/1-5.2.3:1.0/host0/target0:0:0':
    KERNELS=="target0:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS==""

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5.2/1-5.2.3/1-5.2.3:1.0/host0':
    KERNELS=="host0"
    SUBSYSTEMS=="scsi"
    DRIVERS==""

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5.2/1-5.2.3/1-5.2.3:1.0':
    KERNELS=="1-5.2.3:1.0"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb-storage"
    ATTRS{bNumEndpoints}=="02"
    ATTRS{supports_autosuspend}=="1"
    ATTRS{bInterfaceNumber}=="00"
    ATTRS{bInterfaceClass}=="08"
    ATTRS{interface}=="MSC Bulk-Only Transfer"
    ATTRS{bInterfaceProtocol}=="50"
    ATTRS{authorized}=="1"
    ATTRS{bAlternateSetting}==" 0"
    ATTRS{bInterfaceSubClass}=="06"

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5.2/1-5.2.3':
    KERNELS=="1-5.2.3"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{maxchild}=="0"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{authorized}=="1"
    ATTRS{tx_lanes}=="1"
    ATTRS{manufacturer}=="Lomega"
    ATTRS{serial}=="50F26FFFFFFF"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{devpath}=="5.2.3"
    ATTRS{bmAttributes}=="c0"
    ATTRS{configuration}=="USB Mass Storage"
    ATTRS{quirks}=="0x0"
    ATTRS{ltm_capable}=="no"
    ATTRS{busnum}=="1"
    ATTRS{urbnum}=="1569"
    ATTRS{removable}=="unknown"
    ATTRS{bcdDevice}=="0000"
    ATTRS{speed}=="480"
    ATTRS{idProduct}=="0370"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{rx_lanes}=="1"
    ATTRS{bDeviceClass}=="00"
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{product}=="External HD"
    ATTRS{devnum}=="19"
    ATTRS{idVendor}=="059b"
    ATTRS{version}==" 2.00"
    ATTRS{bMaxPower}=="2mA"

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5.2':
    KERNELS=="1-5.2"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{tx_lanes}=="1"
    ATTRS{bmAttributes}=="e0"
    ATTRS{urbnum}=="200"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{quirks}=="0x0"
    ATTRS{manufacturer}=="VIA Labs, Inc.         "
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{rx_lanes}=="1"
    ATTRS{devnum}=="6"
    ATTRS{configuration}==""
    ATTRS{bDeviceClass}=="09"
    ATTRS{busnum}=="1"
    ATTRS{version}==" 2.10"
    ATTRS{speed}=="480"
    ATTRS{idVendor}=="17ef"
    ATTRS{authorized}=="1"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bMaxPower}=="0mA"
    ATTRS{bDeviceProtocol}=="02"
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{maxchild}=="4"
    ATTRS{bcdDevice}=="0a74"
    ATTRS{removable}=="unknown"
    ATTRS{devpath}=="5.2"
    ATTRS{idProduct}=="3071"
    ATTRS{product}=="USB2.0 Hub             "
    ATTRS{ltm_capable}=="no"

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-5':
    KERNELS=="1-5"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{product}=="USB2.0 Hub             "
    ATTRS{devnum}=="3"
    ATTRS{rx_lanes}=="1"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{bmAttributes}=="e0"
    ATTRS{devpath}=="5"
    ATTRS{speed}=="480"
    ATTRS{bDeviceClass}=="09"
    ATTRS{idProduct}=="3071"
    ATTRS{removable}=="removable"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bcdDevice}=="0a73"
    ATTRS{quirks}=="0x0"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{busnum}=="1"
    ATTRS{bMaxPower}=="0mA"
    ATTRS{configuration}==""
    ATTRS{tx_lanes}=="1"
    ATTRS{idVendor}=="17ef"
    ATTRS{authorized}=="1"
    ATTRS{manufacturer}=="VIA Labs, Inc.         "
    ATTRS{ltm_capable}=="no"
    ATTRS{urbnum}=="52"
    ATTRS{bDeviceProtocol}=="02"
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{maxchild}=="5"
    ATTRS{version}==" 2.10"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bMaxPacketSize0}=="64"

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1':
    KERNELS=="usb1"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{version}==" 2.00"
    ATTRS{tx_lanes}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{busnum}=="1"
    ATTRS{bcdDevice}=="0500"
    ATTRS{ltm_capable}=="no"
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{serial}=="0000:00:14.0"
    ATTRS{configuration}==""
    ATTRS{devpath}=="0"
    ATTRS{idProduct}=="0002"
    ATTRS{devnum}=="1"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bmAttributes}=="e0"
    ATTRS{bMaxPower}=="0mA"
    ATTRS{product}=="xHCI Host Controller"
    ATTRS{speed}=="480"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{maxchild}=="12"
    ATTRS{authorized}=="1"
    ATTRS{urbnum}=="92"
    ATTRS{idVendor}=="1d6b"
    ATTRS{bDeviceProtocol}=="01"
    ATTRS{quirks}=="0x0"
    ATTRS{bDeviceClass}=="09"
    ATTRS{manufacturer}=="Linux 5.0.0-15-generic xhci-hcd"
    ATTRS{interface_authorized_default}=="1"
    ATTRS{authorized_default}=="1"
    ATTRS{rx_lanes}=="1"
    ATTRS{removable}=="unknown"

  looking at parent device '/devices/pci0000:00/0000:00:14.0':
    KERNELS=="0000:00:14.0"
    SUBSYSTEMS=="pci"
    DRIVERS=="xhci_hcd"
    ATTRS{revision}=="0x30"
    ATTRS{d3cold_allowed}=="1"
    ATTRS{enable}=="1"
    ATTRS{ari_enabled}=="0"
    ATTRS{broken_parity_status}=="0"
    ATTRS{subsystem_device}=="0x2279"
    ATTRS{local_cpulist}=="0-7"
    ATTRS{irq}=="127"
    ATTRS{vendor}=="0x8086"
    ATTRS{msi_bus}=="1"
    ATTRS{device}=="0x9ded"
    ATTRS{dbc}=="disabled"
    ATTRS{local_cpus}=="ff"
    ATTRS{consistent_dma_mask_bits}=="64"
    ATTRS{numa_node}=="-1"
    ATTRS{dma_mask_bits}=="64"
    ATTRS{class}=="0x0c0330"
    ATTRS{subsystem_vendor}=="0x17aa"
    ATTRS{driver_override}=="(null)"

  looking at parent device '/devices/pci0000:00':
    KERNELS=="pci0000:00"
    SUBSYSTEMS==""
    DRIVERS==""

Based on this info, I created a file in /etc.udev/rules.d/10.autobackup.rules with:

SUBSYSTEM=="block", ACTION=="add", ATTRS{serial}=="50F26FFFFFFF", RUN+="/usr/bin/touch ~david/test_udev.txt"

After reloading the rules with sudo udevadm control --reload and running udevadm test /block/sda I get:

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.

Load module index
Parsed configuration file /usr/lib/systemd/network/99-default.link
Created link configuration context.
Reading rules file: /etc/udev/rules.d/10.autobackup.rules
Reading rules file: /usr/lib/udev/rules.d/39-usbmuxd.rules
Reading rules file: /usr/lib/udev/rules.d/40-usb_modeswitch.rules
Reading rules file: /usr/lib/udev/rules.d/40-vm-hotadd.rules
Reading rules file: /usr/lib/udev/rules.d/50-apport.rules
Reading rules file: /usr/lib/udev/rules.d/50-firmware.rules
Reading rules file: /usr/lib/udev/rules.d/50-udev-default.rules
Reading rules file: /usr/lib/udev/rules.d/55-dm.rules
Reading rules file: /usr/lib/udev/rules.d/55-ippusbxd.rules
Reading rules file: /usr/lib/udev/rules.d/56-hpmud.rules
Reading rules file: /usr/lib/udev/rules.d/60-block.rules
Reading rules file: /usr/lib/udev/rules.d/60-cdrom_id.rules
Reading rules file: /usr/lib/udev/rules.d/60-crda.rules
Reading rules file: /usr/lib/udev/rules.d/60-drm.rules
Reading rules file: /usr/lib/udev/rules.d/60-evdev.rules
Reading rules file: /usr/lib/udev/rules.d/60-input-id.rules
Reading rules file: /usr/lib/udev/rules.d/60-inputattach.rules
Reading rules file: /usr/lib/udev/rules.d/60-libfprint0.rules
Reading rules file: /usr/lib/udev/rules.d/60-libgphoto2-6.rules
Reading rules file: /usr/lib/udev/rules.d/60-libsane.rules
Reading rules file: /usr/lib/udev/rules.d/60-pcmcia.rules
Reading rules file: /usr/lib/udev/rules.d/60-persistent-alsa.rules
Reading rules file: /usr/lib/udev/rules.d/60-persistent-input.rules
Reading rules file: /usr/lib/udev/rules.d/60-persistent-storage-dm.rules
Reading rules file: /usr/lib/udev/rules.d/60-persistent-storage-tape.rules
Reading rules file: /usr/lib/udev/rules.d/60-persistent-storage.rules
Reading rules file: /usr/lib/udev/rules.d/60-persistent-v4l.rules
Reading rules file: /usr/lib/udev/rules.d/60-sensor.rules
Reading rules file: /usr/lib/udev/rules.d/60-serial.rules
Reading rules file: /usr/lib/udev/rules.d/61-gdm.rules
Reading rules file: /usr/lib/udev/rules.d/61-gnome-settings-daemon-rfkill.rules
Reading rules file: /usr/lib/udev/rules.d/61-persistent-storage-android.rules
Reading rules file: /usr/lib/udev/rules.d/64-btrfs.rules
Reading rules file: /usr/lib/udev/rules.d/64-xorg-xkb.rules
Reading rules file: /usr/lib/udev/rules.d/65-libwacom.rules
Reading rules file: /usr/lib/udev/rules.d/66-snapd-autoimport.rules
Reading rules file: /usr/lib/udev/rules.d/69-cd-sensors.rules
Reading rules file: /usr/lib/udev/rules.d/69-libmtp.rules
Reading rules file: /usr/lib/udev/rules.d/69-wacom.rules
Reading rules file: /usr/lib/udev/rules.d/70-joystick.rules
Reading rules file: /usr/lib/udev/rules.d/70-mouse.rules
Reading rules file: /usr/lib/udev/rules.d/70-power-switch.rules
Reading rules file: /usr/lib/udev/rules.d/70-printers.rules
Reading rules file: /etc/udev/rules.d/70-snap.core.rules
Reading rules file: /usr/lib/udev/rules.d/70-spice-vdagentd.rules
Reading rules file: /usr/lib/udev/rules.d/70-touchpad.rules
Reading rules file: /usr/lib/udev/rules.d/70-u2f.rules
Reading rules file: /usr/lib/udev/rules.d/70-uaccess.rules
Reading rules file: /usr/lib/udev/rules.d/71-power-switch-proliant.rules
Reading rules file: /usr/lib/udev/rules.d/71-seat.rules
Reading rules file: /usr/lib/udev/rules.d/71-u-d-c-gpu-detection.rules
Reading rules file: /usr/lib/udev/rules.d/73-seat-late.rules
Reading rules file: /usr/lib/udev/rules.d/73-special-net-names.rules
Reading rules file: /usr/lib/udev/rules.d/73-usb-net-by-mac.rules
Reading rules file: /usr/lib/udev/rules.d/75-net-description.rules
Reading rules file: /usr/lib/udev/rules.d/75-probe_mtd.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-cinterion-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-dell-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-ericsson-mbm.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-fibocom-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-haier-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-huawei-net-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-longcheer-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-mtk-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-nokia-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-pcmcia-device-blacklist.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-qdl-device-blacklist.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-sierra.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-simtech-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-telit-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-ublox-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-usb-device-blacklist.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-usb-serial-adapters-greylist.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-x22x-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-zte-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/78-graphics-card.rules
Reading rules file: /usr/lib/udev/rules.d/78-sound-card.rules
Reading rules file: /usr/lib/udev/rules.d/80-debian-compat.rules
Reading rules file: /usr/lib/udev/rules.d/80-drivers.rules
Reading rules file: /usr/lib/udev/rules.d/80-ifupdown.rules
Reading rules file: /usr/lib/udev/rules.d/80-iio-sensor-proxy.rules
Reading rules file: /usr/lib/udev/rules.d/80-libinput-device-groups.rules
Reading rules file: /usr/lib/udev/rules.d/80-mm-candidate.rules
Reading rules file: /usr/lib/udev/rules.d/80-net-setup-link.rules
Reading rules file: /usr/lib/udev/rules.d/80-udisks2.rules
Reading rules file: /usr/lib/udev/rules.d/84-nm-drivers.rules
Reading rules file: /usr/lib/udev/rules.d/85-brltty.rules
Reading rules file: /usr/lib/udev/rules.d/85-hdparm.rules
Reading rules file: /usr/lib/udev/rules.d/85-hplj10xx.rules
Reading rules file: /usr/lib/udev/rules.d/85-nm-unmanaged.rules
Reading rules file: /usr/lib/udev/rules.d/85-regulatory.rules
Reading rules file: /usr/lib/udev/rules.d/89-alsa-ucm.rules
Reading rules file: /usr/lib/udev/rules.d/90-alsa-restore.rules
Reading rules file: /usr/lib/udev/rules.d/90-bolt.rules
Reading rules file: /usr/lib/udev/rules.d/90-console-setup.rules
Reading rules file: /usr/lib/udev/rules.d/90-fwupd-devices.rules
Reading rules file: /usr/lib/udev/rules.d/90-libinput-model-quirks.rules
Reading rules file: /usr/lib/udev/rules.d/90-nm-thunderbolt.rules
Reading rules file: /usr/lib/udev/rules.d/90-pulseaudio.rules
Reading rules file: /usr/lib/udev/rules.d/95-cd-devices.rules
Reading rules file: /usr/lib/udev/rules.d/95-dm-notify.rules
Reading rules file: /usr/lib/udev/rules.d/95-upower-csr.rules
Reading rules file: /usr/lib/udev/rules.d/95-upower-hid.rules
Reading rules file: /usr/lib/udev/rules.d/95-upower-wup.rules
Reading rules file: /usr/lib/udev/rules.d/97-hid2hci.rules
Reading rules file: /usr/lib/udev/rules.d/99-systemd.rules
Rules contain 393216 bytes tokens (32768 * 12 bytes), 38404 bytes strings
31877 strings (265263 bytes), 28376 de-duplicated (230361 bytes), 3502 trie nodes used
Invalid inotify descriptor.
Starting 'ata_id --export /dev/sda'
Process 'ata_id --export /dev/sda' failed with exit code 1.
sda: Failed to create symlink '/dev/disk/by-id/usb-ST310005_20AS_50F26FFFFFFF-0:0.tmp-b8:0' to '../../sda': Permission denied
DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5.2/1-5.2.3/1-5.2.3:1.0/host0/target0:0:0/0:0:0:0/block/sda
DEVNAME=/dev/sda
DEVTYPE=disk
MAJOR=8
MINOR=0
ACTION=add
SUBSYSTEM=block
ID_VENDOR=ST310005
ID_VENDOR_ENC=ST310005
ID_VENDOR_ID=059b
ID_MODEL=20AS
ID_MODEL_ENC=20AS\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
ID_MODEL_ID=0370
ID_REVISION=0000
ID_SERIAL=ST310005_20AS_50F26FFFFFFF-0:0
ID_SERIAL_SHORT=50F26FFFFFFF
ID_TYPE=disk
ID_INSTANCE=0:0
ID_BUS=usb
ID_USB_INTERFACES=:080650:
ID_USB_INTERFACE_NUM=00
ID_USB_DRIVER=usb-storage
DEVLINKS=/dev/disk/by-path/pci-0000:00:14.0-usb-0:5.2.3:1.0-scsi-0:0:0:0 /dev/disk/by-id/usb-ST310005_20AS_50F26FFFFFFF-0:0
ID_PATH=pci-0000:00:14.0-usb-0:5.2.3:1.0-scsi-0:0:0:0
ID_PATH_TAG=pci-0000_00_14_0-usb-0_5_2_3_1_0-scsi-0_0_0_0
TAGS=:systemd:
USEC_INITIALIZED=3351039864
run: '/usr/bin/unshare -m /usr/bin/snap auto-import --mount=/dev/sda'
run: '/usr/bin/touch ~david/test_udev.txt'
run: '/lib/udev/hdparm'
Unload module index
Unloaded link configuration context.

Which appears to indicate that the touch command in my script should be executed when the USB drive gets added (and after mounting the drive, which is a constraint I will need when performing the backup). Yet, next time I add the drive (turning it off then on), no file gets created at ~david/test_udev.txt.

Executing sudo udevadm trigger doesn't get the file to be created either.

The end goal is for a backup command to execute, but at this time I'm just trying to touch a file to get the basics working…

Best Answer

  • Edit: it turns out my specific case/problems were related to my encrypted home dir and using only systemd was all that was needed for it to work, although the unit has to be started on each login. For more info see here.


    Looking into this more, it appears that triggering the backup script (which could be "long running" for some definition of "long") isn't the best approach anyway (it could delay other udev stuff). Instead, it's better to have udev "want" a systemd user unit that will then trigger the actual backup script. Here's what I did:

    Label the drives in GParted (e.g. to be called "backup") so they will always be mounted at the same mountpoint.

    Add a user systemd unit in ~/.config/systemd/user/auto-usb-backup.service with:

    [Unit]
    Description=Autobackup to USB drive
    
    [Service]
    ExecStart=/home/david/Documents/computer/backup/scripts/backup_to_usb.sh
    

    Reload the daemon: systemctl --user daemon-reload so it's aware of the new unit.

    Then, add a udev rule to trigger the unit when a USB drive with a "backup" partition is mounted. Create a udev rule at /etc/udev/rules.d/90-auto-usb-backup.rules containing

    SUBSYSTEM=="block", ACTION=="add", ENV{ID_FS_LABEL}=="backup", TAG+="systemd", ENV{SYSTEMD_USER_WANTS}="auto-usb-backup.service"
    

    The ID_FS_LABEL parameter name and value were obtained using udevadm monitor --environment --udev and plugging in the drive, but the lsusb (and its -v option) and udevadm info -a -p $(udevadm info -q path -n /dev/sda) may also be useful to fine-tune rules (e.g. have the udev rule trigger only for a specific drive based on its serial number).

    Reload udev for the new rule to apply: sudo udevadm control --reload

    Check the rule will trigger for the drive with udevadm test /block/sda (where sda is the current drive mountpoint): you should see TAGS=:systemd: among the output.

    Finally, turn remove and add the drive: the script in the systemd user unit defined above should get executed. You can double-check this (and debug) using journalctl --user-unit auto-usb-backup -r -b (note that on some systems the --user-unit option may be -u instead).

    Note: it appears the script gets triggered before the drive is done mounting, so the backup script called by the systemd unit has a wait loop to sleep until the folders its looking for are available.

    Resources that were helpful:

    https://vic.demuzere.be/articles/using-systemd-user-units/

    https://borgbackup.readthedocs.io/en/stable/deployment/automated-local.html