fix(linux): load uinput rather than rely on another daemon - #756
Open
AalmanSadath wants to merge 4 commits into
Open
fix(linux): load uinput rather than rely on another daemon#756AalmanSadath wants to merge 4 commits into
AalmanSadath wants to merge 4 commits into
Conversation
The packages ship 70-openlogi.rules, which grants /dev/uinput with TAG+="uaccess" — an ACL logind applies in response to a device event. A machine that has never loaded the uinput module has no such device, so there is nothing for postinstall's `udevadm trigger --attr-match=name=uinput` to match; it is a no-op, and its `|| true` hides that. OPTIONS+="static_node=uinput" does create the node, but a static node gets default permissions and no ACL: opening it would autoload the module, except opening is what the missing permission forbids. Nothing in the package breaks that cycle, so today it is broken by whatever else happens to open /dev/uinput first. On a typical desktop something does — bluetoothd opens it seconds after boot, and Steam and logiops do too — and OpenLogi works. Where nothing does, the agent starts, reports the device, battery and DPI normally over HID++, and button remapping silently never works, with only a journal warning to say so. systemd's own rules show the shape of the fix: snd/seq and snd/timer carry a real GROUP= in 50-udev-default.rules alongside TAG+="uaccess" in 70-uaccess.rules, precisely because uaccess cannot cover the pre-module node. Ship /etc/modules-load.d/openlogi.conf so the module loads from the next boot on, and modprobe it in postinstall so the session that installed the package works too. The config file is package content rather than something the script writes, so removing the package removes it. Verified on Fedora 44 against the released openlogi-v0.7.4-linux-amd64.rpm. With logiops and solaar removed, uinput unloaded and no stale ACL, installing the package leaves /dev/uinput at root:root 0600, and starting the agent as its own post-install message instructs fails with could not install OS input hook — error=Linux input error: Permission denied (os error 13) and creates no virtual input device. Applying this change to that same install restores "OS input hook installed" and the "OpenLogi virtual mouse" node. Reproduced independently on a second machine running the 0.7.3 package, with its mouse's event node confirmed readable first so the failure could only be the uinput side — same "Permission denied (os error 13)". In its untouched state that machine does not fail: bluetoothd had held /dev/uinput since 14 seconds after boot, so the module was loaded and the rules had already tagged it. That is the common case, and it is why this has gone unnoticed — the packages work by luck rather than by construction. Stopping bluetoothd and unloading the module reproduces what a machine with no such daemon looks like from a cold boot: the static node exists at root:root 0600 with no ACL, which is exactly the never-loaded state.
Greptile SummaryThe PR ensures Linux installations load
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| packaging/linux/install.sh | Installs the boot-time module configuration, loads uinput for the current session, and waits for queued udev events. |
| packaging/linux/modules-load/openlogi.conf | Adds the declarative boot-time request to load the uinput kernel module. |
| packaging/linux/nfpm-scripts/postinstall.sh | Loads uinput before retriggering udev rules during package installation. |
| packaging/linux/nfpm.yaml | Includes the new modules-load configuration in all Linux packages produced from the shared nfpm descriptor. |
| packaging/linux/nixos-module.nix | Uses the native NixOS kernel-module option to load uinput at boot. |
| packaging/linux/uninstall.sh | Removes the from-source modules-load configuration without unloading a potentially shared live module. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Linux installation] --> B{Installation path}
B -->|deb/rpm| C[Ship openlogi.conf]
B -->|From source| D[Install openlogi.conf]
B -->|NixOS module| E[Set boot.kernelModules]
C --> F[modprobe uinput during postinstall]
D --> G[modprobe uinput during install]
E --> H[Load uinput during boot]
F --> I[Trigger udev rules]
G --> I
H --> I
I --> J[Apply uaccess ACL]
J --> K[OpenLogi creates virtual input device]
Reviews (4): Last reviewed commit: "fix(linux): wait for udev in the from-so..." | Re-trigger Greptile
The previous commit fixed only the nfpm packages. install.sh and the NixOS module install the same udev rule and hit the same wall: TAG+="uaccess" grants /dev/uinput in response to a device event, and a host that has never loaded the module has no device for it to act on, so the node stays root-owned and the agent cannot create the virtual device button remapping needs. install.sh now installs /etc/modules-load.d/openlogi.conf and modprobes uinput, matching what the packages do. uninstall.sh removes the config again but leaves the module loaded, since other software may be relying on it by then. On NixOS /etc/modules-load.d is not the mechanism, so the module asks for the kernel module directly with boot.kernelModules. Raised in review: the fix worked for package installs while the documented alternative installers left the same hosts broken.
davidbudnick
previously approved these changes
Aug 21, 2026
install.sh reloaded the rules and fired the same three triggers as the package post-install, but returned without settling. `udevadm trigger` only queues the events, so the script could exit before udev had applied the uaccess ACLs, and the next thing the user does — start the agent — would still hit EACCES on a correctly configured system. postinstall.sh has always settled here for exactly that reason. This makes the two paths agree.
Author
|
Greptile flagged that The push dismissed your approval, so it would need re-approval. |
davidbudnick
approved these changes
Aug 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The Linux packages ship
70-openlogi.rules, which grants/dev/uinputwithTAG+="uaccess"— an ACL logind applies in response to a device event. On amachine that has never loaded the
uinputmodule there is no such device, sopostinstall'sudevadm trigger --attr-match=name=uinputmatches nothing. It isa no-op, and its
|| truehides that.OPTIONS+="static_node=uinput"does createthe node, but a static node gets default permissions and no ACL: opening it would
autoload the module, except opening is exactly what the missing permission forbids.
Nothing in the package breaks that cycle, so today it is broken by whatever else
happens to open
/dev/uinputfirst. On a typical desktop something does —bluetoothdopens it seconds after boot, and Steam and logiops do too — andOpenLogi works. Where nothing does, the agent starts, reports the device,
battery and DPI normally over HID++, and button remapping silently never works,
with only a journal warning to say so.
systemd's own rules show the shape of the fix:
snd/seqandsnd/timercarry areal
GROUP=in50-udev-default.rulesalongsideTAG+="uaccess"in70-uaccess.rules, precisely because uaccess cannot cover the pre-module node.Changes
packaging/linux/modules-load/openlogi.conf(new) — loadsuinputat boot.Package content rather than something the script writes, so uninstalling removes
it.
packaging/linux/nfpm.yaml— ships the above to/etc/modules-load.d/at0644.packaging/linux/nfpm-scripts/postinstall.sh—modprobe uinputbefore theudevadmblock, so the session that installed the package works too and notonly the next boot.
No Rust changes;
.deb,.rpmand.pkg.tar.zstall pick this up from theshared nfpm config.
Reproducing
Any machine, ~30 seconds. Unloading the module and dropping the ACL leaves the
static node at
root:root 0600with no ACL — byte-for-byte the state anever-loaded machine boots into.
Before this change:
openlogi liststill shows the mouse and its battery throughout, which is whatmakes this easy to miss.
Restore with
sudo systemctl start bluetooth && sudo modprobe uinput && sudo udevadm trigger.Testing
Fedora 44, x86_64, on real hardware (MX Master 3S over Bluetooth).
Bug reproduced on two machines, both running released packages, neither with
this change:
openlogi-v0.7.4-linux-amd64.rpm, with logiops and Solaar removedconfirmed readable first so the failure could only be the uinput side
Both produced
Permission denied (os error 13)and created no virtual inputdevice. In its untouched state the second machine does not fail —
bluetoothdhad held
/dev/uinputsince 14 s after boot.Fix verified as shipped, not just by hand:
The
.debwas checked the same way (ar p … data.tar.gz | tar tzf -) and carriesboth the config file and the
modprobeline.CI:
cargo xtask ci # 7 passed, 0 failed, 2 skippedIncludes the
shelljob (shellcheck+shfmt -d), which gatespostinstall.sh. Not run:tests (macos)(wrong host) andcargo-deny(not installed locally) — neither is affected by a packaging-only change, but
neither was executed.