加载中…
个人资料
散人
散人
  • 博客等级:
  • 博客积分:0
  • 博客访问:15,299
  • 关注人气:4
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
谁看过这篇博文
加载中…
正文 字体大小:

udev rules详解

(2011-03-14 16:45:51)
标签:

linux

-> Rule syntax


每条规则由一系列成对构建的键值构成,相互之间由逗号分隔。
匹配键作为条件用于设备匹配哪条规则,在设备开始处理之前先匹配规则文件中的所有match键,然后应用相

应的规则并调用assignmnt键,每条规则至少包含一个match键和一个assignmnt键。exa:
KERNEL=="hdb", NAME="my_spare_disk"   (match flag ==)


->Basic Rules


KERNEL == match against 内核中的设备名字
SUBSYSTEM == match against 设备所属子系统
DRIVER == match against 设备所支持的驱动
NAME = 设备节点名字
SYMLINK = 符号链接(文件的列表,作为替代的名字来命名设备节点)
exam:
KERNEL=="hdb", NAME="my_spare_disk"
规则解释:如果在内核中出现名字为hdb的设备,那么就在/dev/下重新命名一个名字为my_spare_disk节点替

换它。
KERNEL=="hdb", DRIVER=="ide-disk", SYMLINK+="sparedisk"
规则解释:如果在内核中出现名字为hdb并且使用ide-disk驱动,那么创建一个默认的节点名字和为节点创建

一个叫sparedisk符号链接。注意,这里我们并没有指定一个设备的节点名字,因此设备管理器使用一个默

认的。


->Matching sysfs attributes 系统文件系统属性匹配
->Device hierarchy 设备层次


->String substitutions 字符串替换


当规则在处理多个类似的设备时,设备管理器的 printf-like字符串替换功能就显的非常有用,你可以简单

地把这些操作放在assignmnt里面制作,让udev自己处理。最普通的操作是%k和%n.%k evaluates to the

kernel name for the device, e.g. "sda3" for a device that would (by default) appear at

/dev/sda3. %n evaluates to the kernel number for the device (the partition number for storage

devices), e.g. "3" for /dev/sda3.也就是说在一个规则里%k代表的是在当前设备在内核中的名字,%n代

表的是当前设备名(字符串)中的数字部分。%C替换返回值。
KERNEL=="hda", PROGRAM="/bin/device_namer %k", SYMLINK+="%c"//参数为hda运行device_namer程序,

为每个返回部分创建符号链接。

如下规则解释:
KERNEL=="mice", NAME="input/%k"
KERNEL=="loop0", NAME="loop/%n", SYMLINK+="%k"
匹配内核名字为"mice", if true 创建一个/dev/input/mice节点
匹配内核名字为"loop0",if true 创建一个/dev/loop/0节点,并且为节点创建一个symbolic link到%k

(/dev/loop0)


->String matching


* - match any character, zero or more times  通配 //支持shell风格的模式匹配
? - match any character exactly once 单字符通配
[] - match any single character specified in the brackets, ranges are also permitted 加范围的

单字符通配
KERNEL=="fd[0-9]*", NAME="floppy/%n", SYMLINK+="%k"
KERNEL=="hiddev*", NAME="usb/%k"
匹配内核名字为fd0,....,fd9,创建一个节点/dev/floppy/0,...,/dev/floppy/9,并且为节点创建一个符号

链接点.
匹配内核名字为hiddev开头的所有设备,在/dev/usb/下创建名字为相应内核名字的节点。

->udevinfo
Enter udevinfo, which is probably the most straightforward tool you can use to construct

rules. All you need to know is the sysfs device path of the device in question. A trimmed

example is shown below:

# udevinfo -a -p /sys/block/sda

  looking at device '/block/sda':
    KERNEL=="sda"
    SUBSYSTEM=="block"
    ATTR{stat}=="  128535     2246  2788977   766188    73998   317300  3132216  5735004      

   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"
As you can see, udevinfo simply produces a list of attributes you can use as-is as match keys

in your udev rules. From the above example, I could produce (e.g.) either of the following two

rules for this device:

SUBSYSTEM=="block", ATTR{size}=="234441648", NAME="my_hard_disk"
SUBSYSTEM=="block", SUBSYSTEMS=="scsi", ATTRS{model}=="ST3120827AS", NAME="my_hard_disk"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"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".

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.

Another point to note is that it is common for text attributes to appear in the udevinfo

output to be padded with spaces (e.g. see ST3120827AS above). In your rules, you can either

specify the extra spaces, or you can cut them off as I have done.

The only complication with using udevinfo is that you are required to know the top-level

device path (/sys/block/sda in the example above). This is not always obvious. However, as you

are generally writing rules for device nodes which already exist, you can use udevinfo to look

up the device path for you:

# udevinfo -a -p $(udevinfo -q path -n /dev/sda)

 

-> Advanced topics


Controlling permissions and ownership
GROUP : which Unix group should own the device node
OWNER : which Unix user should have ownership permissions on the device node
KERNEL=="fb[0-9]*", NAME="fb/%n", SYMLINK+="%k", GROUP="video" //video group 拥有此设备节点
KERNEL=="fd[0-9]*", OWNER="john" //john 拥有此设备
KERNEL=="inotify", NAME="misc/%k", SYMLINK+="%k", MODE="0666"创建misc/inotify节点和符号链接,

该节点可以读写。

 

-> Using external programs to name devices  program只用于解析name

 

//KERNEL=="hda", PROGRAM="/bin/device_namer %k", SYMLINK+="%c"
使用外部程序,串入参数为hda ,为每个返回部分创建符号链接

KERNEL=="hda", PROGRAM="/bin/device_namer %k", NAME="%c{1}", SYMLINK+="%c{2}"
使用外部程序,串入参数为hda ,第一个返回部分用于创建节点,后一个用于建立符号链接

KERNEL=="hda", PROGRAM="/bin/device_namer %k", NAME="%c{1}", SYMLINK+="%c{2+}"
使用外部程序,串入参数为hda ,第一个返回部分用于创建节点,其它的用于建立符号链接

 

-> Running external programs upon certain events//运行外部程序用于特定事件

 

KERNEL=="sdb", RUN+="/usr/bin/my_program"
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.
当/usr/bin/my_program被执行,udev的各种环境变量被有效,包括键值。还有ACTION环境变量用于探测设

备是否已经被插入或拔除。

 

USB Printer

 

I power on my printer, and it is assigned device node /dev/lp0. Not satisfied with such a bland name, I decide to use udevinfo to aid me in writing a rule which will provide an alternative name:

# udevinfo -a -p $(udevinfo -q path -n /dev/lp0)
  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:

SUBSYSTEM=="usb", ATTRS{serial}=="L72010011070626380", SYMLINK+="epson_680"

USB Camera

Like most, my camera identifies itself as an external hard disk connected over the USB bus, using the SCSI transport. To access my photos, I mount the drive and copy the image files onto my hard disk.

Not all cameras work in this way: some of them use a non-storage protocol such as cameras supported by gphoto2. In the gphoto case, you do not want to be writing rules for your device, as is it controlled purely through userspace (rather than a specific kernel driver).

A common complication with USB camera devices is that they usually identify themselves as a disk with a single partition, in this case /dev/sdb with /dev/sdb1. The sdb node is useless to me, but sdb1 is interesting - this is the one I want to mount. There is a problem here that because sysfs is chained, the useful attributes which udevinfo produces for /dev/sdb1 are identical to the ones for /dev/sdb. This results in your rule potentially matching both the raw disk and the partition, which is not what you want, your rule should be specific.

To get around this, you simply need to think about what differs between sdb and sdb1. It is surprisingly simple: the name itself differs, so we can use a simple pattern match on the NAME field.

# udevinfo -a -p $(udevinfo -q path -n /dev/sdb1)
  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", SUBSYSTEMS=="scsi", ATTRS{model}=="X250,D560Z,C350Z", SYMLINK+="camera"

USB Hard Disk

A USB hard disk is comparable to the USB camera I described above, however typical usage patterns are different. In the camera example, I explained that I am not interested in the sdb node - it's only real use is for partitioning (e.g. with fdisk), but why would I want to partition my camera!?

Of course, if you have a 100GB USB hard disk, it is perfectly understandable that you might want to partition it, in which case we can take advantage of udev's string substitutions:

KERNEL=="sd*", SUBSYSTEMS=="scsi", ATTRS{model}=="USB 2.0 Storage Device", SYMLINK+="usbhd%n"

This rule creates symlinks such as:

  • /dev/usbhd - The fdiskable node
  • /dev/usbhd1 - The first partition (mountable)
  • /dev/usbhd2 - The second partition (mountable)

USB Card Reader

USB card readers (CompactFlash, SmartMedia, etc) are yet another range of USB storage devices which have different usage requirements.

These devices typically do not inform the host computer upon media change. So, if you plug in the device with no media, and then insert a card, the computer does not realise, and you do not have your mountable sdb1 partition node for the media.

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:

KERNEL="sd*", SUBSYSTEMS=="scsi", ATTRS{model}=="USB 2.0 CompactFlash Reader", SYMLINK+="cfrdr%n", OPTIONS+="all_partitions"

Network interfaces

Even though they are referenced by names, network interfaces typically do not have device nodes associated with them. Despite that, the rule writing process is almost identical.

It makes sense to simply match the MAC address of your interface in the rule, as this is unique. However, make sure that you use the exact MAC address as shown as udevinfo, because if you do not match the case exactly, your rule will not work.

# udevinfo -a -p /sys/class/net/eth0
  looking at class device '/sys/class/net/eth0':
    KERNEL=="eth0"
    ATTR{address}=="00:52:8b:d5:04:48"

Here is my rule:

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. After that, you should be able to use "lan" instead of "eth0" in any calls to ifconfig or similar utilities.

Testing and debugging

Putting your rules into action

Assuming you are on a recent kernel with inotify support, udev will automatically monitor your rules directory and automatically pick up any modifications you make to the rule files.

Despite this, udev will not automatically reprocess all devices and attempt to apply the new rule(s). For example, if you write a rule to add an extra symbolic link for your camera while your camera is plugged in, you cannot expect the extra symbolic link to show up right away.

To make the symbolic link show up, you can either disconnect and reconnect your camera, or alternatively in the case of non-removable devices, you can run udevtrigger.

If your kernel does not have inotify support, new rules will not be detected automatically. In this situation, you must run udevcontrol reload_rules after making any rule file modifications for those modifications to take effect.

udevtest

If you know the top-level device path in sysfs, you can use udevtest to show the actions which udev would take. This may help you debug your rules. For example, assuming you want to debug a rule which acts on /sys/class/sound/dsp:

# udevtest /class/sound/dsp
main: looking at device '/class/sound/dsp' from subsystem 'sound'
udev_rules_get_name: add symlink 'dsp'
udev_rules_get_name: rule applied, 'dsp' becomes 'sound/dsp'
udev_device_event: device '/class/sound/dsp' already known, remove possible symlinks
udev_node_add: creating device node '/dev/sound/dsp', major = '14', minor = '3', mode = '0660', uid = '0', gid = '18'
udev_node_add: creating symlink '/dev/dsp' to 'sound/dsp'

Note the /sys prefix was removed from the udevtest command line argument, this is because udevtest operates on device paths. Also note that udevtest is purely a testing/debugging tool, it does not create any device nodes, despite what the output suggests!

0

阅读 收藏 禁止转载 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

新浪公司 版权所有