From fbb002f9d31c76f9445c4c16b3b88b11e34f8e86 Mon Sep 17 00:00:00 2001
From: Daniel Drake Writing udev rules
by Daniel Drake (dsd)
-Version 0.72
+Version 0.73
The most recent version of this document can always be found at:
@@ -43,6 +44,7 @@ The most recent version of this document can always be found at:
History
-
October 2nd 2006 v0.72: Fixed a typo in one of the example rules.
+
+Be aware that udev does not support any form of line continuation. Do not insert any line breaks in your rules, as this will cause udev to see your one rule as multiple rules and will not work as expected. +
+@@ -290,19 +297,39 @@ The match keys introduced so far only provide limited matching capabilities. Rea
-Many drivers export information like this into sysfs, and udev allows us to incorporate sysfs-matching into our rules, using the SYSFS key with a slightly different syntax. +Many drivers export information like this into sysfs, and udev allows us to incorporate sysfs-matching into our rules, using the ATTR key with a slightly different syntax.
-Here are some examples of rules which match data from sysfs. Further detail will be provided later in this document which will aid you in writing rules based on sysfs attributes. +Here is an example rule which matches a single attribute from sysfs. Further detail will be provided later in this document which will aid you in writing rules based on sysfs attributes.
+ +-KERNEL=="sda", SYSFS{model}=="ST3120827AS", SYMLINK+="my_hard_disk" -SUBSYSTEM=="block", SYSFS{size}=="234441648", SYMLINK+="my_disk" -BUS=="usb", SYSFS{manufacturer}=="OLYMPUS", SYSFS{product}=="X250,D560Z,C350Z", SYMLINK+="camera" +SUBSYSTEM=="block", ATTR{size}=="234441648", SYMLINK+="my_disk"
+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. +
+ ++The four main match keys introduced so far (KERNEL/SUBSYSTEM/DRIVER/ATTR) only match against values corresponding to the device in question, and do not match values from parent devices. udev provides variants of the match keys that will search upwards through the tree: +
+ ++With hierarchy considerations in mind, you may feel that rule writing is becoming a little complicated. Rest assured that there are tools that help out here, which will be introduced later. +
+-sysfs is actually a very simple structure. It is logically divided into directories. Each directory contains a number of files (attributes) which typically contain just one value. Some symbolic links are present, which link various parts of the tree together. +sysfs is actually a very simple structure. It is logically divided into directories. Each directory contains a number of files (attributes) which typically contain just one value. Some symbolic links are present, which link devices to their parents. The hierarchical structure was touched upon above.
-Some directories are referred to as top-level device paths. These directories act as the top-level glue which chain other parts of sysfs to the device in question. Top-level device paths can be classified as sysfs directories which contain a dev file, the following command will list these for you: +Some directories are referred to as top-level device paths. These directories represent actual devices that have corresponding device nodes. Top-level device paths can be classified as sysfs directories which contain a dev file, the following command will list these for you:
# find /sys -name dev
-For example, on my system, the /sys/block/sda directory is the device path for my hard disk. It is chained to the controller through the /sys/block/sda/device/ symbolic link, which is in turn chained to the device driver through the /sys/block/sda/device/driver/ symbolic link. +For example, on my system, the /sys/block/sda directory is the device path for my hard disk. It is linked to it's parent, the SCSI disk device, through the /sys/block/sda/device symbolic link.
@@ -394,7 +421,7 @@ When you write rules based on sysfs information, you are simply matching attribu
-In a udev rule, I could use SYSFS{size}=="234441648" to identify this disk. As udev iterates through the entire device chain, I could alternatively opt to match attributes in another part of the chain (e.g. attributes in /sys/class/block/sda/device/), however there are some caveats when dealing with different parts of the chain which are described later. +In a udev rule, I could use ATTR{size}=="234441648" to identify this disk. As udev iterates through the entire device chain, I could alternatively opt to match attributes in another part of the chain (e.g. attributes in /sys/class/block/sda/device/) using ATTRS, however there are some caveats when dealing with different parts of the chain which are described later.
@@ -414,30 +441,37 @@ Enter udevinfo, which is probably the most straightforward tool you can looking at device '/block/sda': KERNEL=="sda" SUBSYSTEM=="block" - SYSFS{stat}==" 128535 2246 2788977 766188 73998 317300 3132216 5735004 0 516516 6503316" - SYSFS{size}=="234441648" - SYSFS{removable}=="0" - SYSFS{range}=="16" - SYSFS{dev}=="8:0" - - looking at device '/devices/pci0000:00/0000:00:07.0/host0/target0:0:0/0:0:0:0': - ID=="0:0:0:0" - BUS=="scsi" - DRIVER=="sd" - SYSFS{ioerr_cnt}=="0x0" - SYSFS{iodone_cnt}=="0x31737" - SYSFS{iorequest_cnt}=="0x31737" - SYSFS{iocounterbits}=="32" - SYSFS{timeout}=="30" - SYSFS{state}=="running" - SYSFS{rev}=="3.42" - SYSFS{model}=="ST3120827AS " - SYSFS{vendor}=="ATA " - SYSFS{scsi_level}=="6" - SYSFS{type}=="0" - SYSFS{queue_type}=="none" - SYSFS{queue_depth}=="1" - SYSFS{device_blocked}=="0" + ATTR{stat}==" 128535 2246 2788977 766188 73998 317300 3132216 5735004 0 516516 6503316" + ATTR{size}=="234441648" + ATTR{removable}=="0" + ATTR{range}=="16" + ATTR{dev}=="8:0" + + looking at parent device '/devices/pci0000:00/0000:00:07.0/host0/target0:0:0/0:0:0:0': + KERNELS=="0:0:0:0" + SUBSYSTEMS=="scsi" + DRIVERS=="sd" + ATTRS{ioerr_cnt}=="0x0" + ATTRS{iodone_cnt}=="0x31737" + ATTRS{iorequest_cnt}=="0x31737" + ATTRS{iocounterbits}=="32" + ATTRS{timeout}=="30" + ATTRS{state}=="running" + ATTRS{rev}=="3.42" + ATTRS{model}=="ST3120827AS " + ATTRS{vendor}=="ATA " + ATTRS{scsi_level}=="6" + ATTRS{type}=="0" + ATTRS{queue_type}=="none" + ATTRS{queue_depth}=="1" + ATTRS{device_blocked}=="0" + + looking at parent device '/devices/pci0000:00/0000:00:07.0': + KERNELS=="0000:00:07.0" + SUBSYSTEMS=="pci" + DRIVERS=="sata_nv" + ATTRS{vendor}=="0x10de" + ATTRS{device}=="0x037f"
@@ -445,18 +479,22 @@ As you can see, udevinfo simply produces a list of attributes you can use as-is
+SUBSYSTEM=="block", ATTR{size}=="234441648", NAME="my_hard_disk" +SUBSYSTEM="block", SUBSYSTEMS=="scsi", ATTRS{model}=="ST3120827AS", NAME="my_hard_disk"-SUBSYSTEM=="block", SYSFS{size}=="234441648", NAME="my_hard_disk" -BUS=="scsi", SYSFS{model}=="ST3120827AS", NAME="my_hard_disk"
-You may have noted the use of colour in the above examples. This is to demonstrate that you generally can not mix-and-match attributes from different sections of the udevinfo output - your rule will not work. For example, the following rule is invalid: +You may have noted the use of colour in the above examples. This is to demonstrate that while it is legal to combine the attributes from the device in question and a single parent device, you cannot mix-and-match attributes from multiple parent devices - your rule will not work. For example, the following rule is invalid as it attempts to match attributes from two parent devices:
+SUBSYSTEM=="block", ATTRS{model}=="ST3120827AS", DRIVERS=="sata_nv", NAME="my_hard_disk" + +-SUBSYSTEM=="block", SYSFS{size}=="234441648", SYSFS{model}=="ST3120827AS", NAME="my_hard_disk"
+You are usually provided with a large number of attributes, and you must pick a number of them to construct your rule. In general, you want to choose attributes which identify your device in a persistent and human-recognisable way. In the examples above, I chose the size of my disk and its model number. I did not use meaningless numbers such as ATTRS{iodone_cnt}=="0x31737". +
-You are usually provided with a large number of attributes, and you must pick a number of them (from the same section) to construct your rule. In general, you want to choose attributes which identify your device in a persistent and human-recognisable way. In the examples above, I chose the size of my disk and its model number. I did not use meaningless numbers such as SYSFS{iodone_cnt}=="0x31737". +Observe the effects of hierarchy in the udevinfo output. The green section corresponding to the device in question uses the standard match keys such as KERNEL and ATTR. The blue and maroon sections corresponding to parent devices use the parent-traversing variants such as SUBSYSTEMS and ATTRS. This is why the complexity introduced by the hierarchical structure is actually quite easy to deal with, just be sure to use the exact values that udevinfo suggests.
@@ -567,6 +605,10 @@ Here is an example rule which demonstrates the use of the RUN list assi When /usr/bin/my_program is executed, various parts of the udev environment are available as environment variables, including key values such as SUBSYSTEM. You can also use the ACTION environment variable to detect whether the device is being connected or disconnected - ACTION will be either "add" or "remove" respectively.
+
+udev does not run these programs on any active terminal, and it does not execute them under the context of a shell. Be sure to ensure your program is marked executable, if it is a shell script ensure it starts with an appropriate shebang (e.g. #!/bin/sh
), and do not expect any standard output to appear on your terminal.
+
# udevinfo -a -p $(udevinfo -q path -n /dev/lp0) -looking at the device chain at '/sys/devices/pci0000:00/0000:00:02.1/usb3/3-3': -BUS=="usb" -SYSFS{manufacturer}=="EPSON" -SYSFS{product}=="USB Printer" -SYSFS{serial}=="L72010011070626380" + looking at device '/class/usb/lp0': + KERNEL=="lp0" + SUBSYSTEM=="usb" + DRIVER=="" + ATTR{dev}=="180:0" + + looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb1/1-1': + SUBSYSTEMS=="usb" + ATTRS{manufacturer}=="EPSON" + ATTRS{product}=="USB Printer" + ATTRS{serial}=="L72010011070626380"
My rule becomes:
-+BUS=="usb", SYSFS{serial}=="L72010011070626380", SYMLINK+="epson_680"
SUBSYSTEM=="usb", ATTRS{serial}=="L72010011070626380", SYMLINK+="epson_680"
# udevinfo -a -p $(udevinfo -q path -n /dev/sdb1) - looking at device '/devices/pci0000:00/0000:00:02.0/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0': - ID=="6:0:0:0" - BUS=="scsi" - DRIVER=="sd" - SYSFS{rev}=="1.00" - SYSFS{model}=="X250,D560Z,C350Z" - SYSFS{vendor}=="OLYMPUS " - SYSFS{scsi_level}=="3" - SYSFS{type}=="0" + looking at device '/block/sdb/sdb1': + KERNEL=="sdb1" + SUBSYSTEM=="block" + + looking at parent device '/devices/pci0000:00/0000:00:02.1/usb1/1-1/1-1:1.0/host6/target6:0:0/6:0:0:0': + KERNELS=="6:0:0:0" + SUBSYSTEMS=="scsi" + DRIVERS=="sd" + ATTRS{rev}=="1.00" + ATTRS{model}=="X250,D560Z,C350Z" + ATTRS{vendor}=="OLYMPUS " + ATTRS{scsi_level}=="3" + ATTRS{type}=="0"
My rule:
-+KERNEL=="sd?1", BUS=="scsi", SYSFS{model}=="X250,D560Z,C350Z", SYMLINK+="camera"
KERNEL=="sd?1", SUBSYSTEMS=="scsi", ATTRS{model}=="X250,D560Z,C350Z", SYMLINK+="camera"
+BUS=="usb", KERNEL=="sd*", SYSFS{product}=="USB 2.0 Storage Device", NAME="%k", SYMLINK+="usbhd%n"
KERNEL=="sd*", SUBSYSTEMS="scsi", ATTRS{model}=="USB 2.0 Storage Device", SYMLINK+="usbhd%n"
This rule creates symlinks such as: @@ -710,7 +762,7 @@ These devices typically do not inform the host computer upon media change. So, i One possible solution is to take advantage of the all_partitions option, which will create 16 partition nodes for every block device that the rule matches:
-+BUS=="usb", SYSFS{product}=="USB 2.0 CompactFlash Reader", SYMLINK+="cfrdr%n", OPTIONS+="all_partitions"
You will now have nodes named: cfrdr, cfrdr1, cfrdr2, cfrdr3, ..., cfrdr15. @@ -725,7 +777,7 @@ These devices work as USB-serial devices, so by default, you only get the tt Carsten Clasohm's blog post appears to be the definitive source for this. Carsten's rule is shown below: -KERNEL="sd*", SUBSYSTEMS=="scsi", ATTRS{model}=="USB 2.0 CompactFlash Reader", SYMLINK+="cfrdr%n", OPTIONS+="all_partitions"
+BUS=="usb", SYSFS{product}=="Palm Handheld", KERNEL=="ttyUSB*", SYMLINK+="pilot"
SUBSYSTEMS=="usb", ATTRS{product}=="Palm Handheld", KERNEL=="ttyUSB*", SYMLINK+="pilot"
Note that the product string seems to vary from product to product, so make sure that you check (using udevinfo) which one applies to you. @@ -743,8 +795,8 @@ As we know the KERNEL names for these devices, rule writing is simple. Here are
@@ -761,14 +813,15 @@ It makes sense to simply match the MAC address of your interface in the rule, as-BUS=="ide", KERNEL=="hdc", SYMLINK+="dvd", GROUP="cdrom" -BUS=="ide", KERNEL=="hdd", SYMLINK+="dvdrw", GROUP="cdrom" +SUBSYSTEM=="block", KERNEL=="hdc", SYMLINK+="dvd", GROUP="cdrom" +SUBSYSTEM=="block", KERNEL=="hdd", SYMLINK+="dvdrw", GROUP="cdrom"
# udevinfo -a -p /sys/class/net/eth0 looking at class device '/sys/class/net/eth0': - SYSFS{address}=="00:52:8b:d5:04:48" + KERNEL=="eth0" + ATTR{address}=="00:52:8b:d5:04:48"
Here is my rule:
-+KERNEL=="eth*", SYSFS{address}=="00:52:8b:d5:04:48", NAME="lan"
KERNEL=="eth*", ATTR{address}=="00:52:8b:d5:04:48", NAME="lan"
You will need to reload the net driver for this rule to take effect. You can either unload and reload the module, or simply reboot the system. You will also need to reconfigure your system to use "lan" rather than "eth0". I had some troubles getting this going (the interface wasn't being renamed) until I had completely dropped all references to eth0. @@ -830,7 +883,7 @@ For support, you should mail the linux-hotplug mailing list: GNU General Public License, Version 2. +This document is licensed under the GNU General Public License, Version 2.