加载中…
个人资料
polygun2000
polygun2000
  • 博客等级:
  • 博客积分:0
  • 博客访问:348,260
  • 关注人气:48
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
正文 字体大小:

如何编写udev规则

(2011-06-26 21:02:52)
标签:

udev

rule

编写

自定义

杂谈

分类: 系统管理点滴

 本文是我自己的读书笔记,翻译得不全面,也不准确,目的是自己能看懂,网友看官们见谅,如何编写udev规则

英文原文: http://www.reactivated.net/writing_udev_rules.html 

在使用多路径的SAN作为集群共享存储的时候,同一块硬盘在不同节点上可能会被分配不同的名称,比如同一块硬盘,在node1上可能是/dev/sda,但在node2上就有可能是/dev/sdc。我们希望共享的磁盘在不同的前端节点上的设备名称是一致的。这样可以使得各前端节点的配置文件简化和一致。另外,我们也希望使用对人来说更具有可读性的设备名称,比如/dev/mapper/sharedisk01就比/dev/mapper/3600a0b8000122c6d00000000453174fc好理解的多。

 

设备节点的映射关系可能会被多种因素影响,比如添加新硬件,SAN划分Zone,新增SAN Lun,修改配置文件等。设备会基于下一个可用的设备类型major/minor对随机分配一个名字。

 

UDEV出现之前,系统使用devfs可以部分解决这类问题,但devfs并没有完全满足我们的需求,比如devfs可以做到在同一台主机上,磁盘会永远使用同一个名字,但是在不同主机上,就有可能是不同的名字。另外devfs是基于内核实现的,并且不能自定义设备名称。

 

UDEV是一个用户空间的动态/dev目录解决方案,它可以保持设备名称的一致性。它的主要特征有:

用户空间工具;

动态/dev目录,不会有不使用文件存在于/dev目录中;

设备名一致,同一设备永远是用同一个文件名访问;

可以自定义设备名称;

可以自定义脚本,当设备插上/拔下的时候执行;

 

如何编写udev规则

如何编写UDEV RULE

 

规则文件和语义

当决定如何命名一个设备,并且采取哪些额外的动作的时候,UDEV会读取存放在/etc/udev/rules.d目录下的一系列配置文件。这些文件必须以.rules为后缀。

默认的UDEV规则是/etc/udev/rules.d/50-udev.rules ,可以查看一下该文件,了解系统默认是如何操作的,但是不要往这个文件中写入自定义的规则。

/etc/udev/rules.d目录下的规则文件是以词典顺序被解析的,在某些情况下这个解析的顺序十分重要。如果我们想要自定义一个rule文件,并且在默认的rule之前执行,那么最好创建一个/etc/udev/rules.d/10-local.rules文件,并把我们自己定义的规则写在里边。

 

rule文件中,所有以"#"开头的行会被当作注释行。所有非空行都是一条规则,规则不能跨越多行。

一个设备可以被多条规则匹配到, 例如, 我们可以写两个匹配同一个设备的规则, 每一个规则为设备提供了它自己的可选命名。即使分开写在不同的rule文件中, 两个可选命名也都会被创建, 要明白一点,udev在找到一个匹配规则后不会停止处理其他规则, 它仍然会继续查找并试图应用每条已知的规则。

 

规则语法

每条规则都由一系列的键-值对组成,键-值对之间以逗号分隔。

主要有两个操作符,"==" 用来定义匹配条件,"="用来定义动作

匹配键是用来识别设备的条件,当规则中所有对应设备的匹配键都被匹配以后,规则会被执行,并且触发动作。每条规则至少有一个匹配条件和一个动作。

下边是一个示例:

 

KERNEL=="hdb", NAME="my_spare_disk"

 

这个示例中包含一个匹配键-值对(KERNEL)和一个动作键-值对(NAME)

注意udev不支持任何形式的行连接符, 不要在你的规则里插入任何断行符,这将会导致udev把你的一条规则看做是多条规则但不会按预期的那样工作。

 

基本规则

udev提供了几种不同的匹配键-值用来编写规则。基础的几个如下,更详细的可以去看udevman文档。

  • KERNEL - 匹配设备在内核中对应的名称
  • SUBSYSTEM - 匹配设备对应的子系统名称
  • DRIVER - 匹配设备的驱动名称

 

在定义了匹配设备的条件以后,接下来就是定义执行的动作。基础动作有如下两个,更详细的其他动作可以看udevman文档。

  • NAME - 设备节点要使用的名字
  • SYMLINK - 一个符号连接列表,作为设备节点的其他别名

 

UDEV只给每个设备创建一个真实节点,如果要给这个设备起其他别名,必须使用符号连接。应用SYMLINK动作,我们可以定义一系列指向真实节点的符号连接。

在此,我们介绍一个新的操作符"+=" ,我们可以在规则中附加多个符号连接,每个连接用空格分隔。下边是一个示例:

 

 KERNEL=="hdb", NAME="my_spare_disk"

上面规则意思是:匹配一个设备命名为hdb的设备,把它重新命名为my_spare_disk. 设备节点出现在/dev/my_spare_disk.

 

 KERNEL=="hdb", DRIVER=="ide-disk", SYMLINK+="sparedisk"

上面规则意思是:匹配一个内核命名为hdb以及驱动为ide-disk的设备,命名设备节点为缺省名字,同时创建一个指向它的名为sparedisk的符号链接。注意到我们没有指明设备节点名字,于是udev使用了缺省名字。为了保留标准/dev布局,你自己的规则通常没有设定NAME,但会创建一些SYMLINK并/或执行其他赋值操作。

 

 KERNEL=="hdc", SYMLINK+="cdrom cdrom0"

上面规则很可能就是我们最常会用到的典型规则。它创建了/dev/cdrom和/dev/cdrom0两个符号链接,都指向/dev/hdc,可以看到没有使用NAME赋值键,所以使用缺省的内核名字(hdc)。

 

匹配sysfs属性

到目前为止介绍的匹配键仅仅提供了有限的匹配能力。实际上我们需要更加详细精准的控制:我们想基于设备的高级属性来识别设备, 如供应商编码, 产品编号, 序列号, 存储空间大小, 分区数等等.

许多驱动程序会导出这些信息到sysfs, udev允许我们使用ATTR键通过稍捎不同的语法来合并sysfs匹配到自己的规则中。

这里有一个匹配sysfs中单个属性例子. 更多细节将在稍后的部分中提供。 

 SUBSYSTEM=="block", ATTR{size}=="234441648", SYMLINK+="my_disk"

 

设备级联

linux内核实际上以树状结构展示设备, 这种树状关系可以通过sysfs查看,在编写我们自己的规则时这非常有用。例如我的硬盘是一个SCSI磁盘设备的子设备, 这个SCSI磁盘设备又是一个ATA控制器设备的子设备, 该控制器又是PCI总线设备的子设备。你很有可能发现你需要从一个子设备的上级设备那里取得某些信息, 比如我的硬盘序列号就没有在它自己的信息里体现, 而是在它上级的SCSI磁盘设备中。

目前介绍的四个主要匹配键(KERNEL/SUBSYSTEM/DRIVER/ATTR)仅仅跟对应设备的值匹配, 而不跟其上级设备的值匹配。

udev提供了在树中向上查找的匹配键变量:

KERNELS - 匹配设备在内核中对应的名称,或任何它的上级设备在内核中的名称

SUBSYSTEMS - 匹配设备的子系统名,或任何它的上级设备的子系统名

DRIVERS - 匹配支持设备的驱动名,或任何它的上级设备的驱动名

ATTRS - 匹配设备的sysfs属性,或任何它的上级设备的sysfs属性

看到这里,由于要考虑到级联结构,你可能感觉到规则书写变的有点复杂了,别急,歇一会吧,有工具可以帮助我们的,后边会提到。

 

字符串替换

当要编写规则处理多个相似的设备时, udev可以使用类似C语言的printf函数中的字符串替换操作符。你可以在规则里面的任何赋值操作中包含这些操作符, udev在它们执行时会自动计算。

最常用的操作符是%k和%n。%k计算设备的内核名, 例如设备的"sda3"将(缺省)出现在/dev/sda3. %n计算设备(存储设备的分区号)的内核号码, 例如"3"将被换成"/dev/sda3".

udev也提供了一些高级功能替换操作符. 在读完本文剩下内容后可以查询udev的man文档。以上例子中的操作符也有一个可选的语法 - $kernel和$number。

因此如果你希望在规则中匹配字符%, 你必需写成%%, 如果你希望匹配字符$, 你必须写成$$。

为阐述下字符串替换的概念,我们来展示几个例子:

 KERNEL=="mice", NAME="input/%k"

 KERNEL=="loop0", NAME="loop/%n", SYMLINK+="%k"

第一条规则确保鼠标设备节点一定出现在/dev/input目录下(缺省是在/dev/mice下面)。第二条规则确保名字为loop0的设备节点在/dev/loop/0创建,也会照常创建一个符号链接/dev/loop0.

上面规则的使用都比较可疑,因为他们都可以通过不使用任何替换操作符来重写. 这些替换的真正威力将会在下一节显现。

 

字符串匹配

不仅有字符串精确匹配, udev也允许你使用shell风格的模式匹配. 支持的3种模式为:

* - 匹配任何字符, 匹配0次或多次

? - 匹配任何字符,但只匹配一次

[] - 匹配任何单个字符, 这些字符在方括号里面指定, 范围是受限的

这里有一些例子, 注意字符串替换符的使用:

 KERNEL=="fd[0-9]*", NAME="floppy/%n", SYMLINK+="%k"

 KERNEL=="hiddev*", NAME="usb/%k"

第一条规则匹配所有软盘驱动并确保设备节点放置在/dev/floppy目录下, 也创建一个缺省名字的符号链接。

第二条规则确保hiddev设备节点只放在/dev/usb目录下面

 

sysfs中查找信息

 

sysfs

为了编写我们自己的规则,我们必须了解要改变的设备具有哪些属性,这些属性的当前值是什么。这些信息可以从sysfs中获得。

sysfs实际上是一个非常简单的结构,逻辑上以目录形式区分。每一个目录包含一定量的文件(属性),这些文件往往都仅仅包含一个值. 也会有一些符号链接,它们把设备链到上级设备那里, 级联结构已在上面说明了。

一些目录被称为顶级设备路径,这些目录拥有对应设备节点的实际设备。顶级设备路径可以被列为包含dev文件的sysfs目录, 下列命令可以列举出这些文件:

#find /sys -name dev

例如, 在我的系统中, /sys/block/sda目录就是我的硬盘设备路径, 它通过/sys/block/sda/device符号链接链向它的上级SCSI磁盘设备。

当我们编写基于sysfs信息的规则时, 只是简单的匹配链条上一部分文件的属性内容. 例如, 我可以这样读我的硬盘的大小:

#cat /sys/block/sda/size

234441648

在一个udev规则里面, 我可以使用ATTR{size}=="234441648"来识别这个磁盘. 因为udev反复遍历设备链的入口,我可以通过ATTRS匹配另外链中的属性(如:/sys/class/block/sda/device属性), 但是在处理链中不同部分时会有一些告诫, 后边部分会提到。

虽然这对于关于sysfs的结构和udev如何匹配值的介绍很有用, 但手工对sysfs的梳理是个既耗时也没必要的事。

 

udevinfo

udevinfo大概就是你用来创建规则的最直接的工具了。只需要知道一个设备的sysfs设备路径。下面是一个精简的例子:

# 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        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"

如上所示,udevinfo会产生一个属性列表,这个列表中的属性可以作为匹配键用在udev规则中。从上边的例子中,我可以产生如下的2条规则:

SUBSYSTEM=="block", ATTR{size}=="234441648", NAME="my_hard_disk"

SUBSYSTEM=="block", SUBSYSTEMS=="scsi", ATTRS{model}=="ST3120827AS", NAME="my_hard_disk"

你可能注意到例子中使用了颜色, 这是为了阐述把设备属性和单个上级设备属性并在一起是合法的, 但是你不能混合匹配多个上级设备属性,这样你的规则是不能工作的。例如,下列规则是不合法的,因为它试图匹配两个上级设备属性:

SUBSYSTEM=="block", ATTRS{model}=="ST3120827AS", DRIVERS=="sata_nv", NAME="my_hard_disk"

通常有大量的属性提供给你,你必需挑选其中一些来创建你的规则。一般来讲,尽可能挑选那些能够固定标志你的设备并便于理解的属性。上例中我选取的是我的磁盘大小和它的型号,而没有使用没有意义的诸如ATTRS{iodone_cnt}=="0×31737"这样的数字。

仔细观察下udevinfo的输出级联结构效果, 设备的绿色部分使用了标准匹配键如KERNEL和ATTR, 蓝色部分和栗色部分使用了上级设备遍历变量如SUBSYSTEMS和ATTRS, 这就是为什么级联结构的复杂性实际上是很容易处理的原因,只要确保使用udevinfo建议的准确值就行了。

另外一点需要指出的是udevinfo输出的文本属性之间用空格填充(例如上面的ST3120827AS)是很常见的。在你的规则中你可以添加额外的空格,也可以像我那样去掉.

使用udevinfo的唯一复杂之处在于要求你知道顶级设备路径(例如上面例子中的/sys/block/sda), 这通常并不明显。但是, 因为你通常是为已经存在的设备节点写规则, 你可以自己使用udevinfo查找设备路径:

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

可选方法

虽然udevinfo差不多是列举你要构建的规则的准确属性的最直接方式, 但一些用户仍然乐于使用其他工具, 诸如usbview的工具可以显示类似的信息集, 这些信息也可以用在规则中。

高级话题

控制权限和所有权

udev允许你在规则中使用另外的赋值来控制每个设备的所有权和权限属性。

GROUP赋值允许你定义哪个Unix组应该拥有设备节点. 这里有一个例子规则, 它定义video组拥有framebuffer设备:

KERNEL=="fb[0-9]*", NAME="fb/%n", SYMLINK+="%k", GROUP="video"

OWNER键可能用处不大, 它允许你定义哪个Unix用户应该具有设备节点的拥有权限. 假设有个临时情况要你让john拥有软盘设备,你可以使用:

KERNEL="fd[0-9]*", OWNER="john"

udev缺省用Unix的0660权限(拥有者和组员拥有读写功能)创建设备节点. 需要的话你可以在特定设备的规则中使用包含MODE赋值键覆盖这些缺省值. 作为例子,下面的规则定义了inotify节点可以被每个人读写:

KERNEL=="inotify", NAME="misc/%k", SYMLINK+="%k", MODE="0666"

 

使用外部程序来命名设备

某些情况下你可能要求比udev标准规则提供的更多弹性, 这种情况下你可以请求udev运行一个程序并运用程序的标准输出来提供设备命名。

要使用这个功能,你只需简单的在PROGRAM赋值中指定要运行的程序(以及参数)的完整路径, 然后在NAME/SYMLINK赋值中使用一些%c替换.

下列例子引用一个位于/bin/device_namer的虚构程序。device_namer带一个表示内核名字的命令行参数, 基于内核名device_namer会做一些变换接着产生一些输出到标准输出stdout,这些输出被分割为很多部分, 每一部分是一个单词,各部分之间用一个空格分开。

在我们的第一个例子中, 我们假设device_namer输出一些信息, 每一部分形成当前设备的一个符号链接。

KERNEL=="hda", PROGRAM="/bin/device_namer %k", SYMLINK+="%c"

下一个例子假设device_namer输出分为i两个部分,第一部分是设备名字, 第二部分是另外的符号链接名字. 我们现在介绍%c[N]替换, 它指向输出的第N部分:

KERNEL=="hda", PROGRAM="/bin/device_namer %k", NAME="%c{1}", SYMLINK+="%c{2}"

再下个例子假设device_namer输出第一部分是设备名, 后面跟着的其他部分将形成另外的符号链接。我们现在介绍%c{N+}替换, 它将被计算为N, N+1, N+2…直到输出结束。

KERNEL=="hda", PROGRAM="/bin/device_namer %k", NAME="%c{1}", SYMLINK+="%c{2+}"

PROGRAM的输出也可在赋值键中使用,而不仅仅是NAME和SYMLINK中。下面例子使用一个虚构程序来决定哪个Unix组拥有设备:

KERNEL=="hda", PROGRAM="/bin/who_owns_device %k", GROUP="%c"

特定事件发生时运行外部程序

另外一个书写udev规则的原因是为了在设备连接或者断开时运行一个特定程序。

例如, 你可能想在你的数码相机连到系统时执行一个脚本来自动下载相机里面的所有照片。

不要把这个跟前边所说的的PROGRAM功能弄混淆了, PROGRAM是用来产生设备名字(除此之外不应该做其他事情)的程序。但这些程序执行时, 设备节点设备节点还没有被创建, 所以对设备的任何形式的操作都是不可能的。

这里介绍的功能允许你在设备节点到位后运行一个程序。This program can act on the device, however it must not run for any extended period of time, because udev is effectively paused while these programs are running. One workaround for this limitation is to make sure your program immediately detaches itself. (这一段不知是何意,请知道的高手指点)

这里有个展示RUN赋值的例子:

KERNEL=="sdb", RUN+="/usr/bin/my_program"

当/usr/bin/my_program执行时, udev环境的各部分可作为环境变量可用,包括诸如SUBSYSTEM的键值。你也可以使用ACTION环境变量来检测设备是否连接或断开, 它的值是"add"和"remove"其中的一个。

udev并不在任何激活终端中运行这些程序,也不再shell上下文中执行. 确信你的程序是被设置了可执行权限, 如果它是个shell脚本请确保它以适当的shabang开头(比如: #!/bin/sh)也不要期望任何标准输出出现在你的终端上。

环境交互

udev为环境变量提供了一个ENV键, 即可用来匹配也可用来赋值.

在赋值情况下,你可以设置稍后匹配的环境变量. 你也可以设置环境变量,提供给触发的外部程序使用。一个虚构的设置环境变量的例子规则如下:

KERNEL=="fd0", SYMLINK+="floppy", ENV{some_var}="value"

在匹配情况下你可以确保规则仅仅依赖一个环境变量的值而运行. 注意udev看到的环境跟你在控制台上得到的用户环境不一样. 一个虚构的涉及环境匹配的规则如下:

KERNEL=="fd0", ENV{an_env_var}=="yes", SYMLINK+="floppy"

上面规则仅仅在udev环境中的$an_env_var的值设为"yes"时才创建/dev/floppy链接.

其他附加选项

另外一个有用的赋值是OPTIONS列表,可用的选项不多:

all_partitions - 为一个块设备创建所有可能的分区, 而不是初始检测到的那些分区

ignore_device - 完全忽略事件

last_rule - 确保后面的所有规则不会有效

例如, 下面规则设置我的硬盘节点的组所有权,并且后面的规则对它没有任何效果:

KERNEL=="sda", GROUP="disk", OPTIONS+="last_rule"

例子

USB 打印机

我启动我的打印机, 它就被赋予了一个设备节点/dev/lp0。我对这样的单调的名字不满意并打算使用udevinfo帮我写一个规则来提供一个可选名字:

# 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"

我的规则变成了这样:

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

   

USB相机

跟大多数相机一样, 我的相机标识自己为一个通过USB总线来连接通过SCSI传输的外部硬盘。为了访问我的相片我先挂载驱动然后拷贝图片文件到我的硬盘中。

不是所有相机都这样工作, 其中一些使用非存储协议,如gphoto2支持的相机。在gphoto情况下,你不用为你的设备写任何规则,因为纯粹由用户空间控制(而不是指定的内核驱动)。

USB相机设备的一个通常的复杂性在于它们通常标识自己是一个单分区磁盘,即带有/dev/sdb1的/dev/sdb。sdb节点对我毫无用处,但对sdb1有兴趣 - 这才是我要挂载的。这里有个麻烦因为sysfs是链式的, udevinfo为/dev/sdb1产生的有用属性跟为/dev/sdb产生的一样, 这导致你的规则潜在的匹配到原始磁盘和分区, 这不是你想要的, 你的规则应该明确的。

为解决这个问题,你需要简单的考虑下sdb和sdb1之间有什么区别. 令人惊奇的简单: 只是名字上的区别, 所以我们可在NAME域上使用一个简单的模式匹配.

# 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"

我的规则: 

KERNEL=="sd?1", SUBSYSTEMS=="scsi", ATTRS{model}=="X250,D560Z,C350Z", SYMLINK+="camera"

USB硬盘

USB硬盘跟USB相机差不多,但典型的使用方式不同. 在相机例子中, 我有讲到我对sdb节点没有兴趣, 它仅仅在分区(比如使用fdisk)时才有用, 但我为什么要为我的相机分区呢?

当然如果你有一个100GB的USB硬盘, 你希望为它分区是很好理解的, 这种情况下我们可以使用udev的字符串替换长处:

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

这个规则创建诸如下面的符号链接:

/dev/usbhd - 可被fdisk使用的node

/dev/usbhd1 - 第一块分区(可挂载)

/dev/usbhd2 - 第二块分区(可挂载)

USB读卡器

USB读卡器(CompactFlash, SmartMedia等)属于USB存储设备的另外一种范围, 它有不同的使用需求.

这些设备特别的在媒介改变时不用通知主机. 所以如果你插入没有媒介的设备,接着插入一张卡, 计算机不会意识到这点, 你也不会有媒介的可挂载的sdb1分区节点.

一个可能的解决办法是使用all_partttions选项优点, 它将为每个规则匹配的块设备创建16个分区节点:

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

你将得到这些命名节点:cfrdr, cfrdr1, cfrdr2, cfrdr3, …, cfrdr15.

USB Palm导航仪

这些设备作为USB串行设备工作, 所以缺省的你仅仅得到ttyUSB1设备节点. palm工具依赖于/dev/pilot, 一些用户希望使用一条规则提供这个.

Carsten Clasohm的博客上有完整的源. Carsten的规则如下:

SUBSYSTEM=="usb", ATTRS{product}=="Palm Handheld", KERNEL=="ttyUSB*", SYMLINK+="pilot"

注意到产品字符串因产品不同而不同, 所以确保你检查(使用udevinfo)了哪一个可以应用到你自己的产品.

CD/VCD驱动

我的电脑有两个光驱: 一个DVD只读驱动(hdc)和一个DVD刻录机(hdd). 我不希望这些设备节点改变除非我物理性的重新接线, 但是一些用户喜欢拥有诸如/dev/dvd这么方便的设备节点.

我们知道这些设备的KERNEL名字, 规则书写就很简单了. 这是我的系统上一些规则:

SUBSYSTEM=="block", KERNEL=="hdc", SYMLINK+="dvd", GROUP="cdrom"

SUBSYSTEM=="block", KERNEL=="hdd", SYMLINK+="dvdrw", GROUP="cdrom"

网卡

尽管它们都是通过名字引用,网卡往往没有与之关联的设备节点. 尽管这样,规则书写过程还是相同的。

在规则中简单的匹配网卡MAC地址是有意义的,因为它们是唯一的。但是, 确信你使用的是udevinfo显示的准确MAC地址, 因为如果你没有精确匹配,你的规则不会工作.

# 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"

这是我的规则:

KERNEL=="eth*", ATTR{address}=="00:52:8b:d5:04:48", NAME="lan"

为了让这个规则生效你得重启网络驱动, 你可以卸载并重新加载模块或简单的重启系统即可. 你还得需要重新配置你的系统使用"lan"取代"eth0". 我以前遇到过这样的麻烦(网卡不能重命名)直到我去除了所有对eth0的引用. 在此之后你应该可以在任何ifconfig或类似的工具的调用中使用"lan"而不是"eth0"了.

测试和调试

让你的规则跑起来

假定你在一个有inotify支持的最近内核上工作, udev将自动监视你的规则目录并且自动接管你对规则文件的任何修改。

尽管这样, udev也不会自动重新处理所有设备并试图应用新规则。例如, 如果你写了个规则来为你的已连接相机添加一个额外符号链接, 你不能指望这个符号链接可以马上显现出来。

为使符号链接显示, 你可以断开并重连你的相机或者在非可移除设备情况下运行udevtrigger。

如果你的内核没有inotify支持, 新规则不会自动被检测到。这种情况下你必需在做出更改后运行udevcontrol reload_rules使之生效.

udevtest

如果你知道sysfs中的顶级设备路径, 你可以使用udevtest来显示udev将要执行的动作, 这可能会帮你调试你的规则. 例如, 假设你想调试作用在/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'

注意/sys前缀在udevtest命令行中被删除了, 这是因为udevtest在设备路径上操作. 还要留意的是udevtest是一个纯粹的测试/调试工具, 它不创建任何设备节点无论输出怎么建议。

作者以及联系方式

本文由Daniel Drake<dan@reactivated.net>写就. 欢迎反馈信息.

对于技术支持你可以致信给linux-hotplug邮件列表: linux-hotplug-devel@lists.sourceforge.net

Copyright (C) 2003-2006 Daniel Drake.

This document is licensed under the GNU General Public License, Version 2.

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

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

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

    新浪公司 版权所有