Linux udev的使用
udev是Linux应用层的工具,用于管理应用层的设备节点及热插拔功能。
udev的使用主要是修改配置文件,下面就从配置文件开始讲起。
udev 配置文件
udev的规则配置文件在/lib/udev/rules.d
目录下,有的系统中会创建运行时规则目录/run/udev/rules.d
。文件按顺序执行,一般配置文件使用数字作为文件名的前缀,标识文件的执行顺序。(按照man手册中的描述不一定需要是数字,文件名也没有特殊规则,但是一般都以数字开始,后缀为.rules)。序号越小优先级越高。
当多条规则应用于同一设备时,可根据配置的优先级以及指定的规则判断使用优先级高的规则,还是使用当前规则。
99-usb-serial.rules
udev 服务
udev需要后台服务持续运行以监控系统中的设备事件,在ubuntu中使用systemd-udevd
服务。在busybox系统中往往是后台执行的守护进程。
设备信息
udev规则中我们需要设置匹配信息,当规则中的所有匹配规则都与设备相匹配时,将会执行规则中对应的操作。
我们可以通过以下命令获取设备信息
# udevadm info -a -n <设备节点名>
udevadm info -a -n /dev/ttyUSB0
获取到的内容如下,截取一段进行展示。(下面一段文本中#号后为标注,其它为原始打印信息)
下面显示的所有信息都可以用于匹配设备
looking at device '/devices/platform/soc/10300000.xhci_0/usb1/1-1/1-1:1.0/ttyUSB0/tty/ttyUSB0':
KERNEL=="ttyUSB0" # KERNEL 设备节点在内核中的名称
SUBSYSTEM=="tty" # SUBSYSTEM 设备的子系统
DRIVER==""
# 后续为递归的父节点信息,逐层显示,直到根节点
# 此处仅截取一部分
# 后续的所有配置信息相对于当前节点都加了‘S’
# 例如KERNEL变为KERNELS SUBSYSTEM变为SUBSYSTEMS
looking at parent device '/devices/platform/soc/10300000.xhci_0/usb1/1-1/1-1:1.0/ttyUSB0':
KERNELS=="ttyUSB0" # 注意此处为KERNELS 而不是 KERNEL
SUBSYSTEMS=="usb-serial"
DRIVERS=="ch341-uart"
ATTRS{port_number}=="0"
looking at parent device '/devices/platform/soc/10300000.xhci_0/usb1/1-1/1-1:1.0':
KERNELS=="1-1:1.0"
SUBSYSTEMS=="usb"
DRIVERS=="ch341"
ATTRS{bInterfaceProtocol}=="02"
ATTRS{bInterfaceSubClass}=="01"
ATTRS{bNumEndpoints}=="03"
ATTRS{bInterfaceNumber}=="00"
ATTRS{supports_autosuspend}=="1"
ATTRS{authorized}=="1"
ATTRS{bAlternateSetting}==" 0"
ATTRS{bInterfaceClass}=="ff"
looking at parent device '/devices/platform/soc/10300000.xhci_0/usb1/1-1':
KERNELS=="1-1"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{removable}=="unknown"
ATTRS{bMaxPower}=="98mA"
ATTRS{busnum}=="1" # 总线编号
ATTRS{bmAttributes}=="80"
ATTRS{version}==" 1.10"
ATTRS{quirks}=="0x0"
ATTRS{idProduct}=="7523" # 设备ID
ATTRS{tx_lanes}=="1"
ATTRS{authorized}=="1"
ATTRS{maxchild}=="0"
ATTRS{configuration}==""
ATTRS{bMaxPacketSize0}=="8"
ATTRS{bDeviceClass}=="ff"
ATTRS{rx_lanes}=="1"
ATTRS{bConfigurationValue}=="1"
ATTRS{devspec}==" (null)"
ATTRS{bNumInterfaces}==" 1"
ATTRS{ltm_capable}=="no"
ATTRS{devpath}=="1"
ATTRS{idVendor}=="1a86" # 厂商ID
ATTRS{urbnum}=="12"
ATTRS{devnum}=="3"
ATTRS{speed}=="12"
ATTRS{bNumConfigurations}=="1"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{product}=="USB Serial"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bcdDevice}=="0264"
ATTRS{bDeviceProtocol}=="00"
编写配置文件
配置一条规则主要是两个部分,匹配和操作。匹配部分用于匹配设备和事件,操作部分是对设备进行具体的操作。
下面简要描述了配置文件的语法规则。
- 配置文件中 ‘#’ 号开头的行为注释,其它行为规则
- 一条规则包括其操作只能在一行内完成
- 一个规则的每一个匹配或操作使用 ‘,’ 隔开
- 多个规则或操作没有顺序要求(一般先写规则匹配,再写操作)
- 匹配时可使用指定的模糊匹配规则
下面是一些配置的例子
【注】:设置匹配规则时使用以S结尾的父设备属性时,所有的父设备属性必须来自同一个父设备节点。
例如有如下关系:A–>B–>C。A的父设备为B,B的父设备为C
那么对A设备进行匹配的规则中,以S结尾的父属性必须全部来自于B或者C,而不能交叉引用
# 匹配子系统为tty,内核命名为ttyAMA0的设备,创建软连接到ttysWK0
SUBSYSTEM=="tty", KERNEL=="ttyAMA0", SYMLINK+="ttysWK0"
# 匹配所有的USB虚拟串口设备,且在USB总线3上,创建软连接到ttysWK3
SUBSYSTEM=="tty", KERNEL=="ttyUSB*", ATTRS{busnum}=="3", SYMLINK+="ttysWK3"
应用配置
使用以下命令重新从配置文件中加载配置,并重新配置每一个设备
udevadm control --reload-rules && udevadm trigger
可用的配置
1) 可用的匹配
1. 设备匹配
可用的设备匹配都可以通过udevadm info -a -n
命令查看
可用的模糊匹配规则:
“*”
匹配零个或多个字符。
“?”
匹配任何单个字符。
“[]”
匹配括号内指定的任何单个字符。例如,模式字符串“tty[SR]”将匹配”ttyS”或”ttyR”。范围也通过”-“字符支持。例如,为了匹配所有数字的范围,可以使用模式”[0-9]”。如果”[“后面的第一个字符是”!”,则匹配所有未括起来的字符
“|”
分隔备选模式。例如,模式字符串“abc|x”将匹配“abc”或“x”。
2. 事件匹配
事件匹配使用ACTION
关键字
# 匹配当sd*设备插入时执行操作
ACTION=="add", SUBSYSTEM=="block", KERNEL="sd*",
常见的事件有三种:
事件 | 功能 |
---|---|
add | 设备被添加时 |
remove | 设备被删除时 |
change | 设备属性发生变化时。例如设备的电源状态、配置或其他属性发生变化时 |
3. 自定义匹配
PROGRAM="cmd", 如果命令或脚本的返回值为0,则认为该规则匹配
2) 可执行的操作
操作 | 功能 |
---|---|
赋值[=] | =号赋值用于覆盖之前的赋值 |
赋值[+=] | 追加特定的值给已经存在的键 |
赋值[:=] | 分配一个特定的值给该键,后面的规则不可能覆盖它 |
RUN | RUN=”cmd”, 匹配到设备和事件时执行命令 |
SYMLINK | 软链接,可以使用SYMLINK+=”<链接名>”创建一个软连接 |
3) 执行操作时可使用的特殊值
# 当USB设备被插入时执行脚本,并将插入的设备名作为参数传递给脚本
KERNEL=="ttyUSB*", ACTION=="add", RUN+="/usr/bin/my_script.sh %k"
引用字符 | 引用目标 |
---|---|
%k | 设备KERNEL |
%n | 设备number |
%p | 设备devpath |
%s{file} | 设备属性值{}内为指定属性 |
%E{key} | 指定环境变量的值 |
%M | 主设备号 |
%m | 次设备号 |
%c | PROGRAM自定义匹配规则的终端输出 |
%P | 父设备的设备文件名 |
%r | udev_root值,默认是/dev |
%N | 临时设备名 |
%% | %符号 |
$$ | $符号 |