前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >udev高效、动态地管理 Linux 设备文件

udev高效、动态地管理 Linux 设备文件

作者头像
全栈工程师修炼指南
发布2022-09-28 20:23:04
7.3K0
发布2022-09-28 20:23:04
举报

[TOC]

0x00 前言简介

描述: Linux 用户常常会很难鉴别同一类型的设备名,比如 eth0, eth1, sda, sdb 等等。通过观察这些设备的内核设备名称,用户通常能知道这些是什么类型的设备,但是不知道哪一个设备是他们想要的

例如:在一个充斥着本地磁盘和光纤磁盘的设备名清单 (/dev/sd*) 中,用户无法以名称找到一个序列号为“35000c50000a7ef67”的磁盘。

在这种情况下通过udev就能动态地在 /dev 目录里产生自己想要的、标识性强的设备文件或者设备链接,以此帮助用户方便快捷地找到所需的设备文件。

Q: 什么是 udev?

答: udev 是 Linux kernel 2.6 系列的一个设备管理器功能,由Greg Kroah-Hartman和Kay Sievers共同开发并得到Dan Stekloff等人的帮助, 它在2012年4月 udev 被合并至 systemd; udev 以守护进程的形式运行,通过侦听内核发出来的 uevent 来管理 /dev目录下的设备文件, 它替代了原来的 devfs 及 hotplug 的功能;

Q: 为何要选择使用udev?

答: 在传统的Linux系统中 /dev目录下 的设备节点为一系列静态存在的文件, 而udev则动态提供了在系统中实际存在的设备节点, 虽然在Linux中是采用的devfs提供类似功能但是udev有更好使用的理由:

  • udev 支持设备的固定命名而并不依赖于设备插入系统的顺序, 即默认的udev设置提供了存储设备的固定命名可以使用其vid(vendor)、pid(device)、设备名称(model)等属性或其父设备的对应属性来确认某一设备。
  • udev 完全在用户空间(user space) 执行而不是像devfs在内核空间 (kernel space) 一样执行, 结果就是udev将命名策略从内核中移走并可以在节点创建前用任意程序在设备属性中为设备命名。

运行原理:

  • 1.它以守护进程的方式运行于Linux系统,并监听在新设备初始化或设备从系统中移除时,内核(通过netlink socket)所发出的 uevent(早期的版本使用hotplug,并在/etc/hotplug.d/default添加一个链接到自身来达到目的),并通过一套规则用于匹配可发现的设备事件和属性的导出值, 该规则并可以根据匹配像内核子系统、内核设备名称、设备的物理等属性或设备序列号的属性, 来对设备设定一个持久的名称,而不管该设备什么时候被发现添加;
  • 2.我们知道在Linux中万物皆文件而/dev目录包含了所有可能出现的设备的设备文件, 使用udev通过定义一个 udev 规则 (rule) 来产生匹配设备属性的设备文件,这些设备属性可以是内核设备名称、总线路径、厂商名称、型号、序列号或者磁盘大小等等。

udev功能特点

  • 1.动态管理: 当设备添加 / 删除时,udev 的守护进程侦听来自内核的 uevent,以此添加或者删除 /dev下的设备文件,所以 udev 只为已经连接的设备产生设备文件而不会在 /dev下产生大量虚无的设备文件。
  • 2.自定义命名规则:通过 Linux 默认的规则文件,udev 在 /dev/ 里为所有的设备定义了内核设备名称,比如 /dev/sda、/dev/hda、/dev/fd等等。由于 udev 是在用户空间 (user space) 运行,Linux 用户可以通过自定义的规则文件,灵活地产生标识性强的设备文件名,比如 /dev/boot_disk、/dev/root_disk、/dev/color_printer等等
  • 3.设定设备的权限和所有者 / 组:udev 可以按一定的条件来设置设备文件的权限和设备文件所有者 / 组。(注意不同版本实现或许不同)

Q: 总结一句话简述udev的作用? 答: 系统识别设备都会在/dev目录下创建设备文件与主、次设备表号等每次卸载挂载后其设备名称将会动态的变化, 对于我们来说当然不希望出现这样的情况, 它可以为设备提供持久、自定义的设备名称进行挂载到系统上便于使用者区分使用。

udev 工作流程图:

WeiyiGeek.流程图显示 udev 添加 / 删除设备文件的过程
WeiyiGeek.流程图显示 udev 添加 / 删除设备文件的过程

WeiyiGeek.流程图显示 udev 添加 / 删除设备文件的过程

系统架构:

  • libudev函数库,可以用来获取设备的信息。
  • udevd守护进程,处于用户空间,用于管理虚拟/dev
  • udevadm管理命令,用来诊断出错情况。

相关术语:

  • 1.设备文件:由于本文以较通俗的方式讲解 udev,所以设备文件是泛指在 /dev/下,可被应用程序用来和设备驱动交互的文件。而不会特别地区分设备文件、设备节点或者设备特殊文件;
  • 2.devfs:devfs是 Linux 早期的设备管理工具,已经被 udev 取代。
  • 3.sysfs:sysfs是 Linux 2.6 内核里的一个虚拟文件系统 (/sys)。它把设备和驱动的信息从内核的设备模块导出到用户空间 (userspace)。从该文件系统中Linux 用户可以获取很多设备的属性可以帮助我们编写udev规则。
  • 4.devpath:本文的 devpath是指一个设备在 sysfs文件系统 (/sys)下的相对路径,该路径包含了该设备的属性文件。udev 里的多数命令都是针对 devpath操作的。例如:sda的 devpath是 /block/sda,sda2 的 devpath是 /block/sda/sda2
  • 5.内核设备名称:设备在 sysfs里的名称,是 udev 默认使用的设备文件名。 例如:udevadm info -a -n /dev/sda | grep "KERNEL" 返回的即为内核设备名称 KERNEL==”sda”

注意事项:

  • 1) 使用新版本udev的系统不能在 2.6.13 以下版本启动,除非使用noudev参数来禁用udev并使用传统的/dev来进行设备读取。
0x01 安装udev

描述:从 Fedora3 和 Red Hat Enterprise4 开始,udev 就是默认的设备管理工具并且现在udev已经被集成到systemd中,所以常用的Linux发行版本无需另外下载安装;

检查1.查看系统中版本以及udev运行情况

代码语言:javascript
复制
# 1.CentOS
$yum list | grep "libgudev1"
libgudev1.i686                            219-73.el7_8.9               updates
libgudev1.x86_64                          219-73.el7_8.9               updates
libgudev1-devel.i686                      219-73.el7_8.9               updates
libgudev1-devel.x86_64                    219-73.el7_8.9               updates

# 2.Ubuntu
$apt list | egrep "^udev"
udev/focal-updates,now 245.4-4ubuntu3.2 amd64 [installed,automatic]

# 3.运行状态查看
$ ps -ef | grep "udev"
UID        PID  PPID  C STIME TTY          TIME CMD
root     15981     1  0 9月11 ?       00:00:00 /usr/lib/systemd/systemd-udevd  # 已经集成到systemd中了

$ systemctl status udev.service
● systemd-udevd.service - udev Kernel Device Manager
     Loaded: loaded (/lib/systemd/system/systemd-udevd.service; static; vendor preset: enabled)
     Active: active (running) since Tue 2020-09-15 09:27:07 CST; 13h ago
TriggeredBy: ● systemd-udevd-kernel.socket
             ● systemd-udevd-control.socket
       Docs: man:systemd-udevd.service(8)
             man:udev(7)
   Main PID: 823 (systemd-udevd)
     Status: "Processing with 96 children at max"
      Tasks: 1
     Memory: 171.5M
     CGroup: /system.slice/systemd-udevd.service
             └─823 /lib/systemd/systemd-udevd

0x02 配置文件树形

udev 配置目录一览:

代码语言:javascript
复制
# 此处以Ubuntu 20.04 TLS 为例
$ tree -l /etc/udev/
/etc/udev/
├── hwdb.d
├── rules.d
│?? ├── 70-snap.snapd.rules
│?? └── ubuntu--vg-ubuntu--lv.rules
└── udev.conf

2 directories, 3 files

说明1.udev 的配置文件/etc/udev/udev.conf

代码语言:javascript
复制
$ cat /etc/udev/udev.conf  # Ubuntu
# see udev.conf(5) for details
#
# udevd is also started in the initrd.  When this file is modified you might
# also want to rebuild the initrd, so that it will include the modified configuration.

#udev_log=info
#children_max=
#exec_delay=
#event_timeout=180
#resolve_names=early
  • udev_root:udev 产生的设备所存放的目录,默认值是 /dev/。建议不要修改该参数,因为很多应用程序默认会从该目录调用设备文件。(不建议修改)
  • udev_db:udev 信息存放的数据库或者所在目录,默认值是 /dev/.udev.tdb。
  • udev_rules:udev 规则文件的名字或者所在目录,默认值是 /etc/udev/rules.d/。(不建议修改)
  • udev_permissions:udev 权限文件的名字或者所在目录,默认值是 /etc/udev/permissions.d/。
  • default_mode/ default_owner/ default_group:如果设备文件的权限没有在权限文件里指定,就使用该参数作为默认权限,默认值分别是:0600/root/root。
  • udev_log:syslog记录日志的级别,默认值是 err。如果改为 info 或者 debug 的话,会有冗长的 udev 日志被记录下来。
(1) 指令操作符
代码语言:javascript
复制
# (1) udev指令操作符:
==    # 表示匹配 比较键、值,若等于,则该条件满足;
!=    # 表示不匹配  比较键、值,若不等于,则该条件满足;
=     # 指定要赋予的值 对一个键赋值;
+=    # 添加新值 为一个表示多个条目的键赋值。
:=    # 指定的值且不允许被替换 对一个键赋值,并拒绝之后所有对该键的改动
(2) 字符串替换传值

描述:当编写可能处理多个类似设备的规则时,udev的类似printf的字符串替换操作符非常有用。Linux 用户可以随意地定制 udev 规则文件的值;

例如:my_root_disk, my_printer 同时也可以引用下面的替换操作符:

代码语言:javascript
复制
$kernel, %k:设备的内核设备名称, 例如“sda3”表示将(默认情况下)出现在/dev/sda3上的设备
$number, %n: 计算设备的内核号(存储设备的分区号): e.g. "3" for /dev/sda3
$devpath, %p: 设备的 devpath路径。
$id, %b:设备在 devpath里的 ID 号。
$sysfs{file}, %s{file}:设备的 sysfs 里 file 的内容就是设备属性值, 例如:$sysfs{size} 表示该设备 ( 磁盘 ) 的大小。
$env{key}, %E{key}:一个环境变量的值。
$major, %M:设备的 major 号。
$minor %m:设备的 minor 号。
$result, %c:PROGRAM 返回的结果。
$parent, %P:父设备的设备文件名。
$root, %r:udev_root的值,默认是 /dev/。
$tempnode, %N:临时设备名。
%%:符号 % 本身。
$$:符号 $ 本身。

简单实例:

代码语言:javascript
复制
# 1.下面示例中的$kernel和$number是替换操作符的规则例子
# 第一个规则确保mice设备节点只出现在/dev/input目录中(默认情况下是在/dev/mice)
# 第二个规则确保名为loop0的设备节点在/dev/loop/0处创建,并且像往常一样在/dev/loop0处创建一个符号链接。
KERNEL=="mice", NAME="input/%k"
KERNEL=="loop0", NAME="loop/%n", SYMLINK+="%k"

# 2.该规则的执行:如果有一个内核设备名称以 sd 开头,且 SCSI ID 为 35000c50000a7ef67,则为设备文件产生一个符号链接“sda_35000c50000a7ef67”.
KERNEL=="sd*", PROGRAM="/lib/udev/scsi_id -g -s %p", \
RESULT=="35000c50000a7ef67", SYMLINK="%k_%c"
(3) 字符串匹配
代码语言:javascript
复制
# 使用shell风格的模式匹配(实际都是正则这里不过多接受了)
* - match any character, zero or more times
? - match any character exactly once
[] - match any single character specified in the brackets, ranges are also permitted

# 1.基础示例
# 第一个规则匹配所有软盘驱动器,并确保设备节点被放置在/dev/floppy目录中,并从默认名称创建符号链接。
# 第二条规则确保hiddev设备只存在于/dev/usb目录中。
KERNEL=="fd[0-9]*", NAME="floppy/%n", SYMLINK+="%k"
KERNEL=="hiddev*", NAME="usb/%k"
(4) 设备文件的权限

注意在 RHEL5.3 的 udev 已经没有权限文件,所有的权限都是通过规则文件 (*.rules)来设置

(5) udev基本规则

描述:用于精确装置匹配设备的规则常用如下:

  • KERNEL - 匹配设备的内核名字
  • SUBSYSTEM - 匹配设备的子系统即/dev/block//dev/net;
  • DRIVER - 匹配设备驱动名
  • NAME - 在 /dev下产生的设备文件名
  • SYMLINK - 为 /dev/下的设备文件产生符号链接,由于 udev 只能为某个设备产生一个设备文件,所以为了不覆盖系统默认的 udev 规则所产生的文件,推荐使用符号链接。
  • ACTION - 事件 (uevent) 的行为例如add( 添加设备 )、remove( 删除设备)
  • SYSFS{filename} - 设备的 devpath 路径下,设备的属性文件“filename”里的内容; 如 SYSFS{model}==“ST936701SS” 表示如果设备的型号为 ST936701SS,则该设备匹配该匹配键。
  • ATTRS - 匹配设备的sysfs属性,或任何父设备的sysfs属性
  • DEVPATH - 设备的 devpath 路径。
  • ENV{key} - 环境变量。 ENV{key}:导入一个环境变量。
  • BUS - 设备在 devpath 里的总线名称,例如usb
  • DRIVER - 设备在 devpath 里的设备驱动名称,例如 ide-cdrom
  • ID - 设备在 devpath 里的识别号
  • PROGRAM - 调用外部命令。
  • RESULT - 外部命令 PROGRAM 的返回结果。
  • OWNER, GROUP, MODE - 为设备设定权限。

简单实例:

代码语言:javascript
复制
# 示例1.匹配键与操作符
NAME = "udisk",      # 定义设备名称
SYMLINK += "data1",  # 定义设备的别名
OWNER = "student",   # 定义设备的所有者
MODE = "0600",       # 定义设备的权限
ACTION == "add",     # 判断设备的操作动作、添加或删除设备等
KERNEL == "sd[a-z]1", # 判断设备的内核名称
RUN += 程序          # 为设备添加程序

# 示例2.如果设备的型号为 ST936701SS并且sysfs的size属性匹配234441648值,则该设备匹配该匹配键
SUBSYSTEM=="block",SYSFS{model}=="ST936701SS",ATTR{size}=="234441648", SYMLINK+="my_disk"


# 示例3.调用外部命令 /lib/udev/scsi_id查询设备的 SCSI ID,如果返回结果为 35000c50000a7ef67,则该设备匹配该匹配键。
SUBSYSTEM=="block",PROGRAM=="/lib/udev/scsi_id -g -s $devpath", RESULT=="35000c50000a7ef67"

注意事项:

  • 如果没有任何规则对设备的 NAME 赋值,udev 将使用内核设备名称来产生设备文件
  • 在一条规则中可以设定最多五条 SYSFS 的匹配键以及环境变量的匹配键。
(5) sysfs系统设备属性

描述: 当我们为指定的设备设定规则时,首先需要知道该设备的属性,比如设备的序列号、磁盘大小、厂商 ID、设备路径等等。通常我们可以通过以下的方法获得:

  • 1.根据 sysfs 查找设备的信息 ( 属性 ) 来制定 udev 规则
  • 2.采用udevadm命令的info子命令可以查询 udev 数据库里的设备信息。

sysfs设备的信息(属性):

代码语言:javascript
复制
# (1) 目录表示具有相应设备节点的实际设备
$sudo find /sys -name dev | grep "pci"
/sys/devices/pci0000:00/0000:00:1f.2/ata10/host11/target11:0:0/11:0:0:0/scsi_generic/sg1/dev
/sys/devices/pci0000:00/0000:00:1f.2/ata10/host11/target11:0:0/11:0:0:0/block/sr0/dev
/sys/devices/pci0000:00/0000:00:1f.2/ata10/host11/target11:0:0/11:0:0:0/bsg/11:0:0:0/dev
/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/host0/target0:2:0/0:2:0:0/scsi_generic/sg0/dev
/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/host0/target0:2:0/0:2:0:0/block/sda/sda4/dev
/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/host0/target0:2:0/0:2:0:0/block/sda/sda2/dev
/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/host0/target0:2:0/0:2:0:0/block/sda/dev
/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/host0/target0:2:0/0:2:0:0/block/sda/sda3/dev
/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/host0/target0:2:0/0:2:0:0/block/sda/sda1/dev
/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/host0/target0:2:0/0:2:0:0/bsg/0:2:0:0/dev
/sys/devices/pci0000:00/0000:00:1c.3/0000:03:00.0/ptp/ptp2/dev
/sys/devices/pci0000:00/0000:00:1c.3/0000:03:00.1/ptp/ptp3/dev
/sys/devices/pci0000:00/0000:00:1c.1/0000:07:00.0/0000:08:00.0/0000:09:00.0/0000:0a:00.0/graphics/fb0/dev
/sys/devices/pci0000:00/0000:00:1c.1/0000:07:00.0/0000:08:00.0/0000:09:00.0/0000:0a:00.0/i2c-0/i2c-dev/i2c-0/dev
/sys/devices/pci0000:00/0000:00:1c.1/0000:07:00.0/0000:08:00.0/0000:09:00.0/0000:0a:00.0/drm/card0/dev
/sys/devices/pci0000:00/0000:00:1a.0/usb1/dev
/sys/devices/pci0000:00/0000:00:1a.0/usb1/1-1/dev
/sys/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.6/dev
/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/dev
/sys/devices/pci0000:00/0000:00:1d.0/usb2/dev
/sys/devices/pci0000:00/0000:00:02.0/0000:04:00.0/host4/port-4:1/end_device-4:1/bsg/end_device-4:1/dev
/sys/devices/pci0000:00/0000:00:02.0/0000:04:00.0/host4/port-4:0/end_device-4:0/bsg/end_device-4:0/dev
/sys/devices/pci0000:00/0000:00:02.0/0000:04:00.0/host4/bsg/sas_host4/dev
/sys/devices/pci0000:00/0000:00:1c.2/0000:02:00.0/ptp/ptp0/dev
/sys/devices/pci0000:00/0000:00:1c.2/0000:02:00.1/ptp/ptp1/dev

# (2) 例如在我的系统上 `/sys/block/sda` 目录是我的硬盘的设备路径, 它通过 /sys/block/sda/device 符号链接链接到它的上级SCSI磁盘设备;
$ cat /sys/block/sda/size
2341994496   # 在规则中可以使用ATTR{size}=="234441648"来标识该磁盘
$ cat /sys/block/sda/dev
8:0

补充udev规则所需属性:

代码语言:javascript
复制
# (0) 通过 scsi_id 查询磁盘的 SCSI_ID 的例子
/usr/lib/udev/scsi_id -g -u 设备名
scsi_id -g -s /block/sda 
35000c50000a7ef67

# (1) 例如:用 udevinfo 查询设备 sda 的 model 和 size 信息:
udevinfo -a -p /sys/block/sda
udevinfo -a -p /block/sda | egrep "model|size"
SYSFS{size}=="71096640"
SYSFS{model}=="ST936701SS"
# 或者
udevadm info -q path -n /dev/sda
/devices/pci0000:00/0000:00:15.0/0000:03:00.0/host1/target1:0:0/1:0:0:0/block/sda
udevadm info -a -q $(udevadm info -q path -n /dev/sda) | 
udevadm info -a -n /dev/sda | egrep "model|size"
  # ATTR{size}=="104857600"
  # ATTRS{model}=="Virtual disk    "

0x03 UDEV规则实例

描述:udev 配置文件是 /etc/udev/udev.conf 该文件内容中有指定udev规则存储目录形如 udev_rules="/etc/udev/rules.d" 该指定的目录中存储一系列以.rules结束的规则文件, 每个文件处理一系列规则来帮助udev分配名字给设备文件并保证内核可以识别此设备名称。

(1) 规则文件由系列键-值对组成, 键值对分两类:匹配键(使用操作符"==","!="等) 和 赋值键(使用"=","+=",":="等), 匹配键判断规则是否应被应用,赋值键可以被分配一到多个值。

代码语言:javascript
复制
# 规则语法: 每个规则由一系列键 - 值对,这是由逗号分隔的构造
# 实例1.KERNEL 是匹配键,NAME 和 MODE 是赋值键
KERNEL=="hdb", NAME="my_spare_disk"   
# 如果有一个设备的内核设备名称为 sda则该条件生效,执行后面的赋值:在 /dev下产生一个名为 my_root_disk的设备文件,并把设备文件的权限设为 0660。
KERNEL=="sda", NAME="my_root_disk", MODE="0660"

(2) 规则文件必须以”.rules”为后缀名, 在 RHEL 有默认的规则文件,这些默认规则文件不仅为设备产生内核设备名称,还会产生标识性强的符号链接。

  • 例如:/dev/disk/by-uuid/ 16afe28a-9da0-482d-93e8-1a9474e7245c
  • 其缺点是链接名称较长不易调用, 所以通常需要自定义规则文件以此产生易用且标识性强的设备文件或符号链接。

查看已为您的存储硬件创建的持久性名称:

代码语言:javascript
复制
$ls -lR /dev/disk
/dev/disk:
total 0
drwxr-xr-x 2 root root  60 Sep 14 08:48 by-dname
drwxr-xr-x 2 root root 140 Sep 14 08:48 by-id
drwxr-xr-x 2 root root 120 Sep 14 08:48 by-partuuid
drwxr-xr-x 2 root root 180 Sep 14 08:48 by-path

$tree -l /dev/disk
/dev/disk
├── by-id
│?? ├── ata-VMware_Virtual_SATA_CDRW_Drive_00000000000000000001 -> ../../sr0
│?? ├── dm-name-centos-root -> ../../dm-0
│?? ├── dm-name-centos-swap -> ../../dm-1
│?? ├── dm-uuid-LVM-aU2d8DppVRkxbqQEFXw2K1tUjzEIAQ83cLOioKmuP4CzguVYh6jGG8qKYeQH9BLJ -> ../../dm-1
│?? ├── dm-uuid-LVM-aU2d8DppVRkxbqQEFXw2K1tUjzEIAQ83pkIKVVfwHPfFSrDXwmzJgh1BD4v7yjbJ -> ../../dm-0
│?? └── lvm-pv-uuid-dBw5Er-e0CA-NnE5-9EZW-PQ08-iW0e-smzxdQ -> ../../sda2
├── by-path
│?? ├── pci-0000:02:01.0-ata-1.0 -> ../../sr0
│?? ├── pci-0000:03:00.0-scsi-0:0:0:0 -> ../../sda
│?? ├── pci-0000:03:00.0-scsi-0:0:0:0-part1 -> ../../sda1
│?? └── pci-0000:03:00.0-scsi-0:0:0:0-part2 -> ../../sda2
└── by-uuid
    ├── b4d40c4d-2103-4825-8c1e-0d3ce53fa1a1 -> ../../dm-1
    ├── dc1ba57c-3df8-43b5-a9c6-d7410a40f598 -> ../../sda1
    └── e1e3ac22-fd97-4841-baa0-0c3e3a333f0f -> ../../dm-0
/etc/udev/udev.conf

描述:该文件为udev主配置文件一般不用进行更改,如需更改请参考udev(5)

代码语言:javascript
复制
# 主配置文件:/etc/udev/udev.conf
  - udev_root:创建设备文件位置,默认为/dev
  - udev_rules:udev规则文件位置,默认为/etc/udev/rules.d
  - udev_log : syslog优先级,缺省为err
# 文件位置及格式
  - /etc/udev/rules.d/<rule_name>.rules
# 规则格式
<match-key><op><value>[,...]<assignment-key><op>value[,...]
/etc/udev/rules.d/<rule_name>.rules

描述: 这里是存放了相关规则来指定匹配硬件设备按照何种方式进行绑定名称;

基础实例:

代码语言:javascript
复制
# 示例1.匹配这是由内核建屋局并在名为设备的驱动程序是IDE磁盘。命名与默认名称的设备节点并创建一个符号链接到它命名sparedisk设备节点名称为my_spare_disk;
KERNEL=="hdb", DRIVER=="ide-disk", NAME="my_spare_disk", SYMLINK+="sparedisk"  

# 示例2.它创建于的/dev/CDROM 和/dev/CDROM0两个点的/dev/hdc符号链接。同样没有名称分配指定因此将使用默认的内核名称HDC
KERNEL=="hdc", SYMLINK+="cdrom cdrom0"

# 示例3.匹配的sysfs中size属性234441648的设备创建/dev/my_disk符号连接
SUBSYSTEM=="block", ATTR{size}=="234441648", SYMLINK+="my_disk"

# 实例4.子系统是一个block设备匹配设备类型大小以及scsi id匹配RESULT规则时候将为该设备创建/dev/ipsan符号连接
$vim /etc/udev/rules.d/100-ipsan.rules	
SUBSYSTEM=="block",					                       // 设备类型
ATTR{size}=="41943040",				                     // 设备大小
ATTRS{vendor}=="LIO-ORG ",		                     // 厂家
PROGRAM=="/usr/lib/udev/scsi_id  -g -u $devnode",  // 要执行的程序
RESULT=="36001405423854f332574ae7ae493f2b0",	     // 执行程序后的结果
SYMLINK+="ipsan"					                         // 别名

# 示例5.产生网卡设备文件的规则
# 该规则表示:如果存在设备的子系统为 net,并且地址 (MAC address) 为“AA:BB:CC:DD:EE:FF”,为该设备产生一个名为 public_NIC 的设备文件。
SUBSYSTEM=="net", SYSFS{address}=="AA:BB:CC:DD:EE:FF", NAME="public_NIC"

# 实例6.为指定大小的磁盘产生符号链接的规则
# 如果存在设备的子系统为 block,并且大小为 71096640(block),则为该设备的设备文件名产生一个名为 my_disk 的符号链接。
SUBSYSTEM=="block", SYSFS{size}=="71096640", SYMLINK ="my_disk"

# 实例7.通过外部命令为指定序列号的磁盘产生设备文件的规则
# 如果存在设备的内核设备名称是以 sd 开头 ( 磁盘设备 ),以数字结尾 ( 磁盘分区 ),并且通过外部命令查询该设备的 SCSI_ID 号为“35000c50000a7ef67”,则产生一个以 root_disk 开头,内核号码结尾的设备文件,并替换原来的设备文件(如果存在的话)。例如:产生设备名 /dev/root_disk2,替换原来的设备名 /dev/sda2。
KERNEL=="sd*[0-9]", PROGRAM=="/lib/udev/scsi_id -g -s %p", \
RESULT=="35000c50000a7ef67", NAME +="root_disk%n"
Examples

USB Printer 描述:我打开我的打印机它被分配了设备节点/dev/lp0,下面我想对其进行自定义设备符号名称;

代码语言:javascript
复制
# 设备信息获取
$udevadm info -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"

# udev 规则
SUBSYSTEM=="usb", ATTRS{serial}=="L72010011070626380", SYMLINK+="epson_680"

USB Camera 描述:和大多数相机一样,我的相机将自己标识为通过USB总线连接的外部硬盘使用SCSI传输。为了访问我的照片我挂载驱动器和复制图像文件到我的硬盘。

代码语言:javascript
复制
# USB Camera 设备信息
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"

# 规则
# 它出奇地简单:名称本身不同,因此我们可以在name字段上使用简单的模式匹配。
KERNEL=="sd?1", SUBSYSTEMS=="scsi", ATTRS{model}=="X250,D560Z,C350Z", SYMLINK+="camera"  #即/dev/camera

USB Hard Disk 描述:USB硬盘可与我上面描述的USB相机相比较,然而典型的使用模式是不同的。 在相机的例子中我解释了我对sdb节点不感兴趣——它真正的用途只是用于分区(例如fdisk),但我为什么要对相机进行分区!?当然如果你有一个100GB的USB硬盘,这是完全可以理解的,你可能想要分区,在这种情况下,我们可以利用udev的字符串替换:

代码语言:javascript
复制
# This rule creates symlinks such as:
# /dev/usbhd - The fdiskable node
# /dev/usbhd1 - The first partition (mountable)
# /dev/usbhd2 - The second partition (mountable)
KERNEL=="sd*", SUBSYSTEMS=="scsi", ATTRS{model}=="USB 2.0 Storage Device", SYMLINK+="usbhd%n"

USB Card Reader 描述:USB读卡器(CompactFlash、SmartMedia等)是另一种有不同使用要求的USB存储设备,比如下面将有节点命名:cfrdr, cfrdr1, cfrdr2, cfrdr3,…, cfrdr15。

代码语言:javascript
复制
# 利用all_partitions选项,它将为规则匹配的每个块设备创建16个分区节点:
KERNEL="sd*", SUBSYSTEMS=="scsi", ATTRS{model}=="USB 2.0 CompactFlash Reader", SYMLINK+="cfrdr%n", OPTIONS+="all_partitions"

CD/DVD drives 描述:我有两个光驱在这台电脑:一个DVD阅读器(hdc)和一个DVD重写(hdd)。我不希望这些设备节点发生变化,除非我物理上重新连接我的系统。但是为了方便许多用户喜欢使用/dev/dvd这样的设备节点。

代码语言:javascript
复制
SUBSYSTEM=="block", KERNEL=="hdc", SYMLINK+="dvd", GROUP="cdrom"
SUBSYSTEM=="block", KERNEL=="hdd", SYMLINK+="dvdrw", GROUP="cdrom"

Network interfaces 描述:即使网络接口是通过名称引用的,它们通常也没有与之关联的设备节点。尽管如此规则编写过程几乎是相同的。

代码语言:javascript
复制
# udevadm info -a -p /sys/class/net/eth0
  looking at class device '/sys/class/net/eth0':
    KERNEL=="eth0"
    ATTR{address}=="00:52:8b:d5:04:48"

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

注意事项:

要使此规则生效需要重新加载网络驱动程序。您可以卸载并重新加载模块,或者简单地重新启动系统。您还需要重新配置您的系统,使其使用“lan”而不是“eth0”。

在我完全删除所有对eth0的引用之前,我在进行这个操作时遇到了一些麻烦(接口没有被重命名)。在此之后您应该能够在任何对ifconfig或类似实用程序的调用中使用“lan”而不是“eth0”;

代码语言:javascript
复制
$cat /etc/sysconfig/network-scripts/ifcfg-ens192
TYPE="Ethernet"
PROXY_METHOD="none"
BROWSER_ONLY="no"
BOOTPROTO="static"
DEFROUTE="yes"
IPV4_FAILURE_FATAL="no"
IPV6INIT="yes"
IPV6_AUTOCONF="yes"
IPV6_DEFROUTE="yes"
IPV6_FAILURE_FATAL="no"
IPV6_ADDR_GEN_MODE="stable-privacy"
NAME="ens192"
UUID="78d46457-5eb7-4421-9637-ba4161637646"
DEVICE="ens192"
ONBOOT="yes"
Production Examples

生产实例1: ASM设备动态绑定

代码语言:javascript
复制
# 规则中写明了绑定源路径dm-*绑定磁盘的scsi id,绑定目标路径/dev/asm/hdisk00x,目标路径属组grid:asmadmin,目标路径权限066
$cat /etc/udev/rules.d/99-oracle-asmdevices.rules 
KERNEL=="dm-*",ENV{DM_UUID}=="mpath-36005076xxx000000000010cb",SYMLINK+="asm/hdisk001",OWNER="grid",GROUP="asmadmin",MODE="0660"
KERNEL=="dm-*",ENV{DM_UUID}=="mpath-36005076xxx000000000010cc",SYMLINK+="asm/hdisk002",OWNER="grid",GROUP="asmadmin",MODE="0660"
KERNEL=="dm-*",ENV{DM_UUID}=="mpath-36005076xxx000000000010cd",SYMLINK+="asm/hdisk003",OWNER="grid",GROUP="asmadmin",MODE="0660"

# 执行结果:
[root@ybnode01 ~]# ls -lrt /dev/asm/hdisk0*
lrwxrwxrwx 1 root root 7 Jun 15 15:31 /dev/asm/hdisk017 -> ../dm-2
lrwxrwxrwx 1 root root 8 Jun 15 15:31 /dev/asm/hdisk002 -> ../dm-13
[root@ybnode01 ~]# ls -lrt /dev/dm*
brw-rw---- 1 grid asmadmin 253,  2 Jun 15 15:34 /dev/dm-2
brw-rw---- 1 grid asmadmin 253, 13 Jun 15 15:34 /dev/dm-13
  • 注意点:udev绑定源路径权限不变绑定目标路径/dev/asm/hdisk*的权限是root:root 777 link到dm下。
    • 在rhel7中用udev绑定磁盘后,就算udev规则中写明了权限,但目标路径权限仍然是root:root 777
    • 在rhel6中其权限如udev规则中的一致grid:asmadmin 0660

生产实例2: 在multipath中绑定了scsi id 而又在udev中再次绑定显得有些多余(但最好是这么做),在 scsi id 已绑定的前提下udev可以有如下绑定方式:

代码语言:javascript
复制
# 绑定方式没有在udev规则中绑定磁盘路径与磁盘scsi id 没有生成额外的路径,仅修改了/dev/dm*的权限。
# 这里的udev规则只是用来绑定磁盘权限,数据库可直接使用dm*
$cat /etc/udev/rules.d/12-dm-permissions.rules 
ENV{DM_NAME}=="dm*",OWNER:="grid", GROUP:="asmadmin", MODE:="660"

另外做法是在 multipath.conf 中不写明wwid和alias的对应关系,只在udev中绑定源路径dm、目标路径、scsi id权限。 虽然这种方法有效但是很难理解,其缺陷是如果multipath不生成dm那也轮不到udev去绑定,所以udev一定在multipath之后,multipath没有绑定scsi id那么是不是可能会multipath在启动的时候把scsi id识别错了,这个时候udev在去绑定scsi id和dm所以我个人并不推荐这种绑定方式。

不同的运维人员有不同的做法但无论哪种绑定方式,最终的目的就把磁盘路径和scsi id绑定,且绑定asm要使用的asm_disk的path的权限,理解multipath和udev才可以处理异常状况。

注意事项:

当设备名改变时在 /etc/fstab 里保持系统分区名称的一致性,而不会受驱动加载顺序或者磁盘标签被破坏的影响,导致操作系统启动时找不到系统分区。

触发udev编写的规则配置生效:

代码语言:javascript
复制
start_udev                                      # RHEL6
systemctl restart systemd-udev-trigger.service  # RHEL7

注:本地文件系统 ext2/3/4 xfs ,同时只能单台设备使用gfs 集群文件系统(谷歌的一个文件系统)


0x04 UDEV 相关命令
udevadm 命令 - udev管理工具

描述:udevadm需要命令和命令特定的选项, 它控制system-udevd的运行时行为、请求内核事件、管理事件队列,并提供简单的调试机制。

语法选项:

代码语言:javascript
复制
# Synx
udevadm [--debug] [--version] [--help]

udevadm info [options] [devpath]

udevadm trigger [options] [devpath]

udevadm settle [options]

udevadm control option

udevadm monitor [options]

udevadm test [options] devpath

udevadm test-builtin [options] command devpath

# Option
-d, --debug #打印调试消息到标准错误
-h, --help #打印一个简短的帮助文本并退出。

子命令:

info :查询udev数据库以获取设备信息(查询的可以是设备名称以/dev)或者一个sys路径。

代码语言:javascript
复制
# Option
-q, --query=TYPE  #在数据库中查询指定类型的设备数据Valid TYPEs are: name, symlink, path, property, all.

-p, --path=DEVPATH #要查询的设备的/sys路径
   # e.g.  [/sys]/class/block/sda. This option is an alternative to the positional argument with a /sys/ prefix.
  udevadm info --path=/class/block/sda is equivalent to udevadm info /sys/class/block/sda.

-n, --name=FILE # 查询的设备节点或符号链接的名称(/dev)
  #e.g.  [/dev]/sda. This option is an alternative to the positional argument with a /dev/ prefix.
  udevadm info --name=sda is equivalent to udevadm info /dev/sda.

-r, --root
  Print absolute paths in name or symlink query.

-a, --attribute-walk
  Print all sysfs properties of the specified device that can be used in udev rules to match the specified device. It prints all devices along the
  chain, up to the root of sysfs that can be used in udev rules.

-x, --export
  Print output as key/value pairs. Values are enclosed in single quotes. This takes effects only when --query=property or --device-id-of-file=FILE is specified.

-P, --export-prefix=NAME
  Add a prefix to the key name of exported values. This implies --export.

-d, --device-id-of-file=FILE
  Print major/minor numbers of the underlying device, where the file lives on. If this is specified, all positional arguments are ignored.

-e, --export-db
  Export the content of the udev database.

 -e, --export-db
  Export the content of the udev database.

-c, --cleanup-db
  Cleanup the udev database.

-w[SECONDS], --wait-for-initialization[=SECONDS]
  Wait for device to be initialized. If argument SECONDS is not specified, the default is to wait forever.

trigger: 主要是用于在系统冷插拔时重放事件。

代码语言:javascript
复制
-v, --verbose
  Print the list of devices which will be triggered.

-n, --dry-run
  Do not actually trigger the event.

-t, --type=TYPE
  Trigger a specific type of devices. Valid types are: devices, subsystems. The default value is devices.

-c, --action=ACTION
  Type of event to be triggered. Possible actions are "add", "remove", "change", "move", "online", "offline", "bind", and "unbind". Also, the special
  value "help" can be used to list the possible actions. The default value is "change".

-s, --subsystem-match=SUBSYSTEM
  Trigger events for devices which belong to a matching subsystem. This option supports shell style pattern matching. When this option is specified
  more than once, then each matching result is ORed, that is, all the devices in each subsystem are triggered.

-S, --subsystem-nomatch=SUBSYSTEM
  Do not trigger events for devices which belong to a matching subsystem. This option supports shell style pattern matching. When this option is
  specified more than once, then each matching result is ANDed, that is, devices which do not match all specified subsystems are triggered.

-a, --attr-match=ATTRIBUTE=VALUE
  Trigger events for devices with a matching sysfs attribute. If a value is specified along with the attribute name, the content of the attribute is
  matched against the given value using shell style pattern matching. If no value is specified, the existence of the sysfs attribute is checked. When
  this option is specified multiple times, then each matching result is ANDed, that is, only devices which have all specified attributes are
  triggered.

-A, --attr-nomatch=ATTRIBUTE=VALUE
  Do not trigger events for devices with a matching sysfs attribute. If a value is specified along with the attribute name, the content of the
  attribute is matched against the given value using shell style pattern matching. If no value is specified, the existence of the sysfs attribute is
  checked. When this option is specified multiple times, then each matching result is ANDed, that is, only devices which have none of the specified
  attributes are triggered.
 -g, --tag-match=PROPERTY
  Trigger events for devices with a matching tag. When this option is specified multiple times, then each matching result is ANDed, that is, devices
  which have all specified tags are triggered.

-y, --sysname-match=NAME
  Trigger events for devices for which the last component (i.e. the filename) of the /sys path matches the specified PATH. This option supports shell
  style pattern matching. When this option is specified more than once, then each matching result is ORed, that is, all devices which have any of the
  specified NAME are triggered.

--name-match=NAME
  Trigger events for devices with a matching device path. When this option is specified more than once, then each matching result is ORed, that is,
  all specified devices are triggered.

-b, --parent-match=SYSPATH
  Trigger events for all children of a given device. When this option is specified more than once, then each matching result is ORed, that is, all
  children of each specified device are triggered.

-w, --settle
  Apart from triggering events, also waits for those events to finish. Note that this is different from calling udevadm settle.  udevadm settle waits
  for all events to finish. This option only waits for events triggered by the same command to finish.

--wait-daemon[=SECONDS]
  Before triggering uevents, wait for systemd-udevd daemon to be initialized. Optionally takes timeout value. Default timeout is 5 seconds. This is
  equivalent to invoke invoking udevadm control --ping before udevadm trigger.

settle : 监视udev事件队列,如果所有当前事件都被处理,则退出。

代码语言:javascript
复制
-t, --timeout=SECONDS
  Maximum number of seconds to wait for the event queue to become empty. The default value is 120 seconds. A value of 0 will check if the queue is
  empty and always return immediately.

-E, --exit-if-exists=FILE
  Stop waiting if file exists.

control: 修改正在运行的udev守护进程的内部状态。

代码语言:javascript
复制
-e, --exit
    Signal and wait for systemd-udevd to exit. No option except for --timeout can be specified after this option. Note that systemd-udevd.service
    contains Restart=always and so as a result, this option restarts systemd-udevd. If you want to stop systemd-udevd.service, please use the following:
    systemctl stop systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udevd.service

-l, --log-priority=value
    Set the internal log level of systemd-udevd. Valid values are the numerical syslog priorities or their textual representations: emerg, alert, crit,
    err, warning, notice, info, and debug.

-s, --stop-exec-queue
    Signal systemd-udevd to stop executing new events. Incoming events will be queued.

-S, --start-exec-queue
    Signal systemd-udevd to enable the execution of events.

-R, --reload
    Signal systemd-udevd to reload the rules files and other databases like the kernel module index. Reloading rules and databases does not apply any
    changes to already existing devices; the new configuration will only be applied to new events.

-p, --property=KEY=value
    Set a global property for all events.

-m, --children-max=value
    Set the maximum number of events, systemd-udevd will handle at the same time.

--ping
    Send a ping message to systemd-udevd and wait for the reply. This may be useful to check that systemd-udevd daemon is running.

-t, --timeout=seconds
    The maximum number of seconds to wait for a reply from systemd-udevd.

monitor : 侦听内核uevents和udev规则发送的事件,并将事件的devpath打印到控制台。它可以用来分析事件计时,通过比较内核uevent和udev事件的时间戳。

代码语言:javascript
复制
-k, --kernel
  Print the kernel uevents.

-u, --udev
  Print the udev event after the rule processing.

-p, --property
  Also print the properties of the event.

-s, --subsystem-match=string[/string]
  Filter kernel uevents and udev events by subsystem[/devtype]. Only events with a matching subsystem value will pass. When this option is specified
  more than once, then each matching result is ORed, that is, all devices in the specified subsystems are monitored.

-t, --tag-match=string
  Filter udev events by tag. Only udev events with a given tag attached will pass. When this option is specified more than once, then each matching
  result is ORed, that is, devices which have one of the specified tags are monitored.

test :针对一个设备,在不需要 uevent 触发的情况下模拟一次 udev的运行,并输出查询规则文件的过程、所执行的行为、规则文件的执行结果。

代码语言:javascript
复制
-a, --action=ACTION
  Type of event to be simulated. Possible actions are "add", "remove", "change", "move", "online", "offline", "bind", and "unbind". Also, the special value "help" can be used to list the possible actions. The default
  value is "add".

-N, --resolve-names=early|late|never
  Specify when udevadm should resolve names of users and groups. When set to early (the default), names will be resolved when the rules are parsed. When set to late, names will be resolved for every event. When set to
  never, names will never be resolved and all devices will be owned by root.

test-builtin : 为设备DEVPATH运行内置的命令命令,并打印调试输出。

简单实例: monitor 子命令

代码语言:javascript
复制
# 实例1.UDEV事件监控实时监控内核所处理的事件,比如添加/移除一块设备会提示相对应的信息
udevadm monitor -u         # 在规则处理之后打印udev事件。
udevadm monitor --property # 还要打印事件的属性。
udevadm monitor -k         # 内核 uevent 事件信息查看

info 子命令

代码语言:javascript
复制
# 实例2.查看磁盘设备在内核中的属性(替代udevinfo命令)
$udevadm info -a -p /sys/block/sda
# looking at device '/devices/pci0000:00/0000:00:15.0/0000:03:00.0/host1/target1:0:0/1:0:0:0/block/sda':
# looking at parent device '/devices/pci0000:00/0000:00:15.0/0000:03:00.0/host1/target1:0:0/1:0:0:0':
#   KERNELS=="1:0:0:0"
#   SUBSYSTEMS=="scsi"
#   DRIVERS=="sd"
# looking at parent device '/devices/pci0000:00/0000:00:15.0/0000:03:00.0/host1/target1:0:0':
#   KERNELS=="target1:0:0"
#   SUBSYSTEMS=="scsi"
#   DRIVERS==""
# looking at parent device '/devices/pci0000:00/0000:00:15.0/0000:03:00.0/host1':
#   KERNELS=="host1"
#   SUBSYSTEMS=="scsi"
#   DRIVERS==""
# looking at parent device '/devices/pci0000:00/0000:00:15.0/0000:03:00.0':
#   KERNELS=="0000:03:00.0"
#   SUBSYSTEMS=="pci"
#   DRIVERS=="vmw_pvscsi"
# looking at parent device '/devices/pci0000:00/0000:00:15.0':
#   KERNELS=="0000:00:15.0"
#   SUBSYSTEMS=="pci"
#   DRIVERS=="pcieport"
# looking at parent device '/devices/pci0000:00':
#   KERNELS=="pci0000:00"
#   SUBSYSTEMS==""
#   DRIVERS==""


# 实例3.为已经存在的设备节点编写规则可以直接使用以下属性
$udevadm info -n /dev/sda
# P: /devices/pci0000:00/0000:00:10.0/host32/target32:0:0/32:0:0:0/block/sda
# N: sda
# L: 0
# S: disk/by-path/pci-0000:00:10.0-scsi-0:0:0:0
# E: DEVPATH=/devices/pci0000:00/0000:00:10.0/host32/target32:0:0/32:0:0:0/block/sda
# E: DEVNAME=/dev/sda
# E: DEVTYPE=disk
# E: MAJOR=8
# E: MINOR=0
# E: SUBSYSTEM=block
# E: USEC_INITIALIZED=2120529
# E: SCSI_TPGS=0
# E: SCSI_TYPE=disk
# E: SCSI_VENDOR=VMware
# E: SCSI_VENDOR_ENC=VMware\x20\x20
# E: SCSI_MODEL=Virtual_disk
# E: SCSI_MODEL_ENC=Virtual\x20disk\x20\x20\x20\x20
# E: SCSI_REVISION=1.0
# E: ID_SCSI=1
# E: ID_VENDOR=VMware
# E: ID_VENDOR_ENC=VMware\x20\x20
# E: ID_MODEL=Virtual_disk
# E: ID_MODEL_ENC=Virtual\x20disk\x20\x20\x20\x20
# E: ID_REVISION=1.0
# E: ID_TYPE=disk
# E: MPATH_SBIN_PATH=/sbin
# E: ID_BUS=scsi
# E: ID_PATH=pci-0000:00:10.0-scsi-0:0:0:0
# E: ID_PATH_TAG=pci-0000_00_10_0-scsi-0_0_0_0
# E: ID_PART_TABLE_UUID=36f4f6a3-6312-408e-8497-a333afa589f7
# E: ID_PART_TABLE_TYPE=gpt
# E: DEVLINKS=/dev/disk/by-path/pci-0000:00:10.0-scsi-0:0:0:0
# E: TAGS=:systemd:
$udevadm info -q path -n /dev/sda
/devices/pci0000:00/0000:00:10.0/host32/target32:0:0/32:0:0:0/block/sda
$udevadm info -a -p $(udevadm info -q path -n /dev/sda)  # 效果同2

control 子命令

代码语言:javascript
复制
# 判断守护进程是否在线
sudo udevadm control --ping

test 子命令 描述:通常使用来调试规则文件;

代码语言:javascript
复制
# 1.由于 udevtest是扫描所有的规则文件 ( 包括系统自带的规则文件 ),所以会产生冗长的输出。为了让读者清楚地了解 udevtest,本例只在规则目录里保留一条规则:
$ vim /etc/udev/rules.d/99-test.rules
KERNEL=="sd*", PROGRAM="/lib/udev/scsi_id -g -s %p", RESULT=="35000c50000a7ef67", \
NAME="root_disk%n", SYMLINK="symlink_root_disk%n"

# 从 test 的执行过程可以看出,test对 sda 执行了外部命令 scsi_id, 得到的 stdout 和规则文件里的 RESULT 匹配,所以该规则匹配。然后 ( 模拟 ) 产生设备文件 /dev/root_disk和符号链接 /dev/symlink_root_disk,并为其设定权限。
$ udevadm test /block/sda 
# main: looking at device '/block/sda' from subsystem 'block'
# run_program: '/lib/udev/scsi_id -g -s /block/sda'
# run_program: '/lib/udev/scsi_id' (stdout) '35000c50000a7ef67'
# run_program: '/lib/udev/scsi_id' returned with status 0 
# udev_rules_get_name: reset symlink list 
# udev_rules_get_name: add symlink 'symlink_root_disk'
# udev_rules_get_name: rule applied, 'sda' becomes 'root_disk'
# udev_device_event: device '/block/sda' already in database, \
#                  validate currently present symlinks 
# udev_node_add: creating device node '/dev/root_disk', major = '8', \
#            minor = '0', mode = '0660', uid = '0', gid = '0'
# udev_node_add: creating symlink '/dev/symlink_root_disk' to 'root_disk'
udevinfo - 显示sysfs的设备路径相关属性信息 (deprecated)

描述:该命令用来构建udev规则的最直接方便的工具,现已经被系统整合进入udevadm形成了子命令,但是对于一些老系统仍然存在以下命令;

基础示例:

代码语言:javascript
复制
$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来为你查找设备路径对于已经存在的设备节点编写规则
udevinfo -a -p $(udevinfo -q path -n /dev/sda)

Tips:可依据其编写udev规则及其注意点

代码语言:javascript
复制
# 1.udevinfo 只生成一个属性列表,您可以在udev规则中作为匹配键使用。
SUBSYSTEM=="block", ATTR{size}=="234441648", NAME="my_hard_disk"
SUBSYSTEM=="block", SUBSYSTEMS=="scsi", ATTRS{model}=="ST3120827AS", NAME="my_hard_disk"

# 2.以下规则无效因为它试图匹配来自两个父设备的属性(不能进行设备关联匹配):
SUBSYSTEM=="block", ATTRS{model}=="ST3120827AS", DRIVERS=="sata_nv", NAME="my_hard_disk"

本章小结

描述: udev 是高效的设备管理工具,其最大的优势是动态管理设备和自定义设备的命名规则,因此替代 devfs 成为 Linux 默认的设备管理工具。

上文主要描述了Linux 用户能够了解到 udev 的工作原理和流程,灵活地运用 udev 规则文件,从而方便地管理 Linux 设备文件。

在udev规则中可以规定了系统所有设备绑定的条件当匹配则按照就规则创建符号链接, 在日常使用并不要您全部进行绑定而是按照需求绑定即可;

参考连接

本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-06-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0x00 前言简介
  • 0x01 安装udev
  • 0x02 配置文件树形
    • (1) 指令操作符
      • (2) 字符串替换传值
        • (3) 字符串匹配
          • (4) 设备文件的权限
            • (5) udev基本规则
              • (5) sysfs系统设备属性
              • 0x03 UDEV规则实例
                • /etc/udev/udev.conf
                  • /etc/udev/rules.d/<rule_name>.rules
                    • Examples
                      • Production Examples
                      • 0x04 UDEV 相关命令
                        • udevadm 命令 - udev管理工具
                          • udevinfo - 显示sysfs的设备路径相关属性信息 (deprecated)
                          • 本章小结
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
                          http://www.vxiaotou.com