蚊章汇 - udev
type: channel
link: https://linuxcn.bwsl.wang/tag/udev/
items: 在 Linux 使用 systemd-udevd 管理你的接入硬件
items: udev 入门：管理设备事件的 Linux 子系统
items: 在 Linux 中如何编写基本的 udev 规则
items: Linux 有问必答：如何在 Linux 中永久修改 USB 设备权限

在 Linux 使用 systemd-udevd 管理你的接入硬件
type: item
date: 2021-08-17T18:47:02+08:00
description: 使用 udev 管理你的 Linux 系统处理物理设备的方式。Linux 能够出色地自动识别、加载、并公开接入的无数厂商的硬件设备。事实上，很多年以前，正是这个特性说服我，坚持让我的雇主将整个基础设施转换到 Linux。痛点在于 Redmond 的某家公司（LCTT 译注：指微软）不能在我们的 Compaq 台式机上加载集成网卡的驱动，而 Linux 可以轻松实现这一点。从那以后的岁月里，Linux 的识别设备库随着该过程的复杂化而与日俱增，而 udev 就是解决这个问题的希望之星。udev 负责监听 Linux 内核发出的改变设备状态的事件。它可能是一个新 USB 设备被插入或拔出，也可能是一个无线鼠标因浸入洒出的咖啡中而脱机。udev 负责处理所有的状态变更，比如指定访问设备使用的名称和权限。这些更改的记录可以通过 dmesg 获取。由于 dmesg 的输出通常有几千行，对结果进行过滤通常是聪明的选择。下面的例子说明了 Linux 如何识别我的 WiFi 接口。这个例子展示了我的无线设备使用的芯片组（ath9k）、启动过程早期阶段分配的原始名称（wlan0）、以及正在使用的又臭又长的永久名称（wlxec086b1ef0b3）：$ dmesg | grep wlan [ 5.396874] ath9k_htc 1-3:1.0 wlxec086b1ef0b3: renamed from wlan0 在这篇文章中，我会讨论为何有人想要使用这样的名称。在这个过程中，我会探索剖析 udev 的配置文件，然后展示如何更改 udev 的设置，包括编辑系统命名设备的方式。这篇文件基于我的新课程中《Linux 系统优化》的一个模块。理解 udev 配置系统使用 systemd 的机器上，udev 操作由 systemd-udevd 守护进程管理，你可以通过常规的 systemd 方式使用 systemctl status systemd-udevd 检查 udev 守护进程的状态。严格来说，udev 的工作方式是试图将它收到的每个系统事件与 /lib/udev/rules.d/ 和 /etc/udev/rules.d/ 目录下找到的规则集进行匹配。规则文件包括匹配键和分配键，可用的匹配键包括 action、name 和 subsystem。这意味着如果探测到一个属于某个子系统的、带有特定名称的设备，就会给设备指定一个预设的配置。接着，“分配”键值对被拿来应用想要的配置。例如，你可以给设备分配一个新名称、将其关联到文件系统中的一个符号链接、或者限制为只能由特定的所有者或组访问。这是从我的工作站摘出的一条规则：$ cat /lib/udev/rules.d/73-usb-net-by-mac.rules # Use MAC based names for network interfaces which are directly or indirectly # on USB and have an universally administered (stable) MAC address (second bit # is 0). Don't do this when ifnames is disabled via kernel command line or # customizing/disabling 99-default.link (or previously 80-net-setup-link.rules). IMPORT{cmdline}="net.ifnames" ENV{net.ifnames}=="0", GOTO="usb_net_by_mac_end" ACTION=="add", SUBSYSTEM=="net", SUBSYSTEMS=="usb", NAME=="", \ ATTR{address}=="?[014589cd]:*", \ TEST!="/etc/udev/rules.d/80-net-setup-link.rules", \ TEST!="/etc/systemd/network/99-default.link", \ IMPORT{builtin}="net_id", NAME="$env{ID_NET_NAME_MAC}" add 动作告诉 udev，只要新插入的设备属于网络子系统，并且是一个 USB 设备，就执行操作。此外，如果我理解正确的话，只有设备的 MAC 地址由特定范围内的字符组成，并且 80-net-setup-link.rules 和 99-default.link 文件不存在时，规则才会生效。假定所有的条件都满足，接口 ID 会改变以匹配设备的 MAC 地址。还记得之前的 dmes…

udev 入门：管理设备事件的 Linux 子系统
type: item
date: 2018-12-10T06:12:08+08:00
description: 创建这样一个脚本，当指定的设备插入时触发你的计算机去做一个指定动作。udev 是一个为你的计算机提供设备事件的 Linux 子系统。通俗来讲就是，当你的计算机上插入了像网卡、外置硬盘（包括 U 盘）、鼠标、键盘、游戏操纵杆和手柄、DVD-ROM 驱动器等等设备时，代码能够检测到它们。这样就能写出很多可能非常有用的实用程序，而它已经很好了，普通用户就可以写出脚本去做一些事情，比如当某个硬盘驱动器插入时，执行某个任务。这篇文章教你去如何写一个由一些 udev 事件触发的 udev 脚本，比如插入了一个 U 盘。当你理解了 udev 的工作原理，你就可以用它去做各种事情，比如当一个游戏手柄连接后加载一个指定的驱动程序，或者当你用于备份的驱动器连接后，自动执行备份工作。一个初级的脚本使用 udev 的最佳方式是从一个小的代码块开始。不要指望从一开始就写出完整的脚本，而是从最简单的确认 udev 触发了某些指定的事件开始。对于你的脚本，依据你的目标，并不是在任何情况下都能保证你亲眼看到你的脚本运行结果的，因此需要在你的脚本日志中确认它成功触发了。而日志文件通常放在 /var 目录下，但那个目录通常是 root 用户的领地。对于测试目的，可以使用 /tmp，它可以被普通用户访问并且在重启动后就被清除了。打开你喜欢的文本编辑器，然后输入下面的简单脚本：#!/usr/bin/bash echo $date > /tmp/udev.log把这个脚本放在 /usr/local/bin 或缺省可运行路径的位置中。将它命名为 trigger.sh，并运行 chmod +x 授予可运行权限：$ sudo mv trigger.sh /usr/local/bin $ sudo chmod +x /usr/local/bin/trigger.sh这个脚本没有任何和 udev 有关的事情。当它运行时，这个脚本将在文件 /tmp/udev.log 中放入当前的时间戳。你可以自己测试一下这个脚本：$ /usr/local/bin/trigger.sh $ cat /tmp/udev.log Tue Oct 31 01:05:28 NZDT 2035接下来让 udev 去触发这个脚本。唯一设备识别为了让你的脚本能够被一个设备事件触发，udev 必须要知道在什么情况下调用该脚本。在现实中，你可以通过它的颜色、制造商、以及插入到你的计算机这一事实来识别一个 U 盘。而你的计算机，它需要一系列不同的标准。udev 通过序列号、制造商、以及提供商 ID 和产品 ID 号来识别设备。由于现在你的 udev 脚本还处于它的生命周期的早期阶段，因此要尽可能地宽泛、非特定和包容。换句话说就是，你希望首先去捕获尽可能多的有效 udev 事件来触发你的脚本。使用 udevadm monitor 命令你可以实时利用 udev，并且可以看到当你插入不同设备时发生了什么。用 root 权限试一试。$ su # udevadm monitor该监视函数输出接收到的事件：UDEV：在规则处理之后发出 udev 事件KERNEL：内核发送 uevent 事件在 udevadm monitor 命令运行时，插入一个 U 盘，你将看到各种信息在你的屏幕上滚动而出。注意那一个 ADD 事件的事件类型。这是你所需要的识别事件类型的一个好方法。udevadm monitor 命令提供了许多很好的信息，但是你可以使用 udevadm info 命令以更好看的格式来看到它，假如你知道你的 U 盘当前已经位于你的 /dev 树。如果不在这个树下，拔下它并重新插入，然后立即运行这个命令：$ su -c 'dmesg | tail | fgrep -i sd*'举例来说，如果那个命令返回 sdb: sdb1，说明内核已经给你的 U 盘分配了 sdb 卷标。或者，你可以使用 lsblk 命令去查看所有连接到你的系统上的驱动器，包括它的大小和分区。现在，你的驱动器已经处于你的文件系统中了，你可以使用下面的命令去查看那个设备的相关 udev 信息：# udevadm info -a -n /dev/sdb | less这个命令将返回许多信息。现在我们只关心信息中的第一个块。你的任务是从 udev 的报告中找出能唯一标识那个设备的部分，然后当计算机检测到这些唯一属性时，告诉 udev 去触发你的脚本。udevadm info 命令处理一个（由设备路径指定的）设备上的报告，接着“遍历”父级设备链。对于找到的大多数设备，它以一个“键值对”格式输出所有可能的属性。你可以写一个规则，从一个单个的父级设备属性上去匹配插入设备的属性。looking at device '/devices/000:000/blah/blah//bloc…

在 Linux 中如何编写基本的 udev 规则
type: item
date: 2018-02-20T23:06:32+08:00
description: 读者对象理解 udev 背后的基本概念，学习如何写简单的规则。要求root 权限难度中等约定# - 要求给定的命令使用 root 权限或者直接以一个 root 用户或者使用 sudo 命令去运行。$ - 要求给定的命令以一个普通的非特权用户运行。介绍在 GNU/Linux 系统中，虽然设备的底层支持是在内核层面处理的，但是，它们相关的事件管理是在用户空间中通过 udev 来管理的。确切地说是由 udevd 守护进程来完成的。学习如何去写规则，并应用到发生的这些事件上，将有助于我们修改系统的行为并使它适合我们的需要。规则如何组织udev 规则是定义在一个以 .rules 为扩展名的文件中。那些文件主要放在两个位置：/usr/lib/udev/rules.d，这个目录用于存放系统安装的规则；/etc/udev/rules.d/ 这个目录是保留给自定义规则的。定义那些规则的文件的命名惯例是使用一个数字作为前缀（比如，50-udev-default.rules），并且以它们在目录中的词汇顺序进行处理的。在 /etc/udev/rules.d 中安装的文件，会覆盖安装在系统默认路径中的同名文件。规则语法如果你理解了 udev 规则的行为逻辑，它的语法并不复杂。一个规则由两个主要的节构成：match 部分，它使用一系列用逗号分隔的键定义了规则应用的条件，而 action 部分，是当条件满足时，我们执行一些动作。测试案例讲解可能的选项的最好方法莫过于配置一个真实的案例，因此，我们去定义一个规则作为演示，当鼠标被连接时禁用触摸板。显然，在该规则定义中提供的属性将反映我的硬件。我们将在 /etc/udev/rules.d/99-togglemouse.rules 文件中用我们喜欢的文本编辑器来写我们的规则。一条规则定义允许跨多个行，但是，如果是这种情况，必须在一个换行字符之前使用一个反斜线（\）表示行的延续，就和 shell 脚本一样。这是我们的规则：ACTION=="add" \ , ATTRS{idProduct}=="c52f" \ , ATTRS{idVendor}=="046d" \ , ENV{DISPLAY}=":0" \ , ENV{XAUTHORITY}="/run/user/1000/gdm/Xauthority" \ , RUN+="/usr/bin/xinput --disable 16" 我们来分析一下这个规则。操作符首先，对已经使用以及将要使用的操作符解释如下：== 和 != 操作符== 是相等操作符，而 != 是不等于操作符。通过使用它们，我们可以确认规则上应用的键是否匹配各自的值。分配操作符 = 和 :== 是赋值操作符，是用于为一个键赋值。当我们想要赋值，并且想确保它不会被其它规则所覆盖，我们就需要使用 := 操作符来代替，使用这个操作符分配的值，它就不能被改变。+= 和 -= 操作符+= 和 -= 操作符各自用于从一个指定的键定义的值列表中增加或者移除一个值。我们使用的键现在，来分析一下在这个规则中我们使用的键。首先，我们有一个 ACTION 键：通过使用它，当在一个设备上发生了特定的事件，我们将指定我们要应用的规则的具体内容。有效的值有 add、remove 以及 change。 然后，我们使用 ATTRS 关键字去指定一个属性去匹配。我们可以使用 udevadm info 命令去列出一个设备属性，提供它的名字或者 sysfs 路径即可：udevadm info -ap /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1/0003:046D:C52F.0010/input/input39 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:1d.0/usb2/2-1/2-1.2/2-1.2:1.1/0003:046D:C52F.0010/input/input39': KERNEL=="inp…

Linux 有问必答：如何在 Linux 中永久修改 USB 设备权限
type: item
date: 2015-10-22T17:14:00+08:00
description: 提问：当我尝试在 Linux 中运行 USB GPS 接收器时我遇到了下面来自 gpsd 的错误。gpsd[377]: gpsd:ERROR: read-only device open failed: Permission denied gpsd[377]: gpsd:ERROR: /dev/ttyUSB0: device activation failed. gpsd[377]: gpsd:ERROR: device open failed: Permission denied - retrying read-only 看上去 gpsd 没有权限访问 USB 设备（/dev/ttyUSB0）。我该如何永久修改它在Linux上的权限？当你在运行一个会读取或者写入USB设备的进程时，进程的用户/组必须有权限这么做才行。当然你可以手动用chmod命令改变 USB 设备的权限，但是手动的权限改变只是暂时的。USB 设备会在下次重启时恢复它的默认权限。作为一个永久的方式，你可以创建一个基于 udev 的 USB 权限规则，它可以根据你的选择分配任何权限模式。下面是该如何做。首先，你需要找出 USB 设备的 vendorID 和 productID。使用lsusb命令。$ lsusb -vvv 上面lsusb的输出中，找出你的 USB 设备，并找出"idVendor"和"idProduct"字段。本例中,我们的结果是idVendor (0x067b)和 idProduct (0x2303)下面创建一个新的udev规则。$ sudo vi /etc/udev/rules.d/50-myusb.rules SUBSYSTEMS=="usb", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", GROUP="users", MODE="0666" 用你自己的"idVendor"和"idProduct"来替换。MODE="0666"表示USB设备的权限。现在重启电脑并重新加载 udev 规则：$ sudo udevadm control --reload 接着验证下 USB 设备的权限。via: http://ask.xmodulo.com/change-usb-device-permission-linux.html作者：Dan Nanni 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出