Udev编写规则
作者丹尼尔•德雷克(dsd)
版本0.74
最新版本的文档可以在这个网站上找到:
http://www.reactivated.net/writing_udev_rules.html
内容
udev是针对Linux内核2.6及以后版本在用户空间提供一个动态的/ dev目录与持续的设备命名解决方案。 前面的/ dev实现采用的devfs ,现在已经弃用,udev被视它的替代者。 udev 对 devfs是一个敏感的会话区域,进行对比之前你应该阅读 这个文档 。
这些年来,udev的使用规则发生了变化,以及规则本身的灵活性。 在现代系统上,udev为一些即插即用的设备类型提供了持续的命名,不再需要为这些设备自定义规则。 然而,一些用户仍然需要额外的定制。
本文假设您已安装并使用默认配置成功运行udev。 这通常是由你的Linux发行版决定的。
本文档不忽略规则编写的每一个细节,但旨在介绍所有的主要概念。 细节可以在udev的man手册页中找到。
本文档使用各种示例(其中许多是完全虚构的)来说明思想和概念。 并非所有语法都有详细描述,一定要看看示例规则来达到一个完全理解。
- 2008年4月5日v0.74:错误修复。
- 2007年12月3日v0.73:更新为新的udev版本,和一些其他的改进。
- 2006年10月2日v0.72:一个例子中排版错误。
- 2006年6月10日v0.71:Misc基于最近反馈更改,谢谢!
- 2006年6月3日v0.7:完成修订,更适合现代udev。
- 2005年5月9日v0.6:Misc更新,包括udevinfo的信息,groups和permission,logging,udevtest。
- 2004年6月20日v0.55:在多个符号链接添加信息,和一些小更改/更新。
- 2004年4月26日v0.54:添加了一些Debian信息。 微小的修改。 关于Re-reverted信息如何调用您的规则文件;添加如何命名网络接口的信息。
- 2004年4月15日v0.53:微小的修改。 添加关于NAME{ all_partitions }的信息。 添加关于udevinfo的其他技巧信息。
- 2004年4月14日v0.52:恢复使用“udev.rules。 直到udev默认允许其他的文件。 很小的工作。
- 2004年4月6日v0.51:我现在建议用户使用自己的”local.rules”文件,而取代“udev.rules”。
- 2004年4月3日v0.5:轻微的清理和准备udev。
- 2004年3月20日v0.4:一般改进,澄清和清理。 增加了更多的关于usb存储设备的写作规则。
- 2004年2月23日v0.3:重写部分强调sysfs命名是如何工作的,以及它如何可以匹配。 更新生成规则的部分,新的SYSFS {filename} udev 仅用18s 。 改进的小节澄清了许多细节。 添加KDE信息。
- 2004年2月18日v0.2:一个例子固定的一个小疏忽。 更新的识别部分、大容量设备。 更新nvidia(英伟达)部分。
- 2004年2月15日v0.1:首次出版。
一个基本的介绍,可能不完全准确。
典型的基于linux的系统上 / dev 目录用于存储系统中设备设备类文件节点。 每个节点指向一个系统中的一个设备,这可能存在或可能不存在。 用户空间的应用程序可以使用这些节点作为与系统硬件设备的接口,例如,Xserver将监听/dev/input/mice,以便它可以与用户的鼠标移动和虚拟鼠标指针移动关联。
最初的 / dev 目录只是存放每个可能插入系统中的设备, / dev目录通常非常大就是因为这个。 devfs 仅用来提供一个更易于管理的方法(值得注意的是,/ dev目录下的文件只表示插入系统中的硬件),以及一些其他的功能,但系统被证明有一些不容易确定的问题。
udev 是/dev目录新的管理方式,旨在去掉先前实现存在的一些问题,并提供一个更稳定的途径。为了创建和命名系统中设备的 / dev 目录下的设备节点,udev需要依赖用户提供的 sysfs 规则中的信息 。 本文档旨在详细说明唯一必须由用户实现的规则匹配实现的写法。
sysfs是2.6内核中的一个新的文件系统,由内核管理,并提供关于但前系统中设备的基本信息,udev可以使用这些信息来创建设备相对应的设备节点。 Sysfs文件系统挂载在 / sys 目录下并可浏览,如果需要查看在此处保存的文件udev之前,在本文中,我将使用终端与 / sys 和 sysfs 交互。
udev规则灵活并且非常强大,这里介绍一些您可以使用规则实现的:
- 1,从默认的名称重命名一个设备节点
2,通过指定的设备节点名称为设备创建软链接
- 3,根据程序的输出来命名一个设备的节点名称
4,更改设备节点的权限和所有者权限
- 5,当创建或删除设备节点时执行脚本(通常当一个设备连接或断电时)
6,重命名网络接口
当设备不存在设备节点,甚至没有可以使用的规则时,编写规则不是一个应急的方案,此时udev将使用内核支持的默认名称为设备创建设备节点。
为设备节点命名固定的名称有几个优点,假设有两个USB存储设备:一个数码相机和一个闪存盘,这些设备通常指定设备节点 sda 和 /dev/sdb ,但具体的分配取决于他们最初的连接顺序,一些用户产生疑问,如果每个设备每次被命名为一个持久的名称这样有什么好处?如 /dev/camera 和 /dev/flashdisk 。
udev为一些即插即用的设备类型提供了固定的命名。 这是一个非常有用的功能,在很多情况下,意味着你不需要再写任何规则。
Udev为dev/disk 目录的即插即用的存储设备提供持久命名, 查看为存储设备创建的固定的名称,您可以使用以下命令:
# ls -lR /dev/disk
这适用于所有存储类型。 作为一个例子,udev为root分区创建了持久命名的软连接 /dev/disk/by-id/scsi-SATA_ST3120827AS_4MS1NDXZ-part3, 当插入USB闪存盘的时候udev创建了/dev/disk/by-id/usb-Prolific_Technology_Inc._USB_Mass_Storage_Device-part1, 这也是一个固定的名字。
执行哪个添加动作可以决定在什么时候以及如何命名设备呢?udev读取一系列规则文件, 这些文件保存在 /etc/udev/rules.d 目录,他们都必须有 .rules 后缀。
默认的udev规则存储在 /etc/udev/rules.d/50-udev.rules 。 这个文件你会看起来很有趣,它包括几个例子,然后提供里一些默认的规则证明一个设备文件系统样式的 / dev布局。 然而,你不应该直接将规则写入该文件。
在目录/etc/udev/rules. d /中的文件使用lexical按顺序进行解析,在某些情况下,规则解析的顺序是很重要的。 一般来说,你可能想要自己的规则在默认规则之前解析,所以建议在/etc/udev/rules.d/10-local.rules目录下创建一个文件并且把你所有的规则写进这个文件。
在一个规则文件里,以“#”开始的行被当作注释。 其他所有非空白行是作为规则,规则不能跨越多个行。
一个设备可以被多个规则匹配。 这有实际的好处,例如,我们可以写两个规则匹配相同的设备,每个规则为设备提供自己的别。 即使规则是在单独的文件中,两个名称都将被创建,所以当udev发现一个匹配的规则时将不会停止处理,它将继续搜索并尝试尝试应用每一个找到的匹配规则。
每个规则是由一系列键值对构成,之间用逗号分割。 匹配 键是用来识别将要作用的设备的条件条件。 当在一个规则里的所有符合设备的匹配键处理完之后,然后请求应用规则的行为。 每个规则都应该包括至少一个匹配键和至少一个赋值键。
这里有一个例子来说明上面的规则:
KERNEL=="hdb", NAME="my_spare_disk"
上述规则包含一个匹配键( KERNEL)和一个赋值键(NAME),这些键的语义及其属性将在稍后描述。 要注意,匹配键对应的值使用运算符(= =),而赋值键对应的值使用赋值运算符(=)。
注意:udev不支持任何形式的行连接符,不要插入任何换行符在规则中,因为这将导致udev认为你一个规则作为多个规则以致不能按预期工作。
udev提供了编写规则时可以用来精确匹配设备的的匹配键。 下面介绍了一些最常见的键,其他将在本文的后面介绍。 有关完整列表,请参见udevman手册页。
- KERNEL-匹配设备在内核中对应的名称
- SUBSYSTEM -匹配设备在子系统中对应的名称
- DRIVER -匹配设备在驱动程序中对应的名称
当使用一系列匹配键精确的匹配设备之后,udev接下来通过一系列赋值键提供你精细控制下步做什么。赋值键的完整列表,请参阅udev man手册页。 下面介绍最基本的赋值键。 其他将在本文的后面介绍。
- NAME——设备节点对应的名称
- SYMLINK —— 作为设备节点的软链接名称列表
如前所述,udev只对一个设备创建一个真正的设备节点。如果你希望为这个设备设备节点提供别名,您可以使用符号链接的功能。 对SYMLINK赋值,事实上维护了一个指向真实设备节点的列表。 为了操纵这些链接,我们介绍一个新的添加操作符: + = ,您可以从任何依赖空格符号分割的规则添加多个软链接到列表中。
KERNEL=="hdb", NAME="my_spare_disk"
上面的规则说明了: 匹配一个被内核命名为hdb的设备,调用hdb,命名设备节点为my_spare_disk,设备节点将出现在 /dev/my_spare_disk 。
KERNEL=="hdb", DRIVER=="ide-disk", SYMLINK+="sparedisk"
上面的规则说明里: 匹配一个被内核命名为hdb并且驱动为ide-disk的设备,使用默认名称命名设备节点并且创建为它一个名字为sparedisk的软链接。但是注意,我们没有指定设备节点名称,所以udev使用默认。 为了保持 / dev 布局标准,自己的规则通常会放弃NAME,但创建一些软链接和/或执行其他任务。
KERNEL=="hdc", SYMLINK+="cdrom cdrom0"
上面的规则可能是更典型的类型的规则。 它创建了/dev/cdrom和/dev/cdrom0两个符号链接,都指向/dev/hdc,可以看到没有使用NAME赋值键,所以使用缺省的内核名字(hdc)
到目前为止介绍的匹配键只提供了有限的匹配能力。 实际上我们需要更加详细精准的控制:我们想要基于高级属性确定设备,如供应商编码,产品编号,序列号,存储能力,分区数量等。
许多驱动输出这些信息到sysfs文件系统,udev允许我们使用sysfs-matching合并到我们的规则中,使用 ATTR 关键字语法稍有不同。
这里有一个从sysfs匹配单个属性的规则的例子。 在本文的后面将提供进一步的基于sysfs属性编写规则的细节。
SUBSYSTEM=="block", ATTR{size}=="234441648", SYMLINK+="my_disk"
Linux内核实际上使用树状结构描述设备,该信息是通过sysfs公开并对编写规则很有用。 举个例子,我的硬盘设备表示为SCSI磁盘设备的一个孩子,依次又是一个串行ATA控制器设备的孩子,依次是一个PCI总线设备的子设备。很可能你会发现你需要从一个设备的上级设备查找自己需要的信息,例如我的硬盘设备的序列号不是包含在设备层面,而是包含在其直接父亲SCSI磁盘级别。
到目前为止介绍的四个主要匹配键(KERNEL/SUBSYSTEM/ ATTR /DRIVER)只匹配值对应的设备的问题,并不从父设备匹配对应的值。 udev提供了各种通过树状结构搜索上游匹配键的方法:
- KERNELS-匹配设备在内核中对应的名称,或任何它的上级设备在内核中的名称
- SUBSYSTEMS -匹配设备在子系统中的名称,或任何它的上级=设备在子系统中的名称
- DRIVERS -匹配设备在驱动程序中的名称,或任何它的上级设备在驱动程序中的名称
- ATTRS -匹配设备的sysfs属性,或任何它的上级设备的sysfs属性
考虑到层次原因,你可能感觉到书写规则变得有点复杂。 放心,这里有可以使用的工具帮助我们,这将在后面介绍。
在编写规则时可能会处理多个类似的设备,udev的printf-like string字符串替换操作符是非常有用的。 您可以在任何赋值规则中简单的包含这些操作,执行时,udev将评估他们。
最常见的操作是 % k 和 % n 。 % k获取设备在内核中的名称例如: /dev/sda3(默认)中的设备’sda3’。 % n 获取设备在内核中的编号(存储设备的分区编号),如 “3” /dev/sda3 。
udev还提供了其他一些高级的替换操作。 在阅读本文档的其余部分后查阅udev man手册页,上面的例子中还有一些其他的语法-$kernel和$number。出于这个原因,如果你希望在一个规则中匹配字母%那么你必须写为 % % ,如果你想匹配字母$然后你必须写 $ $ 。
为了说明字符串替换的概念,一些示例规则如下所示。
KERNEL=="mice", NAME="input/%k"
KERNEL=="loop0", NAME="loop/%n", SYMLINK+="%k"
上面的第一条规则确保mice的设备节点只出现在/dev/input这个目录位置(默认情况下在 /dev/mice),第二条规则确保在/dev/loop/0创建命名为loop0的这个设备节点的同时在/dev/loop0这个位置创建一个普通的软链接。
对于上面上面的规则可能觉得即使不使用任何替换操作也能实现这些操作,这些替换操作的真正功能将会在下一节展示的比较明显。
除了可以字符串匹配,udev还允许您使用shell风格模式进行匹配。 有三种模式支持:
- * 匹配任何字符,零个或多个
- ? ——匹配任意一个字符
- [] 匹配括号中指定范围内的任意单个的字符
这里有一些混合使用上述模式的例子。 注意字符串替换操作的使用,
KERNEL=="fd[0-9]*", NAME="floppy/%n", SYMLINK+="%k"
KERNEL=="hiddev*", NAME="usb/%k"
第一条规则匹配所有软盘驱动器,并确保设备节点放置在 /dev/floppy 目录,以及使用默认名称创建一个符号链接。 第二条规则确保hiddev设备只出现在 /dev/usb 目录中。
上面简单探索了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 (类Debian系统中被udevadm取代) 这可能是你可以构建规则最简单的工具。 你只需要知道设备的sysfs设备路径。 一个整理后的示例如下所示:
# udevinfo -a -p /sys/block/sda ( udevadm info -a -p /sys/class/net/eth0)
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"
如您所见,u你可以在你的规则文件里原封不动的使用devinfo处理一个属性列表,作为匹配键。 从上面的例子中,我可以为设备生成下面的两个规则:
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 x31737”。
观察udevinfo (类Debian系统中被udevadm取代) 输出层次结构的内容, 使用KERNEL和ATTR等标准匹配键的绿色的部分对应问题中的设备。 蓝色的和栗色的部分表示使用跳转变量(如SUBSYSTEMS、ATTRS)对应的指定的父设备r。这就是为什么引入复杂的层次结构,为了更容易处理,一定要使用udevinfo建议使用的精确值。
另外要注意的一点是常见的在udevinfo输出中使用空格填补的文本属性(例如,见上面的ST3120827AS)。 在你的规则,你可以指定额外的空格,或者像我一样删除他们。
使用udevinfo唯一复杂的地方就是你需要知道设备的顶级路径(在上面的示例中/ sys / block / sda)。 但这并不常见,因为你通常是为已经存在的设备节点写规则,您可以使用udevinfo查找你的设备路径:
# udevinfo -a -p $(udevinfo -q path -n /dev/sda)
尽管udevinfo几乎肯定是建立规则时查看属性的最直接的方法,一些用户还是比较喜欢使用一些其他的方法, 如一些使用工具: usbview 显示一组类似的设置信息,这些工具大部分可以在规则中使用。
udev允许您使用额外的规则来控制每个设备的所有权和权限属性。
你可以GROUP定义哪个Unix组应该拥有设备节点。有一个定义哪个video group可以拥有framebuffer设备所有权的例子:
KERNEL=="fb[0-9]*", NAME="fb/%n", SYMLINK+="%k", GROUP="video"
关键字OWNER也许不那么有用,它允许你定义哪个Unix用户应该拥有设备节点的权限。 假设有个奇怪的情况, 你想要约翰 拥有你的软盘设备的所有权,您可以使用:
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奇迹般的产生一些输出至标准输出管道,分成进入几个部分,只是一个词,每个部分都是被一个单独的空间隔开的。
在我们的第一个例子中,我们假设device_namer有多个输出,每个输出形成一个需要的设备的符号链接(替代名称)。
KERNEL=="hda", PROGRAM="/bin/device_namer %k", SYMLINK+="%c"
下一个例子假设device_namer输出两部分,第一部分时设备名称,第二部分是一个额外的符号链接名称。 现在我们使用 % 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+}"
程序输出内容可以在任何赋值键中使用,不仅NAME和SYMLINK。 下面的示例使用一个虚构的程序来决定哪个Unix组应该拥有设备所有权:
KERNEL=="hda", PROGRAM="/bin/who_owns_device %k", GROUP="%c"
编写udev规则的另一个原因是当一个设备连接或断开连接时运行一个特定的程序。 例如,当你的数码相机连接的时候,您可能想要执行一个脚本自动从里面下载你所有的照片。
不要和上面描述的PROGRAM功能混淆。 PROGRAM 用于运行生成设备名称的程序(他们没有任何对比性),这些程序被执行时,设备节点还没有被创建,所以不可能在这些设备上起任何作用。
这里介绍的功能允许你运行一个程序,当设备节点在适当位置创建的时候, 这个程序可以在设备上,但是它不能运行在任何时间段,因为当这些程序运行时udev实际上被暂停了。 这种限制的解决方案就是确保程序可以立即结束。
这里有一个例子演示了RUN 的赋值:
KERNEL=="sdb", RUN+="/usr/bin/my_program"
当 /usr/bin/my_program 执行时,udev环境的各个部分都可以作为环境变量使用,包括键值如SUBSYSTEM。 您还可以使用 ACTION 环境变量来检测设备是否连接或断开连接-ACTION分别为“add”或“remove”。
Udev不在任何活动的终端上运行这些程序,也不在shell上下文中执行它们。 一定要确保你的程序是可执行的,如果它是一个shell脚本确保它从一个适当的语句开始 (如。#!/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"
我打开我的打印机,并且给它分配了一个设备节点 /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总线连接、支持SCSI传输的外部硬盘。 我访问我的照片,挂载驱动和复制图片文件到我的硬盘。
并不是所有的相机都按这种方式工作:其中一些使用非磁盘协议,如相机所支持的gphoto2 。 在gphoto情况下,它纯粹直接由用户空间直接控制,你不需为你的设备编写规则(而不是一个特定的内核驱动程序)。
常见的USB摄像机设备他们通常被识别为一个磁盘只有一个分区的磁盘,在这种情况下就是 /dev/sdb 的 /dev/sdb1 。 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相机差不多,但是通常使用模式不同。 在相机的例子中,我解释说,我对使用sdb这个节点名字不是很感兴趣——这是唯一使用的分区(比如fdisk),但是为什么还要再分区这是一个相机! ?
当然,如果你有一个100 gb的USB硬盘,,你可能想要区分它是完全可以理解的,在这种情况下,我们可以利用udev字符串替换的优点:
KERNEL=="sd*", SUBSYSTEMS=="scsi", ATTRS{model}=="USB 2.0 Storage Device", SYMLINK+="usbhd%n"
这条规则创建软链接,如:
USB读卡器(CF闪存卡,SM卡等)是另一种使用需求不同的USB存储设备。
这些设备通常不通知主机其上的媒体的变化。 所以,如果你插入没有存储媒介的设备,然后插入一个卡,电脑无法识别到,并且也不能挂载sdb1分区。
一种可能的解决方案是利用 all_partitions 选项,该选项将为规则匹配的每个块设备创建16个分区节点:
KERNEL="sd*", SUBSYSTEMS=="scsi", ATTRS{model}=="USB 2.0 CompactFlash Reader", SYMLINK+="cfrdr%n", OPTIONS+="all_partitions"
你现在有命名节点:cfrdr,cfrdr1,cfrdr2,cfrdr3,…… ,cfrdr15。
这些设备使用USB转串口方式工作,因此默认情况下,只有 ttyUSB1 设备节点。 掌上设备依赖 /dev/pilot ,所以很多用户想要使用规则提供这个节点。
这条规则来源于Carsten Clasohm的博客文章 。 Carsten的规则如下所示:
SUBSYSTEMS=="usb", ATTRS{product}=="Palm Handheld", KERNEL=="ttyUSB*", SYMLINK+="pilot"
注意product字符串似乎因产品而异,所以你要确保检查 (使用udevinfo) 哪一个适用于你。
我这个计算机上有两个光盘驱动器:一个DVD播放器(hdc)和一个DVD刻录机(hdd)。 我不希望这些设备节点变化, 除非我物理上重新接入系统, 然而,许多用户更喜欢 /dev/dvd 这样方便的设备节点名称。
在我们知道这些设备的KERNEL名称的情况下,制定规则很简单, 这里有一个针对我的系统的例子:
SUBSYSTEM=="block", KERNEL=="hdc", SYMLINK+="dvd", GROUP="cdrom"
SUBSYSTEM=="block", KERNEL=="hdd", SYMLINK+="dvdrw", GROUP="cdrom"
网络接口通常不具备和它们引用的名字有关联的设备节点。 尽管如此,规则的写法几乎是一样的。
只需在规则中简单的和你的网卡的mac地址进行匹配,因为mac地址这是独一无二的。 然而,必须确保您使用的MAC地址和udevinfo 显示的是一致的,否则,您的规则将不能按预期工作。
# 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 eth0”或类似的工具使用中使用’lan’而不必使用‘eth0’了。
假如你使用的是最新的支持inotify 的内核, udev将自动监控规则目录并自动应用对规则文件的任何修改。
尽管如此,udev不会自动处理所有设备或者应用新的规则(s)。 例如,当你的相机在插入系统的情况下,制定了一个为其添加一个额外的软链接的规则,不要指望这个软链接能立刻出现。
你可以断开并重新连接你的相机使这个链接出现,或者如果不是可移动设备,您也可以运行 udevtrigger 实现。
如果您的内核inotify,新规则将不会被自动检测到。 在这种情况下,对规则文件做修改后您必须运行 udevcontrol reload_rules 使修改生效。
如果你知道设备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'
注意 在udevtest的命令行参数中没有 / sys 前缀 ,这是因为udevtest操作只依赖设备路径。 还要注意,udevtest纯粹是一个测试/调试工具,它并不创建任何输出内容中包含的设备节点。
本文档由丹尼尔·德雷克< dan@reactivated.net >编写。 谢谢反馈。
技术支持,发送: linux-hotplug 订阅邮件列表: linux-hotplug-devel@lists.sourceforge.net 。
版权(C)2003 - 2006丹尼尔·德雷克。
本文档遵守 GNU通用公共许可证,版本2 协议。