Files
Gabriel Brown 2a716dac9e Fix correctness bugs across the helper scripts
panama-osd read the wrong brightnessctl field, showing the hardware
max instead of a percentage on any backlight device. panama-doctor
called three sibling scripts by bare name with nothing on PATH,
making three health checks permanently and falsely report broken; its
repair actions also reused the short probe timeout, so a slow-but-
successful restart was reported as failed. panama-wifi-qr left the
cleartext passphrase temp file behind on its failure path (the RETURN
trap doesn't fire on exit), and its nmcli parsing broke on connection
names containing a colon or backslash -- verified against a real
NetworkManager profile.

panama-power-profile's set command always returned success regardless
of whether the write actually took. panama-keyring's daemon-origin
check picked whichever gnome-keyring-daemon process happened to
enumerate first in /proc, defeating the exact dual-daemon scenario it
exists to detect; it now resolves the PID that actually owns the
Secret Service D-Bus name. gnf aborted before running a firmware
update whenever the metadata was already current (a non-error exit
under set -e), and its flatpak update lacked the -y its own docs
promise.

Claude-Session: https://claude.ai/code/session_01E6TJUAh41HaP25MVHWkhRZ
2026-08-18 21:23:28 -04:00

90 lines
3.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# System power profile, via the PowerProfiles D-Bus API.
#
# GNOME's Power panel offers Balanced / Performance / Power Saver; this is the
# same daemon behind it. On Fedora 44 the implementation is tuned-ppd rather
# than power-profiles-daemon, but it serves the same net.hadess.PowerProfiles
# interface, which is why this talks to the interface rather than to either
# binary -- powerprofilesctl is not even installed here.
#
# Setting a profile needs no privileges: the daemon accepts a property write
# from the active session user.
#
# Usage:
# panama-power-profile list -> {"profiles":[...],"active":"...","degraded":"..."}
# panama-power-profile set <name>
#
# PerformanceDegraded is reported because it is the one thing that makes the
# choice a lie: a thermally throttled laptop reports "performance" while
# behaving otherwise, and GNOME surfaces exactly this. It is an empty string
# when nothing is wrong.
set -uo pipefail
readonly BUS_NAME=net.hadess.PowerProfiles
readonly OBJECT=/net/hadess/PowerProfiles
emit_error() {
printf '{"profiles":[],"active":"","degraded":"","error":%s}\n' "$(jq -Rn --arg e "$1" '$e')"
exit 0
}
command -v busctl >/dev/null 2>&1 || emit_error 'busctl is not available'
property() {
busctl get-property "$BUS_NAME" "$OBJECT" "$BUS_NAME" "$1" 2>/dev/null
}
cmd_list() {
# A machine with no power-profiles daemon is a normal state -- plenty of
# desktops have none -- so it is reported rather than treated as a failure.
busctl status "$BUS_NAME" >/dev/null 2>&1 \
|| emit_error 'No power profile service is running. GNOME uses power-profiles-daemon; Fedora ships tuned-ppd.'
local active degraded profiles
active="$(property ActiveProfile | sed 's/^s //; s/"//g')"
degraded="$(property PerformanceDegraded | sed 's/^s //; s/"//g')"
# Profiles is an array of dicts, which busctl renders flat:
# v aa{sv} 3 2 "Profile" s "power-saver" "Driver" s "tuned" 2 "Profile" ...
# so each profile is the string following its own "Profile" marker. Matching
# the marker matters: "Driver" values sit in the same stream, and on this
# machine the driver is called "tuned", which a looser pattern happily
# reports as a fourth profile that does not exist.
profiles="$(property Profiles \
| grep -oE '"Profile" s "[a-z-]+"' \
| sed 's/.*s "//; s/"$//' \
| awk '!seen[$0]++')"
[[ -n "$profiles" ]] || emit_error 'The power profile service reported no profiles.'
jq -cn \
--arg active "$active" \
--arg degraded "$degraded" \
--argjson profiles "$(printf '%s\n' "$profiles" | jq -Rn '[inputs | select(length > 0)]')" \
'{profiles: $profiles, active: $active, degraded: $degraded, error: ""}'
}
cmd_set() {
local profile="${1:-}" status
# Constrained rather than passed through: this reaches a system service.
[[ "$profile" =~ ^[a-z-]+$ ]] || {
printf 'panama-power-profile: refusing a profile name with unexpected characters\n' >&2
return 2
}
# pipefail is set above, so $? here is busctl's real exit status, not
# head's -- a failed write (daemon stopped, profile rejected) must be
# reported rather than always claimed as a success.
busctl set-property "$BUS_NAME" "$OBJECT" "$BUS_NAME" ActiveProfile s "$profile" 2>&1 >/dev/null \
| head -2 >&2
status=$?
return "$status"
}
case "${1:-list}" in
list) cmd_list ;;
set) shift; cmd_set "${1:-}" ;;
*) printf 'usage: panama-power-profile [list|set <profile>]\n' >&2; exit 2 ;;
esac