织梦CMS - 轻松建站从此开始!

罗索实验室

当前位置: 主页 > 基础技术 > Linux开发专题 >

掌握 udev

jackyhwei 发布于 1970-01-01 08:00 点击:次 
目前很多的Linux分发版本采纳了udev的方式,因为它在Linux设备访问,特别是那些对设备有极端需求的站点(比如需要控制上千个硬盘)和热插拔设备(比如USB摄像头和MP3播放器)上解决了几个问题。下面我我们来看看如何管理udev设备。
TAG:

如果你使用ed50b93cc238dc3b76bc62dad54a590d比较长时间了,那你就知道,在对待设备文件这块,Linux改变了几次策 略。在Linux早期,设备文件仅仅是是一些带有适当的属性集的普通文件,它由mknod命令创建,文件存放在/dev目录下。后来,采用了devfs, 一个基于内核的动态设备文件系统,他首次出现在2.3.46内核中。Mandrake,Gentoo等Linux分发版本采用了这种方式。devfs创建 的设备文件是动态的。但是devfs有一些严重的限制,从2.6.13版本后移走了。目前取代他的便是文本要提到的udev--一个用户空间程序。

目前很多的Linux分发版本采纳了udev的方式,因为它在Linux设备访问,特别是那些对设备有极端需求的站点(比如需要控制上千个硬盘)和热插拔设备(比如USB摄像头和MP3播放器)上解决了几个问题。下面我我们来看看如何管理udev设备。

实际上,对于那些为磁盘,终端设备等准备的标准配置文件而言,你不需要修改什么。但是,你需要了解udev配置来使用新的或者外来设备,如果不修改配置, 这些设备可能无法访问,或者说Linux可能会采用不恰当的名字,属组或权限来创建这些设备文件。你可能也想知道如何修改RS-232串口,音频设备等文 件的属组或者权限。这点在实际的Linux实施中是会遇到的。


为什么使用udev

在此之前的设备文件管理方法(静态文件和devfs)有几个缺点:

*不确定的设备映射。特别是那些动态设备,比如USB设备,设备文件到实际设备的映射并不可靠和确定。举一个例子:如果你有两个USB打印机。一个可能称 为/dev/usb/lp0,另外一个便是/dev/usb/lp1。但是到底哪个是哪个并不清楚,lp0,lp1和实际的设备没有一一对应的关系,因为 他可能因为发现设备的顺序,打印机本身关闭等原因而导致这种映射并不确定。理想的方式应该是:两个打印机应该采用基于他们的序列号或者其他标识信息的唯一 设备文件来映射。但是静态文件和devfs都无法做到这点。

*没有足够的主/辅设备号。我们知道,每一个设备文件是有两个8位的数字:一个是主设备号 ,另外一个是辅设备号来分配的。这两个8位的数字加上设备类型(块设备或者字符设备)来唯一标识一个设备。不幸的是,关联这些身边的的数字并不足够。

*/dev目录下文件太多。一个系统采用静态设备文件关联的方式,那么这个目录下的文件必然是足够多。而同时你又不知道在你的系统上到底有那些设备文件是激活的。

*命名不够灵活。尽管devfs解决了以前的一些问题,但是它自身又带来了一些问题。其中一个就是命名不够灵活;你别想非常简单的就能修改设备文件的名字。缺省的devfs命令机制本身也很奇怪,他需要修改大量的配置文件和程序。;

*内核内存使用,devfs特有的另外一个问题是,作为内核驱动模块,devfs需要消耗大量的内存,特别当系统上有大量的设备时(比如上面我们提到的系统一个上有好几千磁盘时)

udev的目标是想解决上面提到的这些问题,他通采用用户空间(user-space)工具来管理/dev/目录树,他和文件系统分开。知道如何改变缺省配置能让你之大如何定制自己的系统,比如创建设备字符连接,改变设备文件属组,权限等。

udev配置文件

主要的udev配置文件是/etc/udev/udev.conf。这个文件通常很短,他可能只是包含几行#开头的注释,然后有几行选项:

CODE:

udev_root="/dev/"
udev_rules="/etc/udev/rules.d/"
udev_log="err"

上面的第二行非常重要,因为他表示udev规则存储的目录,这个目录存储的是以.rules结束的文件。每一个文件处理一系列规则来帮助udev分配名字给设备文件以保证能被内核识别。
你的/etc/udev/rules.d下面可能有好几个udev规则文件,这些文件一部分是udev包安装的,另外一部分则是可能是别的硬件或者软件包 生成的。比如在Fedora Core 5系统上,sane-backends包就会安装60-libsane.rules文件,另外initscripts包会安装60-net.rules文 件。这些规则文件的文件名通常是两个数字开头,它表示系统应用该规则的顺序。

规则文件里的规则有一系列的键/值对组成,键/值对之间用逗号(,)分割。每一个键或者是用户匹配键,或者是一个赋值键。匹配键确定规则是否被应用,而赋 值键表示分配某值给该键。这些值将影响udev创建的设备文件。赋值键可以处理一个多值列表。匹配键和赋值键操作符解释见下表:
<pre>
                          udev 键/值对操作符
操作符        匹配或赋值t                             解释
----------------------------------------
       ==              匹配                        相等比较
       !=              匹配                    不等比较
       =                  赋值                        分配一个特定的值给该键,他可以覆盖之前的赋值。
       +=           赋值                        追加特定的值给已经存在的键
       :=                  赋值                        分配一个特定的值给该键,后面的规则不可能覆盖它。
</pre>
这有点类似我们常见的编程语言,比如C语言。只是这里的键一次可以处理多个值。有一些键在udev规则文件里经常出现,这些键的值可以使用通配符(*,?,甚至范围,比如[0-9]),这些常用键列举如下:
<pre>
常用udev键
键                 含义
ACTION                     一个时间活动的名字,比如add,当设备增加的时候
KERNEL                     在内核里看到的设备名字,比如sd*表示任意SCSI磁盘设备
DEVPATH              内核设备录进,比如/devices/*
SUBSYSTEM              子系统名字,比如sound,net
BUS                     总线的名字,比如IDE,USB
DRIVER                     设备驱动的名字,比如ide-cdrom
ID                       独立于内核名字的设备名字
SYSFS{ value}              sysfs属性值,他可以表示任意
ENV{ key}              环境变量,可以表示任意
PROGRAM              可执行的外部程序,如果程序返回0值,该键则认为为真(true)
RESULT                     上一个PROGRAM调用返回的标准输出。
NAME                     根据这个规则创建的设备文件的文件名。注意:仅仅第一行的NAME描述是有效的,后面的均忽略。
                                     如果你想使用使用两个以上的名字来访问一个设备的话,可以考虑SYMLINK键。
SYMLINK              根据规则创建的字符连接名
OWNER                     设备文件的属组
GROUP                     设备文件所在的组。
MODE                     设备文件的权限,采用8进制
RUN                     为设备而执行的程序列表
LABEL                     在配置文件里为内部控制而采用的名字标签(下下面的GOTO服务)
GOTO                     跳到匹配的规则(通过LABEL来标识),有点类似程序语言中的GOTO
IMPORT{ type}           导入一个文件或者一个程序执行后而生成的规则集到当前文件
WAIT_FOR_SYSFS         等待一个特定的设备文件的创建。主要是用作时序和依赖问题。
PTIONS                     特定的选项: last_rule 对这类设备终端规则执行; ignore_device 忽略当前规则; ignore_remove 忽略接下来的并移走请求。
                      all_partitions 为所有的磁盘分区创建设备文件。
</pre>
我们给出一个列子来解释如何使用这些键。下面的例子来自Fedora Core 5系统的标准配置文件。

CODE:
KERNEL=="*", OWNER="root" GROUP="root", MODE="0600"
KERNEL=="tty", NAME="%k", GROUP="tty", MODE="0666", OPTIONS="last_rule"
KERNEL=="scd[0-9]*", SYMLINK+="cdrom cdrom-%k"
KERNEL=="hd[a-z]", BUS=="ide", SYSFS{removable}=="1", SYSFS{device/media}=="cdrom", SYMLINK+="cdrom cdrom-%k"
ACTION=="add", SUBSYSTEM=="scsi_device", RUN+="/sbin/modprobe sg"


上面的例子给出了5个规则,每一个都是KERNEL或者ACTION键开头:

*第一个规则是缺省的,他匹配任意被内核识别到的设备,然后设定这些设备的属组是root,组是root,访问权限模式是0600(-rw-------)。这也是一个安全的缺省设置保证所有的设备在默认情况下只有root可以读写。
*第二个规则也是比较典型的规则了。它匹配终端设备(tty),然后设置新的权限为0600,所在的组是tty。它也设置了一个特别的设备文件名:%K。在这里例子里,%k代表设备的内核名字。那也就意味着内核识别出这些设备是什么名字,就创建什么样的设备文件名。

*第三行开始的KERNEL=="scd[0-9]*",表示 SCSI CD-ROM 驱动. 它创建一对设备符号连接:cdrom和cdrom-%k。

*第四行,开始的 KERNEL=="hd[a-z]", 表示ATA CDROM驱动器。这个规则创建和上面的规则相同的符号连接。ATA CDROM驱动器需要sysfs值以来区别别的ATA设备,因为SCSI CDROM可以被内核唯一识别。.

*第五行以 ACTION=="add"开始,它告诉udev增加 /sbin/modprobe sg 到命令列表,当任意SCSI设备增加到系统后,这些命令将执行。其效果就是计算机应该会增加sg内核模块来侦测新的SCSI设备。

当然,上面仅仅是一小部分例子,如果你的系统采用了udev方式,那你应该可以看到更多的规则。如果你想修改设备的权限或者创建信的符号连接,那么你需要熟读这些规则,特别是要仔细注意你修改的那些与之相关的设备。

修改你的udev配置

在修改udev配置之前,我们一定要仔细,通常的考虑是:你最好不要修改系统预置的那些规则,特别不要指定影响非常广泛的配置,比如上面例子中的第一行。不正确的配置可能会导致严重的系统问题或者系统根本就无法这个正确的访问设备。

而我们正确的做法应该是在/etc/udev/rules.d/下创建一个信的规则文件。确定你给出的文件的后缀是rules文件名给出的数字序列应该比 标准配置文件高。比如,你可以创建一个名为99-my-udev.rules的规则文件。在你的规则文件中,你可以指定任何你想修改的配置,比如,假设你 修改修改floppy设备的所在组,还准备创建一个信的符号连接/dev/floppy,那你可以这么写:

CODE:
KERNEL=="fd[0-9]*", GROUP="users",   SYMLINK+="floppy" 

有些发行版本,比如Fedora,采用了外部脚本来修改某些特定设备的属组,组关系和权限。因此上面的改动可能并不见得生效。如果你遇到了这个问题,你就需要跟踪和修改这个脚本来达到你的目的。或者你可以修改PROGRAM或RUN键的值来做到这点。

某些规则的修改可能需要更深的挖掘。比如,你可能想在一个设备上使用sysfs信息来唯一标识一个设备。这些信息最好通过udevinfo命令来获取。

CODE:
$ udevinfo –a –p $(udevinfo –q path      –n /dev/hda)

上 面的命令两次使用udevinfo:一次是返回sysfs设备路径(他通常和我们看到的Linux设备文件名所在路径--/dev/hda--不同);第 二次才是查询这个设备路径,结果将是非常常的syfs信息汇总。你可以找到最够的信息来唯一标志你的设备,你可以采用适当的替换udev配置文件中的 SYSFS选项。下面的结果就是上面的命令输出

CODE:
[root@localhost rules.d]# udevinfo -a -p $(udevinfo -q path        -n      /dev/hda1)

Udevinfo starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

      looking at device '/block/hda/hda1':
    KERNEL=="hda1"
    SUBSYSTEM=="block"
    DRIVER==""
        ATTR{stat}=="        1133         2268            2            4"
        ATTR{size}=="208782"
        ATTR{start}=="63"
        ATTR{dev}=="3:1"

      looking at parent device '/block/hda':
    KERNELS=="hda"
    SUBSYSTEMS=="block"
    DRIVERS==""
        ATTRS{stat}=="       28905        18814      1234781       302540        34087       133247       849708       981336            0       218340      1283968"
        ATTRS{size}=="117210240"
        ATTRS{removable}=="0"
        ATTRS{range}=="64"
        ATTRS{dev}=="3:0"

      looking at parent device '/devices/pci0000:00/0000:00:1f.1/ide0/0.0':
    KERNELS=="0.0"
    SUBSYSTEMS=="ide"
    DRIVERS=="ide-disk"
        ATTRS{modalias}=="ide:m-disk"
        ATTRS{drivename}=="hda"
        ATTRS{media}=="disk"

      looking at parent device '/devices/pci0000:00/0000:00:1f.1/ide0':
    KERNELS=="ide0"
    SUBSYSTEMS==""
    DRIVERS==""

      looking at parent device '/devices/pci0000:00/0000:00:1f.1':
    KERNELS=="0000:00:1f.1"
    SUBSYSTEMS=="pci"
    DRIVERS=="PIIX_IDE"
        ATTRS{broken_parity_status}=="0"
        ATTRS{enable}=="1"
        ATTRS{modalias}=="pci:v00008086d000024CAsv0000144Dsd0000C009bc01sc01i8a"
        ATTRS{local_cpus}=="1"
        ATTRS{irq}=="11"
        ATTRS{class}=="0x01018a"
        ATTRS{subsystem_device}=="0xc009"
        ATTRS{subsystem_vendor}=="0x144d"
        ATTRS{device}=="0x24ca"
        ATTRS{vendor}=="0x8086"

      looking at parent device '/devices/pci0000:00':
    KERNELS=="pci0000:00"
    SUBSYSTEMS==""
    DRIVERS==""


举 一个例子:假设你想修改USB扫描仪的配置。通过一系列的尝试,你已经为这个扫描仪标识了Linux设备文件(每次打开扫描仪时,名字都会变)。你可以使 用上面的命令替换这个正确的Linux设备文件名,然后定位输出的采用SYSFS{idVendor}行和SYSFS{idProduct}行。最后你可 以使用这些信息来为这个扫描仪创建新的选项。

CODE:
SYSFS{idVendor}=="0686", \
SYSFS{idProduct}=="400e", \
SYMLINK+="scanner", MODE="0664", \
group="scanner"


上面的例子表示将扫描仪的组设置为scanner,访问权限设置为0664,同时创建一个/dev/scanner的符号连接。

 

 

udev-FAQ 中文翻译

原文出处 http://www.kernel.org/pub/linux/util...tplug/udev-FAQ
中文翻译 王旭 http://gnawux.blogchina.com
本文档遵循 GPL 2 及以后版本发布,修改、发布请保持许可证不变

问: udev是什么? 它的目的何在?
答: 看看那篇 OLS 2003 上的有关 udev 的文章吧,可以在 docs 目录里找到,也能在这
里找到:

OLS 2003 上还有一个关于 udev 的幻灯片,可以在这里找到:


问: udev 和 devfs 是什么关系
答: udev 完全在用户态 (userspace) 工作,利用设备加入或移除时内核所发送的
hotplug 事件 (event) 来工作。关于设备的详细信息是由内核输出 (export) 到位
于 /sys 的 sysfs 文件系统的。所有的设备命名策略、权限控制和事件处理都是在
用户态下完成的。与此相反,devfs 是作为内核的一部分工作的。

问: 如果 udev 不能完成所有 devfs 的工作的话,为什么把 devfs 标记为
OBSOLETE/removed?
答: 引用 Al Viro (Linux VFS 内核维护者):
- devfs 所做的工作被确信可以在用户态来完成。
- devfs 被加入内核之时,大家寄望它的质量可以迎头赶上。
- devfs 被发现了一些可修复和无法修复的 bug。
- 对于可修复的 bug,几个月前就已经被修复了,其维护者认为一切良好。
- 对于后者,同样是相当常一段时间以来没有改观了。
- devfs 的维护者和作者对它感到失望并且已经停止了对代码的维护工作。

问: 但是当一个并不存在的 /dev 节点被打开的时候,udev 并不能如 devfs 一样自动加
载驱动程序。
答: 的确如此,但 Linux 的设计是在设备被发现的时候加载模块,而不是当它被访问的时
候。

问: 不过等等,我确实希望 udev 可以在不存在的节点被打开的时候自动加载驱动。这是
我使用 devfs 的唯一原因了。给 udev 增加这个功能吧。
答: 不,udev 是用来管理 /dev 的,不是用来加载内核驱动的。

问: 嗨,求你们了。这不难做到的。
答: 这么个功能对于一个配置正确的计算机是多余的。系统中所有的设备都应该产生
hotplug 事件、加载恰当的驱动,而 udev 将会注意到这点并且为它创建对应的
设备节点。如果你不想让所有的设备驱动停留在内存之中,应该使用其它东西来
管理你的模块 (如脚本, modules.conf, 等等) 这不是 udev 的工作。

问: 但是我真的喜欢那个功能,还是加上吧
答: devfs 用的方法导致了大量无用的 modprobe 尝试,以此程序探测设备是否存在。
每个试探性探测都新建一个运行 modprobe 的进程,而几乎所有这些都是无用的。

问: 我喜欢 devfs 的设备文件命名方式,udev 可以这样命名么?
答: 可以,udev 可以使用 /dev 的命名策略来创建节点。通过一个配置文件,可以把内
核缺省的名字映射到 devfs 的名字。可以看看 udev 中带的 udev.rules.devfs 文
件。
注意: devfs 的命名方式是不被建议并且不被官方支持的,因为它所用的简单枚举设
备的方式在设备可能被随时加入或删除的情况下确实是一个比较笨的方法。这些编号
代给你的将只有麻烦,而并不能用来确定设备。看看那个永久性磁盘 (persistent
disk) 的规则就知道如何在用户态下正确的做这件事,而不是傻傻地列出设备。

问: udev 可以为哪些设备创建节点?
答: 所有在 sysfs 中显示的设备都可以由 udev 来创建节点。如果内核中增加了其它设
备的支持,udev 也就自动地可以为它们工作了。现在所有的块设备都在被支持之列,
大部分的主字符设备也是被支持的。内核开发者们正致力于让所有的字符设备都被支
持。可以到 linux-kernel 邮件列表上寻找补丁或是查看补丁的状态。

问: udev 是否会去掉匿名设备数量的限制?
答: udev 完全工作于用户态。如果内核支持了更多的匿名设备,udev 就会支持。

问: udev 是否会支持符号链接?
答: udev 现在就支持符号链接,每个设备节点拥有多个符号链接也是被支持的。

问: udev 如何处理 /dev 文件系统?
答: 建议使用一个每次启动系统的时候重新创建的 tmpfs 作为 /dev 的文件系统。不过
实际上 udev 并不关心那种文件系统在被使用。

问: 在 init 运行之前,udev 如何处理设备?
答: udev 可以被放入 initramfs 之中,并在每个设备被发现的时候运行。也可以让
udev 工作在一个真的根分区被加载之后根据 /sys 的内容创建的初始 /dev 目录
之中。

问: 我是否可以利用 udev 在一个 USB 设备被加载的时候自动加载上这个设备?
答: 技术上讲是可以的,但是 udev 不是用于这个工作的。所有的主流发布版 (distro)
都包含了 HAL (http://freedesktop.org/wiki/Software_2fhal) 用于这个工作,它
也是专门用于监视设备变更的,并且集成进入了桌面软件。

换个角度说,这可以简单的通过 fstab 来实现:
/dev/disk/by-label/PENDRIVE /media/PENDRIVE vfat user,noauto 0 0

这样,用户可以用如下命令来访问设备:
$mount /media/PENDRIVE
同样不需要管理员权限,但却拥有了设备的全部访问权限。使用永久性磁盘链接
(label, uuid) 将可以指定同一设备,无论其实际上的内核名字是什么。

问: 有什么我需要注意的安全问题么?
答: 当使用动态设备编号的时候,一个给定的主/从设备号可能在不同时间对应不同的设
备,如果一个用户拥有对这个节点的访问权限,并且可以创建一个到这个节点的硬链
接,他就可以如此得到一个这个设备节点的拷贝。当设备被移除之后,udev 删除了
设备节点,但硬链接依然存在。如果这个设备节点之后被重新使用不同的访问权限被
创建的时候,其硬链接仍然可以使用先前的访问权限来访问。
(同样的问题也存在在使用 PAM 改变访问权限的 login 上。)

简单的解决方案就是通过把 /dev 放在 tmpfs 这样的单独的文件系统之上来防止建
立硬链接。

问: 我有其他的关于 udev 的问题,我应该问谁?
答: linux-hotplug-devel 正是问这些的地方。邮件列表的地址是
linux-hotplug-devel@lists.sourceforge.net

(王旭)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net]
本文出处:百度博客 作者:王旭
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容