Skip to content

fix(linux): stop the agent when the package is removed - #762

Open
AalmanSadath wants to merge 2 commits into
AprilNEA:masterfrom
AalmanSadath:fix/linux-stop-agent-on-removal
Open

fix(linux): stop the agent when the package is removed#762
AalmanSadath wants to merge 2 commits into
AprilNEA:masterfrom
AalmanSadath:fix/linux-stop-agent-on-removal

Conversation

@AalmanSadath

Copy link
Copy Markdown

Summary

Removing the .deb or .rpm deleted the binaries but left the background agent running, and left its user unit enabled so it returned on the next login. postremove.sh only reloaded udev rules.

A stranded agent isn't just untidy: it keeps HID++ sessions open on the same /dev/hidraw* nodes as whatever OpenLogi is running now, and those devices admit one owner at a time — the same contention the issue template's pre-flight checklist warns about for Logi Options+. Devices then go missing or come back misdetected, with nothing pointing at a package the user already removed. When the survivor belongs to the same install as the new client, it also keeps the singleton lock and the IPC socket.

packaging/linux/uninstall.sh has always done this correctly; only the packaged path was missing it.

Related: #673 is the same family on Windows (a leftover agent holding a lock the current client can't use), following #621/#644 for the overlay.

Changes

packaging/linux/nfpm-scripts/postremove.sh

  • Disable the user unit on removal. The agent is a per-user service while this script runs as root under the package manager, so there's no single session to address — walk /run/user/* and disable it for each logged-in user, mirroring the SUDO_USER + XDG_RUNTIME_DIR handling already in uninstall.sh. disable --now rather than stop: the unit is Restart=on-failure, and the agent may have written its own copy to $XDG_CONFIG_HOME/systemd/user/ for launch-at-login. Both share a unit name, so one disable covers whichever is active.
  • Kill a GUI-spawned agent, which systemd can't reach, matching strictly on executable path so a Flatpak, source build, or /usr/local install is left untouched.
  • Act only on removal. Both managers run this on upgrade too, spelled differently — dpkg passes remove/purge/upgrade, rpm passes the number of instances left behind. Without this, the fix would turn autostart off on every package update.

Testing

  • cargo xtask ci — 7 passed, 0 failed, 2 skipped. Not run: tests (macos) (wrong host OS), cargo-deny (not installed).
  • cargo xtask ci shell — shellcheck and shfmt clean.
  • Argument dispatch verified against all seven forms with stubbed systemctl/runuser/udevadm: 0, remove, purge stop the agent; 1, 2, upgrade, and empty leave it alone. udevadm still runs in all seven, unchanged from before.
  • Executable matcher verified to spare /app/bin/…, /usr/local/bin/…, target/release/… and the Flatpak deployment path, matching only /usr/bin/openlogi-agent and its (deleted) form.
  • Runtime-tested on hardware (Fedora, x86_64), package built with cargo xtask linux package:
    • Removal: install → systemctl --user enable --now openlogi-agent.service → dnf remove → agent gone, unit no longer enabled.
    • Upgrade: install → enable → dnf reinstall (drives %postun with $1=1, same as a version bump) → agent still running with the same PID, unit still enabled.
    • Bug reproduced on the current release: installing the official 0.7.4 rpm and removing it leaves the agent running.
  • Not tested: the .deb path (rpm only).

`postremove.sh` only reloaded udev rules, so removing the .deb or .rpm deleted
the binaries and left the agent running. The unit stayed enabled too, which
means it also came back on the next login.

A stranded agent is not merely untidy. It keeps HID++ sessions open on the same
/dev/hidraw* nodes as whatever OpenLogi the user is running now, and those
devices admit one owner at a time — the same contention the issue template's
pre-flight checklist warns about for Logi Options+. Devices then go missing or
come back misdetected, with nothing pointing at a package that is no longer
installed. When the survivor belongs to the same install as the new client it
also keeps the singleton lock and the IPC socket.

uninstall.sh has done this correctly all along; only the packaged path was
missing it. The awkward part is that the agent is a per-user service while this
script runs as root under the package manager, so there is no single session to
address. Walk /run/user instead and disable the unit for each logged-in user.
`disable --now` rather than `stop`, because the unit is Restart=on-failure and
the agent may have written its own copy to $XDG_CONFIG_HOME/systemd/user/ for
launch-at-login; both share a unit name, so one disable covers whichever is
active and drops the symlink that would restart it.

An agent the desktop app spawned is not under systemd at all, so that pass
cannot reach it. Match those on their executable path, which keeps a Flatpak,
a source build, or a /usr/local install untouched.

Both managers also run this on upgrade, spelled differently: dpkg passes
"remove"/"purge"/"upgrade", rpm passes the number of instances left behind. Act
only on the removal forms, so an update no longer silently turns autostart off.
@AalmanSadath
AalmanSadath requested a review from AprilNEA as a code owner August 21, 2026 16:12
@greptile-apps

greptile-apps Bot commented Aug 21, 2026

Copy link
Copy Markdown

Greptile Summary

The PR updates Linux package removal to disable active per-user agent units and terminate GUI-spawned packaged agents, while preserving agents during package upgrades.

  • Distinguishes final removal from Debian and RPM upgrade invocations.
  • Cleans up systemd user services for logged-in and lingering users.
  • Restricts direct process termination to agents running from the packaged /usr/bin path.
  • Continues reloading udev rules after package lifecycle operations.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains from the previous review findings.

Important Files Changed

Filename Overview
packaging/linux/nfpm-scripts/postremove.sh Adds removal-only cleanup for systemd-managed and GUI-spawned packaged agents; the two previously discussed enablement concerns are fixed or invalid at the current head.

Reviews (2): Last reviewed commit: "docs(linux): record what postremove deli..." | Re-trigger Greptile

Comment thread packaging/linux/nfpm-scripts/postremove.sh
Comment thread packaging/linux/nfpm-scripts/postremove.sh
Comment-only. Two points a reviewer raised, kept next to the code so the next
reader does not have to rediscover them.

Removing the unit file before this script runs does not defeat the disable:
systemd matches .wants symlinks by unit name rather than by reading [Install],
so a dangling symlink is still cleaned up.

A logged-out user without linger keeps a dangling symlink until the package is
reinstalled, and that is deliberate. Root has no route into their systemd
instance, and the standard tooling does not attempt one either, so the residue
is inert rather than worth chasing through home directories.
@davidbudnick davidbudnick added type: bug Something is broken or behaves incorrectly platform: linux Linux-specific issue labels Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

platform: linux Linux-specific issue type: bug Something is broken or behaves incorrectly

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants