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
90 lines
3.5 KiB
Bash
Executable File
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
|