一.udev简介
udev是一个设备管理工具,udev以守护进程的形式运行,通过侦听内核发出来的uevent来管理/dev目录下的设备文件。udev在用户空间运行,而不在内核空间 运行。它能够根据系统中的硬件设备的状态动态更新设备文件,包括设备文件的创建,删除等。设备文件通常放在/dev目录下。使用udev后,在/dev目录下就只包含系统中真正存在的设备。
二.udev的配置文件
主要的udev配置文件是/etc/udev/udev.conf文件。
udev_root="/dev/"
udev_rules="/etc/udev/rules.d/"
udev_log="err"
udev_root:代表着设备文件添加到哪。
udev_rules:代表着udev的规则存储的目录。这个目录存储的是以.rules结束的文件。每一个文件处理一系列规则来帮助udev分配名字给设备文件以保证能被内核识别。你的/etc/udev/rules.d下面可能有好几个udev规则文件,这些文件一部分是udev包安装的,另外一部分则是可能是别的硬件或者软件包生成的。该目录下有多个文件时,udev读取文件是按照文件名的ASCII字母顺序来读取的,如果udev一旦找到了与新加入的设备匹配的规则,udev 就会根据规则定义的措施对新设备进行配置。同时不再读后续的规则文件。
udev_log:代表着udev的日志级别,用syslog记录错误信息。
三.udev的工作流程图
四.udev的匹配规则
在/etc/udev/rules.d/文件夹下有一系列的.rules文件,在这些文件中有一些匹配规则:
udev规则的所有操作符:
“==”:比较键、值,若等于,则该条件满足;
“!=”:比较键、值,若不等于,则该条件满足;
“=”:对一个键赋值;
“+=”:为一个表示多个条目的键赋值。
“:=”:对一个键赋值,并拒绝之后所有对该键的改动。目的是防止后面的规则文件对该键赋值。
udev规则的匹配键:
ACTION:事件(uevent)的行为,例如:add(添加设备)、remove(删除设备)。
KERNEL:内核设备名称,例如:sda,cdrom。
DEVPATH:设备的devpath路径。
SUBSYSTEM:设备的子系统名称,例如:sda的子系统为block。
BUS:设备在devpath 里的总线名称,例如:usb。
DRIVER:设备在devpath 里的设备驱动名称,例如:ide-cdrom。
ID:设备在devpath 里的识别号。
SYSFS{filename}:设备的devpath 路径下,设备的属性文件“filename”里的内容。
例如:SYSFS{model}==“ST936701SS”表示:如果设备的型号为ST936701SS,则该设备匹配该匹配键。
在一条规则中,可以设定最多五条SYSFS的匹配键。
ENV{key}:环境变量。在一条规则中,可以设定最多五条环境变量的匹配键。
PROGRAM:调用外部命令。
RESULT:外部命令PROGRAM 的返回结果。例如:
PROGRAM=="/lib/udev/scsi_id-g -s $devpath", RESULT==“35000c50000a7ef67”
调用外部命令/lib/udev/scsi_id查询设备的SCSIID,如果返回结果为35000c50000a7ef67,则该设备匹配该匹配键。
udev 的重要赋值键:
NAME:在/dev下产生的设备文件名。只有第一次对某个设备的NAME的赋值行为生效,之后匹配的规则再对该设备的NAME赋值行为将被忽略。如果没有任何规则对设备的NAME赋值,udev将使用内核设备名称来产生设备文件。
SYMLINK:为/dev/下的设备文件产生符号链接。由于udev只能为某个设备产生一个设备文件,所以为了不覆盖系统默认的udev规则所产生的文件,推荐使用符号链接。
OWNER, GROUP, MODE:为设备设定权限。
ENV{key}:导入一个环境变量。
RUN:运行后面的程序。
udev 的值和可调用的替换操作符:
在键值对中的键和操作符都介绍完了,最后是值(value)。Linux用户可以随意地定制udev规则文件的值。例如:my_root_disk,my_printer。同时也可以引用下面的替换操作符:
$kernel, %k:设备的内核设备名称,例如:sda、cdrom。
$number, %n:设备的内核号码,例如:sda3的内核号码是3。
$devpath, %p:设备的devpath路径。
$id, %b:设备在devpath里的ID号。
$ s y s f s sysfs 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:临时设备名。
%%:符号%本身。
$$
:
符
号
:符号
:符号本身。
注意:在匹配的过程中,要匹配所有的比较键都满足时,才算匹配成功。
下面举个例子来说明一下,有这样一条规则:
SUBSYSTEM==“net”, ACTION==“add”, SYSFS{address}==“00:0d:87:f6:59:f3”, IMPORT="/sbin/rename_netiface %k eth0"
这个规则中的“匹配”部分有三项,分别是SUBSYSTEM,ACTION和SYSFS。而"赋值"部分有一项,是IMPORT。这个规则就是说,当系统中出现的新硬件属于net子系统范畴,系统对该硬件采取的动作是加入这个硬件,且这个硬件在SYSFS文件系统中的“address”信息等于“00: 0d…"时,对这个硬件在udev层次施行的动作是调用外部程序/sbin/rename_netiface,传递的参数有两个,一个是“%k”,代表内核对该新设备定义的名称。另一个是”eth0“。
从上面这个例子中可以看出,udev的规则的写法比较灵活的,尤其在“匹配”部分中,可以通过诸如”*“, ”?“,[a-c],[1-9]等shell通配符来灵活匹配多个匹配项。具体的语法可以参考udev的man文档。
udev怎样做到不管设备连接的顺序而维持一个统一的设备名?
答:实际上,udev是通过对内核产生的设备名增加别名的方式来达到上述目的的。前面说过,udev是用户模式程序,不会更改内核的行为。因此,内核依然会我行我素地产生设备名如sda,sdb等。但是,udev可以根据设备的其他信息如总线(bus),生产商(vendor)等不同来区分不同的设备,并产生设备文件。udev只要为这个设备文件取一个固定的文件名就可以解决这个问题。在后续对设备的操作中,只要引用新的设备名就可以了。但为了保证最大限度的兼容,一般来说,新设备名总是作为一个对内核自动产生的设备名的符号链接(link)来使用的。
五.udev的使用方法
1.使用udevadm 命令来查看设备的信息:
在使用udev时需要获得该设备的一些信息,来用于匹配规则。
udevadm info -a -p $(udevadm info -q path -n /dev/sdb)
其中/dev/sdb是插入设备后设备在/dev下的名字。
输出如下:
Udevadm info 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 '/devices/pci0000:00/0000:00:10.0/host20/target20:0:1/20:0:1:0/block/sdb':
KERNEL=="sdb"
SUBSYSTEM=="block"
DRIVER==""
ATTR{alignment_offset}=="0"
ATTR{capability}=="50"
ATTR{discard_alignment}=="0"
ATTR{events}==""
ATTR{events_async}==""
ATTR{events_poll_msecs}=="-1"
ATTR{ext_range}=="256"
ATTR{hidden}=="0"
ATTR{inflight}==" 0 0"
ATTR{range}=="16"
ATTR{removable}=="0"
ATTR{ro}=="0"
ATTR{size}=="41943040"
ATTR{stat}==" 85 0 4184 20 0 0 0 0 0 8 20"
looking at parent device '/devices/pci0000:00/0000:00:10.0/host20/target20:0:1/20:0:1:0':
KERNELS=="20:0:1:0"
SUBSYSTEMS=="scsi"
DRIVERS=="sd"
ATTRS{blacklist}==""
ATTRS{device_blocked}=="0"
ATTRS{device_busy}=="0"
ATTRS{dh_state}=="detached"
ATTRS{eh_timeout}=="10"
ATTRS{evt_capacity_change_reported}=="0"
ATTRS{evt_inquiry_change_reported}=="0"
ATTRS{evt_lun_change_reported}=="0"
ATTRS{evt_media_change}=="0"
ATTRS{evt_mode_parameter_change_reported}=="0"
ATTRS{evt_soft_threshold_reached}=="0"
ATTRS{inquiry}==""
ATTRS{iocounterbits}=="32"
ATTRS{iodone_cnt}=="0x7a"
ATTRS{ioerr_cnt}=="0x3"
ATTRS{iorequest_cnt}=="0x7a"
ATTRS{model}=="VMware Virtual S"
ATTRS{queue_depth}=="32"
ATTRS{queue_ramp_up_period}=="120000"
ATTRS{queue_type}=="simple"
ATTRS{rev}=="1.0 "
ATTRS{scsi_level}=="3"
ATTRS{state}=="running"
ATTRS{timeout}=="180"
ATTRS{type}=="0"
ATTRS{vendor}=="VMware, "
looking at parent device '/devices/pci0000:00/0000:00:10.0/host20/target20:0:1':
KERNELS=="target20:0:1"
SUBSYSTEMS=="scsi"
DRIVERS==""
looking at parent device '/devices/pci0000:00/0000:00:10.0/host20':
KERNELS=="host20"
SUBSYSTEMS=="scsi"
DRIVERS==""
looking at parent device '/devices/pci0000:00/0000:00:10.0':
KERNELS=="0000:00:10.0"
SUBSYSTEMS=="pci"
DRIVERS=="mptspi"
ATTRS{broken_parity_status}=="0"
ATTRS{class}=="0x010000"
ATTRS{config}==""
ATTRS{consistent_dma_mask_bits}=="32"
ATTRS{d3cold_allowed}=="0"
ATTRS{device}=="0x0030"
ATTRS{dma_mask_bits}=="32"
ATTRS{driver_override}=="(null)"
ATTRS{enable}=="1"
ATTRS{irq}=="17"
ATTRS{local_cpulist}=="0-3"
ATTRS{local_cpus}=="00000000,00000000,00000000,0000000f"
ATTRS{msi_bus}=="1"
ATTRS{numa_node}=="-1"
ATTRS{revision}=="0x01"
ATTRS{subsystem_device}=="0x1976"
ATTRS{subsystem_vendor}=="0x15ad"
ATTRS{vendor}=="0x1000"
looking at parent device '/devices/pci0000:00':
KERNELS=="pci0000:00"
SUBSYSTEMS==""
DRIVERS==""
2.编写.rules文件的规则
进入/etc/udev/rules.d文件夹:
cd /etc/udev/rules.d
新建文件10-usb.rules:
vi 10-usb.rules
在10-usb.rules文件中输入:
KERNEL=="sdb",SUBSYSTEM=="block",ACTION=="add",SYMLINK+="USB_link"
然后保存,退出。
3.使得udev文件生效的方法:
通常,使得配置后的文件生效,需要采用热插拔的方法更新udev规则,不过有更简单的方法如下:
udevadm test /sys/class/block/sdb
4.结果如下:
在/dev文件夹下: