---
date: 2024-11-23
title: 与 udev 和 systemd 的搏斗
lastmod: 2024-12-06
tags: [Arch Linux, systemd]
---

……只为设置触控板手势。

今天尝试把自己从 `input` 组丢出去，然后发现 `libinput-gestrues` 不工作了。其实不工作的原因有两个方面：

- `libinput` 本身没有了读写 `/dev/input/eventX` 的权限（在非 root 下）
- 用于模拟键盘输入的 `ydotool` 没有了写入 `/dev/uinput` 的权限。

为了最小化权限，首先解决第一个问题。增加一个 `udev` 规则，给触摸板加一个 `uaccess` 的 TAG，然后 `sudo udevadm trigger` 就可以了：

``` udev
SUBSYSTEMS=="input", ENV{ID_INPUT_TOUCHPAD}=="1", MODE="0660", TAG+="uaccess"
```

根据 [Wiki](https://wiki.archlinux.org/title/Udev#Allowing_regular_users_to_use_devices)：

> The modern recommended approach for systemd systems is to use a `MODE` of `660` to let the group use the device, and then attach a `TAG` named [`uaccess`](https://github.com/systemd/systemd/blob/main/rules.d/70-uaccess.rules.in). This special tag makes udev apply a [dynamic user ACL](https://github.com/systemd/systemd/blob/main/src/udev/udev-builtin-uaccess.c) to the device node, which coordinates with [systemd-logind(8)](https://man.archlinux.org/man/systemd-logind.8) to make the device usable to logged-in users.

当然并没有看懂。

对于第二个问题，比较麻烦。`ydotool` 不能工作的原因是，他依赖于由用户单元启动的 `ydotoold` 守护进程，而后者作为用户单元自然没有写入 `/dev/uinput` 的权限（该路径的所有者是 `root:input`，见下文）。

尝试了官方源中的 [wtype](https://github.com/atx/wtype)，发现他依赖于 [virtual-keyboard-unstable-v1](https://wayland.app/protocols/virtual-keyboard-unstable-v1) 这个 Wayland Protocol，当然可以实现权限最小化。但很遗憾我在用的 KWin 并没有实现他……

还尝试了 AUR 中的 [dotool](https://git.sr.ht/~geb/dotool)，且不说 PKGBUILD 写的一团糟，把软件包自带的 udev 规则往 `/etc` 下面扔，而且他和 ydotool 的方案一样，写 udev 规则匹配这个设备然后加上 `OPTIONS+="static_node=uinput"`，所以还是要求我在 input 组里面。

这里先嘴一句 ydotool，要求用户在配置文件里写 keycode 而不是按键名称实在是太抽象了……

言归正传，我能想到的加固方式是，把 ydotoold 变成系统单元，然后加入 input 组并添加一大堆 systemd 的加固选项。

大家都知道（其实不知道），systemd 的文档又多又杂就像天书一样，尝试自己写一个系统单元加上这样的设置：

``` systemd
PrivateDevices=yes
DeviceAllow=/dev/uinput
```

单元里面 `/dev` 地下只有这些最基本的设备节点：

![assets/Pasted image 20241123233109.png](assets/139ca58e49250988db1e4fc4a34b1aa3b77222bd.png "wikilink")

如果改成：

``` systemd
DevicePolicy=closed
DeviceAllow=/dev/uinput
```

单元里 `/dev` 似乎什么都有（群友说能看见但其实不能访问，未证实）。遂放弃。

研究 systemd 从来都是耗费生命，然后开始怀疑自己有阅读障碍。

最后的解决方案是使用 cn 源的 ydotool-git，仙子在里面 ship 了一个 udev 规则给 uinput 打上了 `uaccess` 的 TAG，和上文一样。

那么问题来了，我为什么没想到呢？🥲

See:

- [ydotool](https://github.com/ReimuNotMoe/ydotool)
- [systemd.resource-control Device Access](https://www.freedesktop.org/software/systemd/man/latest/systemd.resource-control.html#Device%20Access)
- [systemd.exec PrivateDevices](https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#PrivateDevices=)
- [udev](https://www.freedesktop.org/software/systemd/man/latest/udev.html)
