udev 规则其实挺简单的,但第一次配置也颇费了一番工夫。
事情的起因是这样子的。我的手机,还有 Kindle Paperwhite,都能接电脑上提供一 USB 网络设备,可以用来 ssh 啊 rsync 啊什么的。但是呢,每次接好之后还要执行条命令设置 IP 地址,还要用 sudo、输入密码,很是麻烦。
我用来配置 IP 地址的命令是:
ifconfig usb0 192.168.42.1 # 手机 ifconfig usb0 192.168.15.1 # Kindle
查阅 udev(7) man 文档之后,对 udev 规则有了大概了解,知道大约要写成以下形式:
ACTION=="add", SUBSYSTEM=="net", XXX, RUN+="xxx"
需要一个属性来确定添加的设备是目标设备。插入设备,使用udevadm
命令来检查设备的各种属性:
udevadm info --attribute-walk /sys/class/net/usb0
本来准备用 MAC 地址的,但后来才发现我这 Android 手机每次的 MAC 地址都不一样。想到 adb 用的序列号,于是我决定用ATTRS{serial}=="BX90345MWH"
。然后轮到 Kindle 了。结果一看,竟然没有序列号属性了……但是它的 MAC 地址不会变,所以用 MAC 地址了。
写好规则之后可以先测试一下:
udevadm test /sys/class/net/usb0
配置正确的话会看到一行以run:
开头的行里写着自己定义的命令。
没问题就让 udevd 重新加载规则文件:
sudo udevadm control --reload-rules
到这里似乎就该结束了。可事与愿违,测试都没问题了,但 IP 地址就是没出现。查阅各处文档,也没做错什么呀。后来才注意到测试时上边有一行输出:
run: '/usr/lib/systemd/systemd-sysctl --prefix=/proc/sys/net/ipv4/conf/usb0 --prefix=/proc/sys/net/ipv4/neigh/usb0 --prefix=/proc/sys/net/ipv6/conf/usb0 --prefix=/proc/sys/net/ipv6/neigh/usb0'
它使用的是绝对路径!想起 systemd 的命令必须是绝对路径,我尝试改成绝对路径,果然可以了:
ACTION=="add", SUBSYSTEM=="net", ATTRS{serial}=="BX90345MWH", RUN+="/bin/ifconfig %k 192.168.42.1" ACTION=="add", SUBSYSTEM=="net", ATTR{address}=="ee:49:00:00:00:00" RUN+="/bin/ifconfig %k 192.168.15.1"