利用udev规则进行一些自动化操作
什么是udev规则
udev 是 Linux 中的一个用户空间设备管理器 (userspace device manager),用于动态管理设备节点和设备事件。
下文,我们将以打印机使用场景进行简单的讲解演示,亦可用于其他功能。
场景环境与触发逻辑
环境:飞牛nas中新建了win10虚拟机,并设置打印机硬件直通。
逻辑:当打印机被开启/关闭时,利用规则联动脚本操作虚拟机的开启或关闭
注:我的打印机比较老旧,没有联网功能也没有linux驱动,因此cups无法正常使用
开始实操
1、查看虚拟机名称
使用 sudo virsh list --all
命令,会得到如下输出
cming@EWEDL:~$ sudo virsh list --all
Id Name State
---------------------------
3 tangjq53 running
- u5wohjw8 shut off
其中name列即为虚拟机名称,可以根据虚拟机状态进行确定,我这里需要控制的是“u5wohjw8”
2、查看需要监测的设备信息
此处建议直接使用命令 lsusb
进行查看。
3、编写自动化脚本
主要用于udev调用,当需要开机时调用start部份,需要关机时调用stop部份。
#!/bin/bash
echo "脚本已被udev调用,参数:$1" >> /tmp/udev_printer_debug.log
# 自动获取脚本所在目录
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
LOG_FILE="$SCRIPT_DIR/printer_vm_control.log"
# 配置虚拟机名称
VM_NAME="u5wohjw8"
# 获取当前时间
TIME_NOW=$(date "+%Y-%m-%d %H:%M:%S")
# 日志函数
lo**essage() {
echo "$TIME_NOW [$ACTION] $1" >> "$LOG_FILE"
}
# 获取操作类型
ACTION="$1"
# 启动虚拟机
start_vm() {
virsh start "$VM_NAME" >> "$LOG_FILE" 2>&1
if [ $? -eq 0 ]; then
lo**essage "✅ 已启动虚拟机: $VM_NAME"
else
lo**essage "❌ 启动虚拟机失败: $VM_NAME"
fi
}
# 关闭虚拟机
stop_vm() {
virsh shutdown "$VM_NAME" >> "$LOG_FILE" 2>&1
local try=0
local max_try=5
local sleep_time=3
while [ $try -lt $max_try ]; do
sleep $sleep_time
VM_STATE=$(virsh domstate "$VM_NAME" 2>/dev/null)
if [[ "$VM_STATE" == "shut off" ]]; then
lo**essage "🛑 已关闭虚拟机: $VM_NAME"
return 0
fi
try=$((try+1))
lo**essage "⚠️ 第$try次检测,虚拟机仍未关闭: $VM_NAME,状态: $VM_STATE"
done
# 如果多次尝试后仍未关闭,可以选择强制关闭
virsh destroy "$VM_NAME" >> "$LOG_FILE" 2>&1
VM_STATE=$(virsh domstate "$VM_NAME" 2>/dev/null)
if [[ "$VM_STATE" == "shut off" ]]; then
lo**essage "❗多次尝试后已强制关闭虚拟机: $VM_NAME"
else
lo**essage "❌ 强制关闭虚拟机失败: $VM_NAME,当前状态: $VM_STATE"
fi
}
# 主逻辑
case "$ACTION" in
start)
VM_STATE=$(virsh domstate "$VM_NAME" 2>/dev/null)
if [[ "$VM_STATE" == "shut off" ]]; then
start_vm
elif [[ "$VM_STATE" == "running" ]]; then
lo**essage "🔵 虚拟机已运行,无需操作"
else
lo**essage "❓ 虚拟机状态未知: $VM_STATE"
fi
;;
stop)
VM_STATE=$(virsh domstate "$VM_NAME" 2>/dev/null)
if [[ "$VM_STATE" == "running" ]]; then
stop_vm
else
lo**essage "🟢 虚拟机未运行,无需关闭"
fi
;;
*)
lo**essage "🚫 未知操作: $ACTION"
;;
esac
保存到想要存放的位置,记得chmod一下使其可执行!随后我们便可以将设备直通给虚拟机了。
4、创建udev规则,需要注意的是,移除设备后ID便不存在了,此时只能使用PRODUCT去做判定,不能直接采用插入事件的写法去监测,我们需要将文件进行规范命名,此处我命名为99-konica-printer.rules,我们需要将此文件保存到/etc/udev/rules.d/下
# 插入事件
ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_VENDOR_ID}=="132b", ENV{ID_MODEL_ID}=="20a3", ENV{PATH}="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", RUN+="/bin/sh -c '/vol1/1000/config/printer.sh start >> /tmp/udev_printer_debug.log 2>&1'"
# 拔出事件
ACTION=="remove", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="132b/20a3/100", ENV{PATH}="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", RUN+="/bin/sh -c '/vol1/1000/config/printer.sh stop >> /tmp/udev_printer_debug.log 2>&1'"
5、效果展示

总结
本文主要介绍如何利用udev规则配合脚本,来实现设备状态的监控并执行所需要的后续操作。文中的脚本为AI编写,存在一些不必要的内容,请不要照抄。本文更多的是提供一种联动思路,具体使用场景可以发挥各自脑洞去尝试。
另外,udev规则可以视为默认使用root权限运行,因此不用担心因脚本权限不足而造成无法正常运行的问题。