5

This is a duplicate of the question "Is there a way to automatically activate a script when a USB device connects?" from 2014 but the solution presented does not work for me.

I would like to run a script when any device (drive, keyboard, ...) connects to any USB port. Following the answer to the question above, I tried to build a rule for that 5I commented out various other incantations of the rules):

# cat /etc/udev/rules.d/plug_usb.rules
ACTION=="add", RUN+="/bin/date > /tmp/date.txt"
#ACTION=="add", DEVTYPE="usb_device", RUN+="/bin/date > /tmp/date.txt"
#KERNEL="*", RUN+="/bin/date > /tmp/date.txt"
#SUBSYSTEMS=="usb", RUN+="/bin/date > /tmp/date.txt"

This is the simplest rule I can imagine (when and "add" action is trigerred, run the script). I would like to constraint it to USB devices but at this point I wanted to start from the most basic one.

I restarted udev via systemctl restart udev and udevadm control --reload-rulesand plugged in a USB drive. The script was not ran (no /tmp/date.txtfile).

When inserting the USB drive I do see lots of events:

# udevadm monitor -p -k -u
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
KERNEL - the kernel uevent

KERNEL[1775.965890] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4 (usb)
ACTION=add
BUSNUM=001
DEVNAME=/dev/bus/usb/001/019
DEVNUM=019
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4
DEVTYPE=usb_device
MAJOR=189
MINOR=18
PRODUCT=90c/1000/1000
SEQNUM=1947
SUBSYSTEM=usb
TYPE=0/0/0

KERNEL[1775.967288] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0 (usb)
ACTION=add
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0
DEVTYPE=usb_interface
INTERFACE=8/6/80
MODALIAS=usb:v090Cp1000d1000dc00dsc00dp00ic08isc06ip50in00
PRODUCT=90c/1000/1000
SEQNUM=1948
SUBSYSTEM=usb
TYPE=0/0/0

KERNEL[1775.968292] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15 (scsi)
ACTION=add
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15
DEVTYPE=scsi_host
SEQNUM=1949
SUBSYSTEM=scsi

KERNEL[1775.968577] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/scsi_host/host15 (scsi_host)
ACTION=add
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/scsi_host/host15
SEQNUM=1950
SUBSYSTEM=scsi_host

UDEV  [1775.979656] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4 (usb)
ACTION=add
BUSNUM=001
DEVNAME=/dev/bus/usb/001/019
DEVNUM=019
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4
DEVTYPE=usb_device
ID_BUS=usb
ID_MODEL=USB_DISK
ID_MODEL_ENC=USB\x20DISK
ID_MODEL_FROM_DATABASE=Flash Drive
ID_MODEL_ID=1000
ID_REVISION=1000
ID_SERIAL=090c_USB_DISK_15111933000107
ID_SERIAL_SHORT=15111933000107
ID_USB_INTERFACES=:080650:
ID_VENDOR=090c
ID_VENDOR_ENC=090c
ID_VENDOR_FROM_DATABASE=Silicon Motion, Inc. - Taiwan (formerly Feiya Technology Corp.)
ID_VENDOR_ID=090c
MAJOR=189
MINOR=18
PRODUCT=90c/1000/1000
SEQNUM=1947
SUBSYSTEM=usb
TYPE=0/0/0
USEC_INITIALIZED=75965869

UDEV  [1775.987989] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0 (usb)
ACTION=add
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0
DEVTYPE=usb_interface
ID_MODEL_FROM_DATABASE=Flash Drive
ID_VENDOR_FROM_DATABASE=Silicon Motion, Inc. - Taiwan (formerly Feiya Technology Corp.)
INTERFACE=8/6/80
MODALIAS=usb:v090Cp1000d1000dc00dsc00dp00ic08isc06ip50in00
PRODUCT=90c/1000/1000
SEQNUM=1948
SUBSYSTEM=usb
TYPE=0/0/0
USEC_INITIALIZED=967657

UDEV  [1775.994239] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15 (scsi)
ACTION=add
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15
DEVTYPE=scsi_host
SEQNUM=1949
SUBSYSTEM=scsi
USEC_INITIALIZED=969049

UDEV  [1776.001861] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/scsi_host/host15 (scsi_host)
ACTION=add
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/scsi_host/host15
SEQNUM=1950
SUBSYSTEM=scsi_host
USEC_INITIALIZED=969180

KERNEL[1777.370293] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0 (scsi)
ACTION=add
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0
DEVTYPE=scsi_target
SEQNUM=1951
SUBSYSTEM=scsi

KERNEL[1777.370439] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0 (scsi)
ACTION=add
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0
DEVTYPE=scsi_device
MODALIAS=scsi:t-0x00
SEQNUM=1952
SUBSYSTEM=scsi

KERNEL[1777.370584] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/scsi_disk/15:0:0:0 (scsi_disk)
ACTION=add
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/scsi_disk/15:0:0:0
SEQNUM=1953
SUBSYSTEM=scsi_disk

KERNEL[1777.370662] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/scsi_device/15:0:0:0 (scsi_device)
ACTION=add
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/scsi_device/15:0:0:0
SEQNUM=1954
SUBSYSTEM=scsi_device

KERNEL[1777.371165] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/scsi_generic/sg0 (scsi_generic)
ACTION=add
DEVNAME=/dev/sg0
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/scsi_generic/sg0
MAJOR=21
MINOR=0
SEQNUM=1955
SUBSYSTEM=scsi_generic

KERNEL[1777.371799] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/bsg/15:0:0:0 (bsg)
ACTION=add
DEVNAME=/dev/bsg/15:0:0:0
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/bsg/15:0:0:0
MAJOR=252
MINOR=0
SEQNUM=1956
SUBSYSTEM=bsg

KERNEL[1777.374198] add      /devices/virtual/bdi/8:0 (bdi)
ACTION=add
DEVPATH=/devices/virtual/bdi/8:0
SEQNUM=1957
SUBSYSTEM=bdi

UDEV  [1777.374832] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0 (scsi)
ACTION=add
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0
DEVTYPE=scsi_target
SEQNUM=1951
SUBSYSTEM=scsi
USEC_INITIALIZED=370884

UDEV  [1777.376907] add      /devices/virtual/bdi/8:0 (bdi)
ACTION=add
DEVPATH=/devices/virtual/bdi/8:0
SEQNUM=1957
SUBSYSTEM=bdi
USEC_INITIALIZED=77375231

UDEV  [1777.383332] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0 (scsi)
ACTION=add
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0
DEVTYPE=scsi_device
MODALIAS=scsi:t-0x00
SEQNUM=1952
SUBSYSTEM=scsi
USEC_INITIALIZED=371005

KERNEL[1777.385276] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/block/sda (block)
ACTION=add
DEVNAME=/dev/sda
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/block/sda
DEVTYPE=disk
MAJOR=8
MINOR=0
SEQNUM=1958
SUBSYSTEM=block

UDEV  [1777.387755] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/bsg/15:0:0:0 (bsg)
ACTION=add
DEVNAME=/dev/bsg/15:0:0:0
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/bsg/15:0:0:0
MAJOR=252
MINOR=0
SEQNUM=1956
SUBSYSTEM=bsg
USEC_INITIALIZED=77375131

UDEV  [1777.391037] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/scsi_device/15:0:0:0 (scsi_device)
ACTION=add
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/scsi_device/15:0:0:0
SEQNUM=1954
SUBSYSTEM=scsi_device
USEC_INITIALIZED=371101

UDEV  [1777.392879] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/scsi_disk/15:0:0:0 (scsi_disk)
ACTION=add
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/scsi_disk/15:0:0:0
SEQNUM=1953
SUBSYSTEM=scsi_disk
USEC_INITIALIZED=371059

UDEV  [1777.397161] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/scsi_generic/sg0 (scsi_generic)
ACTION=add
DEVNAME=/dev/sg0
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/scsi_generic/sg0
MAJOR=21
MINOR=0
SEQNUM=1955
SUBSYSTEM=scsi_generic
USEC_INITIALIZED=77374811

UDEV  [1777.436968] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/block/sda (block)
ACTION=add
DEVLINKS=/dev/disk/by-id/usb-090c_USB_DISK_15111933000107-0:0 /dev/disk/by-label/ESD_ISO /dev/disk/by-path/platform-3f980000.usb-usb-0:1.4:1.0-scsi-0:0:0:0 /dev/disk/by-uuid/2016-07-21-13-55-06-00
DEVNAME=/dev/sda
DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host15/target15:0:0/15:0:0:0/block/sda
DEVTYPE=disk
ID_BUS=usb
ID_FS_BOOT_SYSTEM_ID=EL\x20TORITO\x20SPECIFICATION
ID_FS_LABEL=ESD_ISO
ID_FS_LABEL_ENC=ESD_ISO
ID_FS_TYPE=udf
ID_FS_USAGE=filesystem
ID_FS_UUID=2016-07-21-13-55-06-00
ID_FS_UUID_ENC=2016-07-21-13-55-06-00
ID_INSTANCE=0:0
ID_MODEL=USB_DISK
ID_MODEL_ENC=USB\x20DISK
ID_MODEL_ID=1000
ID_PATH=platform-3f980000.usb-usb-0:1.4:1.0-scsi-0:0:0:0
ID_PATH_TAG=platform-3f980000_usb-usb-0_1_4_1_0-scsi-0_0_0_0
ID_REVISION=1000
ID_SERIAL=090c_USB_DISK_15111933000107-0:0
ID_SERIAL_SHORT=15111933000107
ID_TYPE=disk
ID_USB_DRIVER=usb-storage
ID_USB_INTERFACES=:080650:
ID_USB_INTERFACE_NUM=00
ID_VENDOR=090c
ID_VENDOR_ENC=090c
ID_VENDOR_ID=090c
MAJOR=8
MINOR=0
SEQNUM=1958
SUBSYSTEM=block
TAGS=:systemd:
USEC_INITIALIZED=77386166

I expected that using the add action combined with DEVTYPE=usb_devicewould be ideal ("add a USB device"). I also searched on Debian and Ubuntu forums buit the solutions all gravitate around the same idea - so I must be doing something really wrong.

What would be the suitable rule for such an event?

WoJ
  • 545
  • 2
  • 6
  • 15

2 Answers2

5

The script was not ran (no /tmp/date.txtfile).

Because you are trying to use redirection there (>), which is something that works via a shell (e.g., in a script or on the command line), but this is not something that is executed by a shell.

To explain a bit: What that actually does is execute date with two arguments, > and /tmp/date.txt, but those are not valid arguments to date so it will fail, and any error it reports discarded. When you execute a command line like that normally via a shell, the shell parses it first, and it interprets the > /tmp/date.txt redirection and pipes the output of date (with no arguments). But again: The RUN command is not executed via a shell; as per this it is parsed as "the program name and following arguments...separated by spaces. Single quotes can be used to specify arguments with spaces." This means if you want to write to a file, you can't rely on a shell to do the redirection for you.

Unless you use a shell wrapper -- so what you should try instead is to put that in a script with an appropriate shebang:

#!/bin/sh

/bin/date >> /tmp/date.txt

Make it executable, and use the full path to that with RUN instead, no arguments (unless you want to include them in that script). Keep reading to understand why I've put >> there instead of >.

udevadm monitor output can be confusing to match since it is not straightforward. One thing I find handy with udev is the PROGRAM= option; this will be called if the == constaints match, and be passed all the associated environment variables from udev (see here again). If it exits with a status of 0, then the match is considered good and, e.g., anything in RUN will run. If it exits with any other value, the match will fail (so, it's a way to further customize control over the RUN, make use of those variables, and/or return non-zero and allow the match to occur with subsequent rules). Create another shell script like this:

#!/bin/sh

env >> /tmp/udev-env.txt
echo -e "\n|||-----------|||\n" >> /tmp/udev-env.txt
exit 0

Call it /usr/local/bin/udev-test.sh, or whatever, make it executable, then try a rule like this:

ACTION=="add" PROGRAM="/usr/local/bin/udev-test.sh" RUN+="/foo/bar.sh"

Where /foo/bar.sh is that script that calls date, and you should get the picture (the use of append redirect, >> instead of overwrite, >, and the easily visible |||--------|||, will allow you to tell if this rule fires multiple times for one device, which it likely will).

Notice the environment reported is very minimal. If you do try this while running udevadm monitor you should be able to correspond the sequence of add events for a device.

In my experience getting a lot of attributes to match an add event, particularly on a system like Raspbian that doesn't use udev to implement "persistent naming" (which creates move events that can be matched against much more information) is a PITA. However, since you are just trying to do something for anything USB related, I would think SUBSYSTEM="usb" should work; SUBSYSTEMS (subtle difference, see that previous link) is more flexible but I think bound to trigger multiple add events when plugging in a single device.

Beware that doing something this broad may screw certain things up by overriding system rules. Using PROGRAM and returning non-zero (hence, no RUN) will prevent this; the program can be a shell script that forks whatever you want but beware:

  1. The program itself should not be persistent.

  2. Anything it forks should use setsid or that may not complete; you'll have to experiment but keep this possibility in mind (TBH I'm not positive that setsid will help either but it should).

goldilocks
  • 58,859
  • 17
  • 112
  • 227
  • Thank you . I did not manage to create a filter which would trigger exactly one run of the script (I posted an auxiliary answer with my workaround) – WoJ Jul 29 '16 at 08:52
3

Following up on the excellent @goldilocks's answer, I ended up with the following setup

# cat /etc/udev/rules.d/plug_usb.rules
ACTION=="add", SUBSYSTEM=="usb", PROGRAM="/opt/plug_usb_in.sh"
ACTION=="remove", SUBSYSTEM=="usb", PROGRAM="/opt/plug_usb_out.sh"

This is quite specific to my need: I want to use the USB port as a way to send some information on an headless RPi (without anything connected to the USB ports). The idea is that I will plug and unplug something to a USB port, which will generate a message (actually a call to a web service). This is to say that the scenario is known and predictable.

I wanted to avoid having several messages sent, if possible. The filters above generate two messages but it looks like that the programs launched are queued and not threaded (they are launched one after the other). The solution I used was a lock file - it is not the best one (there will be issues if several devices are plugged in together) but it works in my case

# cat plug_usb_in.sh
#!/bin/sh

LOCK=/tmp/lockfile_for_plug_usb

if [ -f $LOCK ]
then
        exit 1
else
        touch $LOCK
        # the actual command to run upon USB plug in
        /bin/date >> /tmp/date.txt
fi

# cat plug_usb_out.sh
#!/bin/sh

LOCK=/tmp/lockfile_for_plug_usb
/bin/rm -f /tmp/lockfile_for_plug_usb
WoJ
  • 545
  • 2
  • 6
  • 15