Udev
Basics
Udev rules are created in
/etc/udev/rules.d/
Create a file named e.g. 10_my_udev.rules ... the leading number 10 should ensure that it runs before all other rules already on your system (unless you already have rules starting with 10 or smaller). The ending .rules is important for the file to be recognized as a udev rules file.
Specify the properties to be matched for the device you want to create a rule for and provide the action to be taken when it is (un)plugged. Basic example for a USB mouse: Run lsusb to get the vendor and product id:
root@host:~$ lsusb
Bus 001 Device 010: ID 192f:0416 Avago Technologies, Pte.
... more irrelevant output
You could now specify the following rule:
ATTRS{idVendor}=="192f", ATTRS{idProduct}=="0416", RUN+="/path/to/my/shellscript.sh"
Or, if e.g. you wanted to disable the touchpad upon plugin
ACTION=="add", ATTRS{idVendor}=="192f", ATTRS{idProduct}=="0416", RUN+="/sbin/modprobe -r psmouse"
And to enable upon unplug
ACTION=="remove", ATTRS{idVendor}=="192f", ATTRS{idProduct}=="0416", RUN+="/sbin/modprobe psmouse"
Symlinks
Device node names are typically not very intuitive. If you want to always have a device node called /dev/sdcard when an sdcard is inserted, use the SYMLINK directive:
ACTION=="add", SUBSYSTEMS=="usb", KERNEL=="sd*1", ENV{ID_DRIVE_FLASH_SD}="1", SYMLINK="sdcard"
The KERNEL condition prevents multiple execution of the same rule.
Automatically open folders that contain certain files in a file-manager
E.g. always open folders with JPG files when an SCARD is inserted: Use the following rule:
ACTION=="add", SUBSYSTEMS=="usb", KERNEL=="sd*1", ENV{ID_DRIVE_FLASH_SD}="1", RUN+="/usr/local/bin/handle_sd_card.sh"
In combination with the following script:
#!/bin/bash
# /usr/local/bin/handle_sd_card.sh
#
# Cleanup of old mounts
umount /tmp/sdcard.*
rmdir /tmp/sdcard.*
#
# Actual script
MOUNTPOINT=/tmp/sdcard.$BASHPID
FILE_EXTENSION=JPG
USER_FOR_FILE_BROWSER
if [ "${ACTION}" == "add" ];then
mkdir -p $MOUNTPOINT
mount /dev/disk/by-uuid/${ID_FS_UUID} $MOUNTPOINT
cd $MOUNTPOINT
export DISPLAY=:0
for directory in $(find . -iname "*.$FILE_EXTENSION"| sed 's#.\*/.*#\1#' | sort -u) ; do
cd $MOUNTPOINT/$directory
su $USER_FOR_FILE_BROWSER -c thunar &
done
fi
Giving member of a certain group write access to usb device nodes
Let's say you want members of the group usbadmin to be able to write to usb device nodes. You can achieve it with a rule like this:
SUBSYSTEMS=="usb", ACTION=="add", GROUP="usbadmin"
Using properties in a shell script
You can also use the properties in a shell script you are calling. E.g. if you wanted to use only one rule, and let the shell script decide what to do based on the action, you could do
ATTRS{idVendor}=="192f", ATTRS{idProduct}=="0416", RUN+="/path/to/my/shellscript.sh"
in the rules file and
#!/bin/bash
if [ ${ACTION} == "add" ];then
modprobe -r psmouse
elif [ ${ACTION} == "remove" ];then
modprobe psmouse
fi
in the called shell script
More advanced matching rules
Get more detailed info on the device now:
lsusb -d 192f:0416 -v
Bus 001 Device 007: ID 192f:0416 Avago Technologies, Pte.
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x192f Avago Technologies, Pte.
idProduct 0x0416
bcdDevice 2.00
iManufacturer 0
iProduct 2 USB Optical Mouse
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 34
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 98mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 1 Boot Interface Subclass
bInterfaceProtocol 2 Mouse
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.11
bCountryCode 0 Not supported
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 71
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0006 1x 6 bytes
bInterval 10
Device Status: 0x0000
(Bus Powered)
Alternatively, call a script that outputs the environment generated by udev to a log file - this gives you a whole bunch of properties you can match against to specifiy the device.
You could now specify the following rule:
ATTRS{idVendor}=="152d", ATTRS{idProduct}=="2329", RUN+="/path/to/my/shellscript.sh"
and /path/to/my/shellscript.sh:
#!/bin/bash
env >> /tmp/env.log
(Obviously make the script executable and find useful info in /tmp/env.log after the next hotplug. You can access the environment both in rules and in scripts.
E.g. for my mouse the output is
ID_USB_DRIVER=usbhid
ID_MODEL=USB_Optical_Mouse
ID_PATH_TAG=pci-0000_00_14_0-usb-0_4_1_0
ID_MODEL_ENC=USB\x20Optical\x20Mouse
ID_REVISION=0200
ID_BUS=usb
SUBSYSTEM=input
EV=17
ID_SERIAL=192f_USB_Optical_Mouse
DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0/input/input57
NAME="USB Optical Mouse"
ID_MODEL_ID=0416
ID_VENDOR_ENC=192f
ID_INPUT_MOUSE=1
ACTION=remove
MODALIAS=input:b0003v192Fp0416e0111-e0,1,2,4,k110,111,112,r0,1,6,8,am4,lsfw
PWD=/
UDEV_LOG=3
REL=143
KEY=70000 0 0 0 0
USEC_INITIALIZED=10222831102
ID_VENDOR_ID=192f
SHLVL=1
MSC=10
PHYS="usb-0000:00:14.0-4/input0"
ID_TYPE=hid
PRODUCT=3/192f/416/111
PROP=0
ID_VENDOR=192f
ID_USB_INTERFACE_NUM=00
ID_INPUT=1
UNIQ=""
SEQNUM=2437
ID_USB_INTERFACES=:030102:
ID_PATH=pci-0000:00:14.0-usb-0:4:1.0
_=/usr/bin/env
SUBSYSTEM=hidraw
DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0/0003:192F:0416.0027/hidraw/hidraw0
MINOR=0
ACTION=remove
PWD=/
UDEV_LOG=3
USEC_INITIALIZED=11145880798
MAJOR=251
DEVNAME=/dev/hidraw0
SHLVL=1
SEQNUM=2438
_=/usr/bin/env
To get a generic rule that does the touchpad dis/en-abling for any mouse you can now do
ACTION=="add", ATTRS{bInterfaceProtocol}=="02", ATTRS{bInterfaceClass}=="03", ATTRS{bInterfaceSubClass}=="01", RUN+="/sbin/modprobe -r psmouse"
ACTION=="remove", ENV{ID_INPUT_MOUSE}=="?*", RUN+="/sbin/modprobe psmouse"
Gaining more info on the device using udevadm
Log at the syslog during the (un)plug event:
tail -f /var/log/syslog:
Nov 17 23:44:32 asus-n56v mtp-probe: checking bus 1, device 52: "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-3"
Then run udevadm on the device path to get the devices properties:
udevadm info -a -p /sys/devices/pci0000:00/0000:00:14.0/usb1/1-3
.. shows all attributes to match against. Note that plugin and unplug can point to different levels in the file system hierarchy - with folders representing parent devices of the files / folders in them. You can match against attributes of the device and one parent device.
Triggering Events
If e.g. at system startup the right states aren't picked up you can trigger them manually. E.g. for a USB mouse to be more reliably detected, you could run the following (as root) upon session start:
/sbin/udevadm trigger --action="add" --subsystem-match="usb"
Finding good examples
On Debian, the good stuff can be found in /lib/udev/rules.d/