当前位置: 首页 > 科技观察

udev入门:用于管理设备事件的Linux子系统

时间:2023-03-20 17:35:38 科技观察

创建一个脚本,在插入特定设备时触发您的计算机执行特定操作。udev是一个为您的计算机提供设备事件的Linux子系统。通俗地说,代码会检测插入计算机的网卡、外部硬盘驱动器(包括U盘)、鼠标、键盘、操纵杆和控制器、DVD-ROM驱动器等设备。这允许编写许多可能非常有用的实用程序,并且普通用户可以编写脚本来执行某些操作(例如在插入某个硬盘驱动器时执行某些任务)已经足够好了。本文教您如何编写udev由某些udev事件触发的脚本,例如插入U盘。了解udev的工作原理后,您可以使用它来做各种事情,例如在连接游戏手柄时加载特定驱动程序,或者在连接备份驱动器时自动执行备份作业。基本脚本使用udev的最佳方式是从一个小代码块开始。不要指望一开始就写出完整的脚本,而是从最简单的udev触发一些指定事件的确认开始。对于你的脚本,根据你的目标,并不总是能够保证你会看到你的脚本运行的结果,所以你需要在你的脚本日志中确认它是否触发成功。日志文件通常放在/var目录中,但该目录通常是root用户的域。出于测试目的,请使用/tmp,它可供普通用户访问并在重新启动后被清除。打开您喜欢的文本编辑器并输入以下简单脚本:#!/usr/bin/bashecho$date>/tmp/udev.log将此脚本放在/usr/local/bin或默认可运行路径的位置。将其命名为trigger.sh,并运行chmod+x以授予可运行权限:$sudomvtrigger.sh/usr/local/bin$sudochmod+x/usr/local/bin/trigger.sh此脚本没有任何和udev相关的东西。当它运行时,该脚本会将当前时间戳放入文件/tmp/udev.log中。你可以自己测试这个脚本:$/usr/local/bin/trigger.sh$cat/tmp/udev.logTueOct3101:05:28NZDT2035接下来让udev触发这个脚本。唯一的设备标识为了让您的脚本被设备事件触发,udev必须知道脚本在什么情况下被调用。实际上,您可以通过颜色、制造商以及插入计算机的事实来识别USB驱动器。而你的电脑,它需要一套不同的标准。udev通过序列号、制造商和供应商ID以及产品ID号来识别设备。由于您的udev脚本现在处于其生命周期的早期,请尝试尽可能广泛、非特定和包容。换句话说,您希望首先捕获尽可能多的有效udev事件来触发您的脚本。使用udevadmmonitor命令,您可以实时使用udev并查看插入不同设备时发生的情况。用root权限试试。$su#udevadmmonitor监控函数输出接收到的事件:UDEV:规则处理后发送udev事件KERNEL:从内核发送uevent事件udevadmmonitor命令运行时,插入U盘,你会看到卷轴中的各种信息在屏幕上。请注意该ADD事件的事件类型。这是确定您需要的事件类型的好方法。udevadmmonitor命令提供了很多有用的信息,但您可以使用udevadminfo命令以更好的格式查看它,前提是您知道您的USB记忆棒当前位于/dev树中。如果没有,请将其拔下并重新插入,然后立即运行此命令:$su-c'dmesg|尾巴|fgrep-isd*'例如,如果该命令返回sdb:sdb1,则内核已为您的USB驱动器分配了卷标sdb。或者,您可以使用lsblk命令查看连接到系统的所有驱动器,包括它们的大小和分区。现在您的驱动器在您的文件系统中,您可以使用以下命令查看有关该设备的udev信息:#udevadminfo-a-n/dev/sdb|less这个命令会返回很多信息。现在我们只关心消息中的第一个块。您的任务是从udev的报告中找出唯一标识该设备的部分,然后告诉udev在计算机检测到这些唯一属性时触发您的脚本。udevadminfo命令处理有关设备(由设备路径指定)的报告,然后“遍历”父设备链。对于它找到的大多数设备,它以“键值对”格式输出所有可能的属性。您可以编写规则来匹配来自单个父设备属性的插入设备的属性。查看设备'/devices/000:000/blah/blah//block/sdb':KERNEL=="sdb"SUBSYSTEM=="block"DRIVER==""ATTR{ro}=="0"ATTR{size}=="125722368"ATTR{stat}=="276515375393"ATTR{range}=="16"ATTR{discard\_alignment}=="0"ATTR{removable}=="1"ATTR{blah}=="blah"一个udev规则必须包含来自单个父设备的一个属性。parent属性是描述一个设备最基本的东西,比如是不是插在物理端口上,或者容量是多少,或者是不是可移动设备。由于KERNEL卷标sdb可能会由于分配给之前插入的其他驱动器而发生变化,因此卷标不是udev规则的父属性的好选择。但是,您可以在进行概念验证时使用它。事件的一个很好的候选者是SUBSYSTEM属性,它指示设备是一个“块”系统设备(这就是我们使用lsblk命令列出设备的原因)。在/etc/udev/rules.d目录下打开一个名为80-local.rules的文件,然后输入以下代码:SUBSYSTEM="block",ACTION="add",RUN+="/usr/local/bin/trigger.sh”,拔下测试USB驱动器,然后重新启动系统。等等,重启Linux机器?理论上,你可以只运行udevadmcontrol--reload它会重新加载所有规则,但在我们实验的这个阶段,绝对有必要排除任何可能影响实验结果的因素。udev非常复杂,为了让你不至于整夜躺在床上思考为什么这条规则不起作用,是不是因为语法错误?它仍然应该重新启动。因此,无论POSIX装腔作势地告诉您什么,您都应该重新启动。系统重新启动后,切换到文本控制台(使用Ctl+Alt+F3或类似方式)并插入USB驱动器。如果你运行的是一个不错的内核,当你插入U盘时你可能会看到很多输出。如果您看到类似“无法执行/usr/local/bin/trigger.sh”的错误消息,可能是因为您忘记授予脚本运行权限。否则你会看到,一个设备插入,它得到一些由内核设备分配的东西,等等。现在是见证奇迹的时候了。$cat/tmp/udev.logTueOct3101:35:28NZDT2035如果您在/tmp/udev.log中看到***日期和时间,则udev已成功触发您的脚本。改进规则做一些有用的事情现在的问题是使用的规则太通用了。插入鼠标、U盘或某人的U盘会盲目触发此脚本。现在,让我们关注我们想要触发您的脚本的特定U盘。实现上述目标的一种方法是使用提供商ID和产品ID。您可以使用lsusb命令获取这些数字。$lsusbBus001设备002:ID8087:0024SlackerCorp.HubBus002设备002:ID8087:0024SlackerCorp.HubBus003设备005:ID03f0:3307TyCoonCorp.Bus003Deviceb0找到061:ID0002001设备003:ID13d3:5165SBoNetworks在这个例子中,TyCoonCorp前面的03f0:3307代表providerID和productID的属性。您还可以在udevadminfo-a-n/dev/sdb|的输出中看到这些数字。grepvendor,但很容易从lsusb的输出中一目了然地找到它们。现在,您可以在脚本中包含这些属性。SUBSYSTEM=="block",ATTRS{idVendor}=="03f0",ACTION=="add",RUN+="/usr/local/bin/thumb.sh"来测试它(是的,确保没有来自udev,我们仍然建议先重启),它应该像以前一样工作,现在,如果你插入一个不同公司生产的U盘(因为他们有不同的供应商ID),或者插入一个鼠标,或者插入一台打印机,这个脚本不会被触发。继续添加新属性以进一步关注您希望触发脚本的唯一USB驱动器。使用udevadminfo-a-n/dev/sdb命令,您可以找到提供商名称、序列号或产品名称等信息。为清楚起见,请确保一次只添加一个新属性。我们(和其他人在网上看到的)在udev规则中遇到的大多数错误是由于一次添加了太多的属性并且想知道为什么事情不起作用。最安全的做法是逐一测试属性,确保udev能够成功识别您的设备。安全地编写udev规则以在插入驱动器时自动执行某些操作会引发安全问题。在我的机器上,我什至没有打开自动挂载,就本文而言,脚本和规则可以在插入设备时运行命令来做事。这里有两件事要记住。专注于您的udev规则,当您实际使用它们时,一旦规则起作用,脚本就会被触发。执行脚本来盲目地将数据复制到您的计算机或从您的计算机中复制数据是一个非常糟糕的主意,因为有可能遇到与您插入计算机的同一品牌U盘的人。你机器上的情况。不要在编写udev规则和脚本时忘记它们的存在。我知道哪些计算机上有我的udev规则,这些计算机通常是我的个人计算机,而不是我用来开会或在办公室工作的计算机。一台计算机越“社交”,它上面可以有udev规则的就越少,因为它可能会导致我的数据最终出现在某人的设备上,或者出现在某人的数据中,或者恶意程序出现在我的设备上。换句话说,由于GNU系统提供了如此强大的功能,您的任务是谨慎使用它们的强大功能。如果你滥用它或粗心地使用它,你最终会遇到问题,而且很可能会导致严重的问题。现实中的Udev现在您可以确认您的脚本是由udev触发的,您可以将注意力转移到脚本功能上。到目前为止,该脚本是无用的,它只是记录脚本已经运行的事实。我使用udev来触发我的USB驱动器的自动备份。我的想法是在我的USB记忆棒上保留我正在处理的文档的主副本(因为我随身携带,所以我可以随时处理它)并拥有它,这些主文档将备份到我的电脑上。换句话说,我的电脑是备份驱动器,生成的数据是移动的。源代码可用,请随时查看附件代码以进一步限制您的udev测试示例。虽然这是我用udev最多的情况,udev可以捕获很多事件,比如gamepad(连接gamepad时,让系统加载xboxdrv模块),camera,microphone(连接指定麦克风时使用)设置输入),所以要知道它可以做的比这个例子多得多。我的备份系统的简化版本是一个由两个命令组成的过程:SUBSYSTEM="block",ATTRS{idVendor}="03f0",ACTION="add",SYMLINK+="safety%n"SUBSYSTEM=="block",ATTRS{idVendor}==”03f0”,ACTION==”add”,RUN+=”/usr/local/bin/trigger.sh”***使用属性检测我的U盘,这个前面有讨论,然后我在设备树中为我的U盘分配了一个符号链接,分配给它的符号链接是safety%n。%n是一个udev宏,它是内核分配给这个设备的任意数字,例如sdb1、sdb2、sdb3等。所以%n应该是1或2或3。这将在开发树中创建一个符号链接,所以它不会干扰插入设备的正常过程。这意味着如果你在自动挂载设备的桌面环境中使用它,就不会有任何问题。第二行运行脚本。我的备份脚本如下:#!/usr/bin/bashmount/dev/safety1/mnt/hdsleep2rsync-az/mnt/hd//home/seth/backups/&&umount/dev/safety1这个脚本使用符号链接,它会避免udev命名引起的意外情况(比如假设我的电脑上插了一个名为DISK的U盘,而我插的另一个U盘恰好名为DISK,那么第二个U盘的卷标就是名为DISK_,这会导致我的脚本无法正常运行),它将safety1(驱动器的第一个分区)挂载在我最喜欢的挂载点/mnt/hd上。安全安装后,它使用rsync将驱动器备份到我的备份文件夹(我实际使用的脚本使用rdiff-backup,但您可以使用您喜欢的任何自动备份解决方案)。udev让您控制您的设备udev是一个非常灵活的系统,它允许您以很少有其他系统敢于向用户提供的方式定义规则和功能。学习它,使用它,享受POSIX的强大功能。本文内容来自SlackermediaHandbook,该手册采用GNUFreeDocumentationLicense1.3授权。