简介
udev时Linux(Linux2.6内核之后)的默认设备管理工具。udev以守护进程形式运行,通过侦听内核发出来的uevent来管理/dev目录目录下的设备文件。
udev能够处理设备事件、管理设备文件权限、在/dev目录中创建额外的符号链接、重命名网络接口等。内核通常仅根据设备被发现的先后顺序给设备文件命名,因此很难在设备文件与物理硬件之间建立稳定的对应关系。而根据设备的物理属性后配置特征创建有意义的符号链接名称或网络接口名称,就可以在物理设备与设备文件名之间加你离稳定的对应关系。
udev守护进程直接从内核接收设备的插入、拔出、改变状态等事件,并根据这些事件的各种属性,到规则库中进行匹配,以确定触发事件的设备。被匹配成功的规则有可能提供额外的设备信息,这些信息可能会被记录到udev数据库中,也可能被用于创建符号链接。
udev处理的所有设备信息都存储在udev数据库中, 并且会发送给可能的设备事件的订阅者。 可以通过 libudev 库访问udev数据库以及设备事件源。
工作流程
配置文件
udev的配置文件,位于/etc/udev/udev.conf。该文件包含一组允许用户修改的变量,以控制该进程的行为。空行或以’#’号开头的行将被忽略。
systemd-udevd 将使用 /etc/udev/udev.conf 作为主配置文件。该文件包含一组 允许用户修改的变量( VAR=VALUE 格式),以控制该进程的行为。 空行或以”#”开头的行将被忽略。 可以设置的变量(VAR)如下:
- udev_log= :日志等级。可以设置为数字(与syslog习惯相同),也可以设为这些文本值:err(3)、info(6)、debug(7)。
- children_max= :一个正整数,表示允许同时执行的最大设备事件数量。等价于 —children-max选项。
- exec_delay= :一个正整数,表示延迟多少秒后再执行RUN指令。常用于调试,由于加载冷插拔设备的内核模块而导致的系统崩溃。等价于 —exec-delay=选项
- event_timeout= :一个正整数,表示等待设备事件完成的超时秒数。 超时后,设备事件将会被强制终止。默认为 180 秒。等价于 —event-timeout= 选项。
- resolve_name= :设置systemd-udevd 在何时解析用户与组的名称。 默认值 early 表示在规则的解析阶段; late 表示在每个设备事件发生的时候; never 表示不解析(所有设备都归 root 用户拥有)。等价于 —resolve-names= 选项。
规则文件
规则文件是 udev 里最重要的部分。所有的规则文件必须以“.rules”为后缀名。
规则文件分别位于系统规则目录(/usr/lib/udev/rules.d)、运行时规则目录(/run/udev/rules.d)、本机规则目录(/etc/udev/rules.d)。所有的规则文件(无论位于哪个目录中),统一按照文件名的字典顺序处理。对于不同目录下的同名规则文件,仅以优先级最高的目录中的那一个为准。具体来说就是:/etc/的优先级最高、/run/的优先级居中、/usr/lib/的优先级最低。
如果系统管理员想要屏蔽/usr/lib/目录中的某个规则文件,那么最佳做法是在/etc/目录中创建一个指向/dev/null的同名符号链接,即可彻底屏蔽/usr/lib/目录中的同名文件。注意,规则文件必须以 .rules 作为后缀名,否则将被忽略。
每条规则都是由一系列逗号分隔的”键-值”对组成。根据操作符的不同,键可分为匹配键和赋值键,每个键都对应着一个唯一的操作。可用的操作符如下:
符号 | 说明 |
---|---|
== | 比较键、值,若等于,则该条件满足 |
!= | 比较键、值,若不等于,则该条件满足 |
= | 对一个键赋值 |
+= | 为一个表示多个条目的键赋值 |
-= | 为一个键删除此处指定值 |
:= | 对一个键赋值,并拒绝之后所有对该键的改动。目的是防止后面的规则文件对该键赋值。 |
下面的”键”可作匹配键使用。注意,其中的某些键还可以针对父设备进行匹配,而不仅仅是生成设备事件的那个设备自身。如果在同一条规则中有多个键可以针对父设备进行匹配,那么仅在所有这些键都同时成功匹配同一个父设备时,才算匹配成功。
- ACTION:匹配事件的动作。例如”add”表示插入一个设备。
- DEVPATH:匹配设备的路径(也就是该设备在sysfs文件系统下的相对路径)。
- KERNEL:匹配设备的内核名称。”内核名称”是指设备在sysfs里的名称,也就是默认的设备文件名称,例如”sda”。
- NAME:匹配网络接口的名称。仅在先前的规则中已将NAME键赋值的前提下,才可将此键用于匹配。
- SYMLINK:匹配指向此设备节点的软连接的名称。仅在先前的规则中已将 SYMLINK 键赋值的前提下,才可将此键用于匹配。可能有多个软连接指向同一个设备节点,但只需其中的一个匹配成功即可。
- SUBSYSTEM:匹配设备所属的子系统。例如”sound”或”net”。
- DRIVER:匹配设备的驱动程序名称。 仅在设备事件发生时,此设备确实正好绑定着一个驱动程序情况下,此键才会被设置。
- ATTR{文件}, SYSCTL{内核参数}:匹配设备在sysfs中的属性值,属性值中的尾部空白会被忽略,除非指定的值自身就包含尾部空白;匹配”内核参数”的值。
- KERNELS:匹配设备及其所有父设备的内核名称。
- SUBSYSTEMS:匹配设备及其所有父设备所属的子系统。
- DRIVERS:匹配设备及其所有父设备的驱动程序名称。
- ATTRS{文件}:匹配设备及其所有父设备在sysfs中的属性值。如果指定了多个 ATTRS 匹配,那么必须在同一个设备上全部匹配成功,才算最终匹配成功。属性值中的尾部空白会被忽略,除非指定的值自身就包含尾部空白。
- TAGS:匹配设备及其所有父设备的标签。
- ENV{设备属性}:匹配设备的属性。例如 “DEVTYPE”, “ID_PATH”, “SYSTEMD_WANTS” 等等。
- TAG:匹配设备的标签。
- TEST{八进制模式掩码}:检测指定的文件是否存在。 如果有必要,还可以额外指定一个八进制的访问模式掩码。
- PROGRAM:执行指定的程序并检查返回值,如果返回值为零,则匹配成功,否则匹配失败。设备的属性会转化为该程序的环境变量供其使用。同时该程序的标准输出会被自动保存在RESULT键中。注意,仅可用于执行时间很短的前台程序。
- RESULT:匹配最近一次PROGRAM程序的输出字符串,必须位于PROGRAM之后(但可出现在同一条规则中)。
可以在用于匹配的”值”中使用shell风格的通配符, 具体说来就是:
- “*”:匹配任意数量的字符(包括零个)
- “?”:匹配单独一个字符
- “[]”:匹配中括号内的任意一个字符。例如 “tty[SR]” 可以匹配 “ttyS” 或 “ttyR” 。还可以使用 “-“ 符号表示一个区间。例如 “[0-9]” 可以匹配任意数字。如果在左括号 “[“ 后紧接着一个 “!” 则表示匹配非括号内的字符。
- “|”:用于分隔两个可相互替代的匹配模式(也就是”或”的意思)。例如 “abc|x“ 的意思是匹配 “abc” 或 “x“
下面的键可作赋值健使用:
- NAME:设置网络接口的名称。实际上,udev并不能直接修改网络接口的设备节点名称,只是额外创建了一个符号链接而已。
- SYMLINK:设置指向此设备节点的软连接名称。软连接的名字中仅允许使用下列字符:”0-9A-Za-z#+-.:=@/“、有效的UTF-8字符、”\x00”风格的十六进制编码(实际的文件名并不转码)。其他字符将被替换为 ““ 字符。只需在多个名称之间使用空格分隔,即可一次指定多个软连接名称。如果为多个不同的设备指定了相同的软连接,那么实际的软连接将指向link_priority值最高的设备。如果 link_priority值最高的设备被移除,那么该软连接将重新指向下一个 link_priority 值最高的设备,以此类推。对于未指定 link_priority 值或者 link_priority 值相等的设备,它们之间的顺序是不确定的。符号连接的名称必须不能与内核的默认名称相同,否则会得到无法预知的结果。
- OWNER, GROUP, MODE:设置设备节点的属主、属组、权限。会覆盖内置的默认值。
- SECLABEL{模块}:设置设备节点的Linux安全模块标签。
- ATTR{文件}:设置在sysfs中的设备属性。
- SYSCTL{内核参数}:设置”内核参数”的值。
- ENV{属性}:设置设备的属性。例如 “DEVTYPE”, “ID_PATH”, “SYSTEMD_WANTS” 等等。如果属性名以 “.” 开头,那么此属性将不会被记录到udev数据库中, 也不会被导出为环境变量(例如 PROGRAM)。
- TAG:设置设备的标签。用于为libudev监视(monitor)功能的用户过滤事件或者枚举已标记的设备。标签仅在与特殊的设备过滤器一起使用时才有意义,千万不要用于常规目的。滥用标签将会导致设备事件处理效率显著下降,所以应该尽量避免为设备设置标签。
- RUN{类型}:对于每一个设备事件来说,在处理完所有udev规则之后,都可以再接着执行一个由此键设置的程序列表(默认为空)。不同的”类型”含义如下:
- “program”:一个外部程序, 如果是相对路径, 那么视为相对于 /usr/lib/udev 目录。 否则必须使用绝对路径。 如果未明确指定”类型”,那么这是默认值。
- “builtin”:与 program 类似, 但是仅用于表示内置的程序。
程序名与其参数之间用空格分隔。 如果参数中含有空格,那么必须使用单引号(‘)界定。
仅可使用运行时间非常短的前台程序, 切勿设置任何后台守护进程或者长时间运行的程序。
设备事件处理完成之后, 所有派生的进程(无论是否已经分离), 都将会被无条件的杀死。
注意,禁止在 udev 规则中运行访问网络、或挂载/卸载文件系统的程序, 因为在 systemd- udevd.service 中强制使用了默认沙盒机制。
- LABEL:设置一个可用作 GOTO 跳转目标的标签。
- GOTO:跳转到下一个匹配的 LABEL 标签所在的规则。
- IMPORT{类型}:将一组变量导入为设备的属性。不同的”类型”含义如下:
- “program”:执行一个外部程序,并且当其返回值为零时导入其输出内容。 注意,输出内容的每一行都必须符合”key=value”格式。关于程序路径、命令与参数分隔符、引号的使用规则、程序执行时间等,都与 RUN 相同。
- “builtin”:与 “program” 类似,但是仅用于执行内置的程序。
- “file”:导入一个文本文件的内容。该文本文件的每一行都必须符合”key=value”格式。以”#”开头的行将被视为注释而忽略。
- “db”:从当前已有的udev数据库中导入一个单独的属性。仅可用于udev数据库确实已经被早先的设备事件所填充的情形。
- “cmdline”:从内核引导选项导入一个单独的属性。对于那些仅有单独的标记而没有值的属性,其值将被指定为 “1” 。
- “parent”:从父设备导入已有的属性(包括对应的值)。可以将 IMPORT{parent} 赋值为shell风格的匹配模式,以导入多个属性名称与匹配模式相符的属性。仅可使用运行时间非常短的前台程序,切勿设置任何后台守护进程或者长时间运行的程序。参见 RUN
- OPTIONS:规则与设备的选项:
- link_priority=value:指定创建符号链接时的优先级。 数值越大优先级越高。默认值是”0”。
- stringescape=none|replace:在对设备进行命名时,如何处理设备名字中的非常规字符(比如控制字符与不安全的字符)。none 表示不做处理,保持原样;replace 表示将这些非常规字符替换为”“(下划线)。
- static_node=:将本条规则设定的权限应用到此选项指定的静态设备节点上。同时,如果在本规则中指定了标签(tag),那么还会在 /run/udev/static_node-tags/tag 目录中创建一个指向该静态设备节点的软连接。注意,在 systemd-udevd 启动之前,静态设备节点就已经由 systemd-tmpfiles 创建完成了。创建静态设备节点时,并不要求存在对应的内核设备,因为当这些设备节点被访问时,会触发内核模块的自动加载功能。、
- watch:使用文件系统的 inotify 功能监视设备节点。当节点被打开并写入之后又被关闭,将会触发一个”设备状态已变化”的事件。
- nowatch:禁用针对设备节点的 inotify 监视功能。
NAME, SYMLINK, PROGRAM, OWNER, GROUP, MODE, SECLABEL, RUN 都支持简单的字符串替换。 RUN 的替换发生在所有规则全部处理完成之后、程序将要执行之前, 因此可以使用由匹配成功的规则所设置的设备属性。 而其他键的替换发生在该键所在规则被处理完成的当时。 可用的替换标记如下:
- $kernel, %k:设备的内核名称。
- $number, %n:设备在内核中的序号。例如,对于 “sda3” 来说,此值为 “3”。
- $devpath, %p:设备路径(devpath)。也就是该设备在sysfs文件系统下的相对路径。例如,/dev/sda1 对应的设备路径是 /block/sda/sda1 (一般对应着 /sys/block/sda/sda1 目录)。
- $id, %b:被 SUBSYSTEMS, KERNELS, DRIVERS, ATTRS 成功匹配到的设备的设备名称。
- $driver:被 SUBSYSTEMS, KERNELS, DRIVERS, ATTRS 成功匹配到的设备的驱动名称。
- $attr{文件}, %s{文件}:在规则匹配成功时,设备路径(devpath)下”文件”的内容(用于表示设备的属性)。如果该设备路径下没有此文件,则从先前 KERNELS, SUBSYSTEMS, DRIVERS, ATTRS 匹配的父设备中提取。如果”文件”是一个软连接,则一直追踪软连接到最终的实际文件。
- $env{属性}, %E{属性}:设备的属性值。例如 “DEVTYPE”, “ID_PATH”, “SYSTEMD_WANTS” 等。
- $major, %M:设备的主设备号。
- $minor,%m:设备的次设备号。
- result, %c:外部程序PROGRAM 程序的输出字符串。可以使用 “%c{N}” 提取第N个子字符串(以空格为分隔符,从”1”开始计数)。也可以通过 “%c{N+}”(也就是在数字后附加一个 “+”)提取从第N个子字符串开始一直到结尾的部分。
- $parent, %P:父设备的节点名称。
- $name:设备的当前名称。如果没有被任何udev规则修改,那么等于该设备的内核名称。
- $links:一个空格分隔的软链接名称列表,这些软链接都指向该设备的节点。该值仅在两种情况下存在:(1)发生”remove”事件;(2)先前的规则已对 SYMLINK 赋值。
- $root, %r:udev_root 的值。
- $sys, %S:sysfs 文件系统的挂载点。
- $devnode, %N:设备节点的名称(也就是设备文件的名称)。
- %%:百分号 “%” 自身。
- $$:美元符号 “$” 自身。