mirror of
https://github.com/meshtastic/firmware.git
synced 2026-10-31 04:19:58 -04:00
A portduino node is a process on a computer that outlives it. shutdown() ends at exit(EXIT_SUCCESS), so "Shutdown" only stops the daemon -- and the shipped unit sets Restart=always, which makes it a restart in practice. There is no way from the node's UI to halt the machine it runs on. Add "Power Off Host" to the hidden test menu, behind its own confirmation. It is kept separate from shutdownMenu() because the two mean different things: one ends the node, the other ends the machine, and on a headless node nothing brings the host back. Confirming raises hostPowerOffRequested and then injects the ordinary INPUT_BROKER_SHUTDOWN, so the normal sequence still runs and the NodeDB, message store and waypoints are saved exactly as for any other shutdown. Only at the portduino arm does it hand off to logind, falling through to exit() if that is refused rather than claiming to shut down and sitting there. The call is org.freedesktop.login1.Manager.PowerOff with interactive=false: the daemon has no session and no way to answer a polkit prompt, so asking for one would hang until timeout. It opens its own bus connection rather than reusing the BLE backend's, which may already be torn down by then. meshtasticd runs unprivileged with no session, so logind's default of auth_admin_keep refuses it. bin/polkit-1/meshtasticd.rules grants the two power-off actions to that one user, shipped from both the deb and the rpm alongside the existing D-Bus policy. It deliberately does not grant power-off-ignore-inhibit, so a package upgrade or a held lock still blocks the halt; power-off-multiple-sessions is granted because logind escalates to it whenever anyone is logged in, which on a node someone has SSH'd into is the normal case. HAS_HOST_POWEROFF gets its own __has_include test rather than reusing HAS_BLUETOOTH: the two share a transport, not a purpose, and a build with Bluetooth off should still be able to halt the box. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
26 lines
1.3 KiB
Plaintext
26 lines
1.3 KiB
Plaintext
// Let the unprivileged meshtasticd service user halt the machine, so the node's
|
|
// "Power Off Host" action can take the computer down rather than only ending its own
|
|
// process (which, under Restart=always, systemd would immediately undo).
|
|
//
|
|
// logind's own policy defaults this to auth_admin_keep for anything without an active
|
|
// local session. meshtasticd is a system daemon with no session at all, so without a
|
|
// rule the call comes back NotAuthorized and the menu entry silently does nothing.
|
|
//
|
|
// Scope is deliberately narrow: one user, and only the power-off actions. In particular
|
|
// it does NOT grant power-off-ignore-inhibit, so a running inhibitor (a package upgrade,
|
|
// a user-held lock) still blocks the halt the way it would for anyone else. Reboot,
|
|
// suspend and hibernate are not granted either -- the node has no UI for them.
|
|
//
|
|
// power-off-multiple-sessions is included because logind escalates to that action when
|
|
// anyone else is logged in, which on a node someone has SSH'd into is the normal case,
|
|
// not the exception.
|
|
polkit.addRule(function (action, subject) {
|
|
if (subject.user !== "meshtasticd") {
|
|
return;
|
|
}
|
|
if (action.id === "org.freedesktop.login1.power-off" ||
|
|
action.id === "org.freedesktop.login1.power-off-multiple-sessions") {
|
|
return polkit.Result.YES;
|
|
}
|
|
});
|