feat(power): configurable power button behavior + rename Power Mode → Power Options (OS-463)#2671
feat(power): configurable power button behavior + rename Power Mode → Power Options (OS-463)#2671elibosley wants to merge 6 commits into
Conversation
WalkthroughAdds configurable physical power-button behavior with shutdown, reboot, ignore, and plugin-defined actions. The ACPI and elogind integration routes events through the new handler. A WebUI page exposes the setting. The Power Options menu now includes a separate CPU governor configuration page. ChangesPhysical Power Button Behavior
Power Options Menu Reorganization
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Browser
participant update.php
participant dynamix.cfg
participant acpid
participant unraid_power_handler
participant init
Browser->>update.php: Submit selected powerbutton action
update.php->>dynamix.cfg: Write configured action
acpid->>unraid_power_handler: Dispatch button/power event
unraid_power_handler->>dynamix.cfg: Read current action
alt shutdown or reboot
unraid_power_handler->>init: Invoke clean shutdown or reboot
else ignore
unraid_power_handler->>unraid_power_handler: Log event
else plugin action
unraid_power_handler->>unraid_power_handler: Execute configured extension
end
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🔧 PR Test Plugin AvailableA test plugin has been generated for this PR that includes the modified files. Version: 📥 Installation Instructions:Install via Unraid Web UI:
Alternative: Direct Download
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@emhttp/plugins/dynamix/PowerModeCpu.page`:
- Around line 38-40: The jQuery selector `$(this).next('span')` in the disabled
radio button check loop is not finding the correct elements because radio inputs
are not directly followed by span siblings, but rather by text nodes or
differently structured elements. Inspect the actual HTML structure around the
radio inputs to determine what element actually follows them, then update the
traversal method in the loop (replacing `.next('span')`) to correctly locate the
element that should receive the unavailable label text. This may require using a
different jQuery method like .closest(), .parent(), or .find() depending on the
actual DOM hierarchy.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 14608339-fb32-4abb-a61e-ba54b9d0fe05
📒 Files selected for processing (6)
emhttp/languages/en_US/helptext.txtemhttp/plugins/dynamix/PowerButton.pageemhttp/plugins/dynamix/PowerMode.pageemhttp/plugins/dynamix/PowerModeCpu.pageetc/acpi/unraid_power_handler.shetc/rc.d/rc.acpid
| $('input[type=radio]').each(function(){ | ||
| if ($(this).prop('disabled')) $(this).next('span').html(" <i>(_(unavailable)_)</i>"); | ||
| }); |
There was a problem hiding this comment.
Unavailable-label injection currently never matches the DOM.
At Line 39, $(this).next('span') does not find anything because the radio inputs are followed by text nodes, not <span> siblings. As written, disabled options won’t get the “unavailable” note.
Suggested fix
$(function(){
$('input[type=radio]').each(function(){
- if ($(this).prop('disabled')) $(this).next('span').html(" <i>(_(unavailable)_)</i>");
+ if ($(this).prop('disabled')) {
+ $(this).after(" <i>(_(unavailable)_)</i>");
+ }
});
<?if (exec("dmesg | grep -Pom1 'Hypervisor detected'")):?>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| $('input[type=radio]').each(function(){ | |
| if ($(this).prop('disabled')) $(this).next('span').html(" <i>(_(unavailable)_)</i>"); | |
| }); | |
| $(function(){ | |
| $('input[type=radio]').each(function(){ | |
| if ($(this).prop('disabled')) { | |
| $(this).after(" <i>(_(unavailable)_)</i>"); | |
| } | |
| }); | |
| <?if (exec("dmesg | grep -Pom1 'Hypervisor detected'")):?> |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@emhttp/plugins/dynamix/PowerModeCpu.page` around lines 38 - 40, The jQuery
selector `$(this).next('span')` in the disabled radio button check loop is not
finding the correct elements because radio inputs are not directly followed by
span siblings, but rather by text nodes or differently structured elements.
Inspect the actual HTML structure around the radio inputs to determine what
element actually follows them, then update the traversal method in the loop
(replacing `.next('span')`) to correctly locate the element that should receive
the unavailable label text. This may require using a different jQuery method
like .closest(), .parent(), or .find() depending on the actual DOM hierarchy.
|
Update — hardware testing on devgen.local revealed a second handler. The power button generates two events: an ACPI event (acpid → Added Note for reviewers: the new |
|
Update — added more actions + a plugin extension point (commit Power Button options are now: Shut down (default), Reboot, Sleep (suspend) (shown only when the kernel reports suspend-to-RAM support), and Do nothing. Rather than baking plugin-specific actions into core, the power button is now extensible so plugins add their own actions in their own repos:
This is the mechanism the User Scripts plugin would use to add a "Run script" action — intentionally left to that plugin rather than coupled into core. Verified on devgen.local: all four handler branches (shutdown/reboot/sleep/ignore) dispatch correctly, the |
|
Update — Sleep is now plugin-provided, not a core option (commit Dropped the built-in Sleep option and its generic Core now offers only the trivially-safe primitives: Shut down, Reboot, Do nothing. Sleep is added by the S3 Sleep plugin via the same extension hook as any other plugin action ( |
Rename the "Power Mode" settings page to "Power Options" and turn it into a tabbed page with two tabs: - Power Mode - the existing CPU governor controls (moved verbatim) - Power Button - new setting to choose what the physical power button does The power button behavior (Shut down / Do nothing) is stored in the [powermode] section of dynamix.cfg and read live by the ACPI handler on each press, so changes take effect without a reload or reboot. A setting-aware ACPI handler (etc/acpi/unraid_power_handler.sh) is installed over the stock Slackware acpi_handler.sh at boot by rc.acpid, so it reliably overrides the default poweroff regardless of package install order. This mirrors how rc.cpufreq applies the [powermode] governor setting at boot. Closes OS-463 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A physical power press fires both an ACPI event (handled by acpid) and an input key event handled by elogind, whose default HandlePowerKey=poweroff shuts the system down regardless of the acpid handler. Ship a logind.conf.d drop-in setting HandlePowerKey/HandlePowerKeyLongPress to ignore so acpid is the sole authority over the power button, making the "Do nothing" Power Options setting actually take effect. Verified on hardware: elogind D-Bus HandlePowerKey now reports "ignore". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Power Button now offers Shut down, Reboot, Sleep (suspend, shown only when the kernel supports suspend-to-RAM), and Do nothing. Plugins can add or override actions without touching core: - WebUI: PowerButton.page includes plugins/*/include/powerbutton-option.php (and powerbutton-extra.php for action-specific fields). - Action: unraid_power_handler.sh dispatches to /etc/acpi/powerbutton.d/<action> for non-builtin actions, and the builtin "sleep" defers to powerbutton.d/sleep when present (so the S3 Sleep plugin can do array-aware prep). Contract documented in /etc/acpi/powerbutton.d/README. This lets the User Scripts plugin add a "Run script" action in its own repo rather than coupling it into core. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the built-in Sleep option and its generic echo-mem suspend. A core suspend bypasses the array/Docker/VM/wake prep the S3 Sleep plugin performs and is hardware-fragile, and Unraid intentionally ships S3 sleep as a plugin. Core now offers only the trivially-safe primitives (Shut down, Reboot, Do nothing). Sleep is added by the S3 Sleep plugin via the same extension hook used for other plugin actions: it ships /etc/acpi/powerbutton.d/sleep and a powerbutton-option.php fragment. The handler already routes powerbutton="sleep" through the plugin dir. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
b232893 to
1e7413b
Compare
…rop shared-file edits - Save mode is now much faster: pipe the single-pass streaming zip (scripts/flash_backup) into the destination file instead of appending each top-level item to a growing archive (one zip invocation vs many). - On completion the save job raises an Unraid notification (the tray bell) with a click-to-download link, exposes the saved file for download via a docroot symlink, and the GUI shows a Download button next to the saved path. - Revert the helptext.txt and .gitignore edits to base so this PR touches only its own files. helptext.txt was the single file shared with other in-flight PR test plugins (#2671, #2673), which made the stacked PR-plugin patch fail to apply; with it gone, #2677 stacks cleanly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
QA (jorgeb) failed PR 2671. Fixes: - Preview-plugin activation: the PR test plugin patches /etc late (after rc.M started acpid/elogind with the stock config) and re-applies every boot, so the new ACPI handler + elogind power-key drop-in never took effect and "Do nothing" still shut the server down. generate-pr-plugin.sh now restarts acpid/elogind when the patch touches their files. (A real release bakes these into bzroot, so its boot ordering is already correct.) - Force tabbed rendering of Power Options (Tabs="true") so Power Mode and Power Button show as tabs instead of stacked sections. - Let the "no available power modes" notice grow (height:auto) so it no longer overflows and overlaps the Power Button heading at 390px. - Debounce duplicate power-button ACPI events so a doubled event is not logged (or acted on) twice.
…r-options # Conflicts: # .github/scripts/generate-pr-plugin.sh
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
etc/acpi/unraid_power_handler.sh (1)
43-46: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winConsider a timeout around plugin action invocation.
"$PLUGIN_DIR/$behavior"runs synchronously with no bound on execution time. A wedged or misbehaving plugin handler (e.g. a Sleep plugin stuck on array-quiesce prep) would stall this handler indefinitely, delaying/losing subsequent power-button events depending on acpid's dispatch model.♻️ Suggested guard
logger -t acpid "Power button: running plugin action '$behavior'" - "$PLUGIN_DIR/$behavior" + timeout 30 "$PLUGIN_DIR/$behavior"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@etc/acpi/unraid_power_handler.sh` around lines 43 - 46, Wrap the plugin action invocation in the power-button handler with a bounded timeout so a wedged executable cannot block event processing indefinitely. Preserve the existing executable check, logging, and plugin arguments while applying the timeout specifically to "$PLUGIN_DIR/$behavior".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/scripts/generate-pr-plugin.sh:
- Around line 283-295: Update the elogind handling block in the payload-change
logic to avoid invoking `/etc/rc.d/rc.elogind restart`, which can terminate
active sessions. Use the supported non-disruptive reload mechanism, or defer
elogind configuration changes until reboot; leave the separate acpid restart
behavior unchanged.
In `@etc/acpi/unraid_power_handler.sh`:
- Around line 41-49: Update the unknown-action fallback in run_powerbutton so
non-empty values that match neither a built-in action nor an executable plugin
invoke the documented shutdown behavior instead of being ignored. Preserve the
plugin execution path for valid executable handlers and retain shutdown handling
for unset values.
- Around line 41-49: Validate the config-derived behavior value before using it
in the plugin path within the wildcard action branch: accept only a simple
executable name with no slash or path traversal components, and ignore invalid
values. Keep the existing executable check, logging, and invocation behavior for
validated plugin names, using the behavior handling in the power-button case as
the change point.
---
Nitpick comments:
In `@etc/acpi/unraid_power_handler.sh`:
- Around line 43-46: Wrap the plugin action invocation in the power-button
handler with a bounded timeout so a wedged executable cannot block event
processing indefinitely. Preserve the existing executable check, logging, and
plugin arguments while applying the timeout specifically to
"$PLUGIN_DIR/$behavior".
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 1e8c5336-c9a0-4852-b50f-70dc985a4369
📒 Files selected for processing (9)
.github/scripts/generate-pr-plugin.shemhttp/languages/en_US/helptext.txtemhttp/plugins/dynamix/PowerButton.pageemhttp/plugins/dynamix/PowerMode.pageemhttp/plugins/dynamix/PowerModeCpu.pageetc/acpi/powerbutton.d/READMEetc/acpi/unraid_power_handler.shetc/elogind/logind.conf.d/20-unraid-powerbutton.confetc/rc.d/rc.acpid
🚧 Files skipped from review as they are similar to previous changes (5)
- emhttp/plugins/dynamix/PowerMode.page
- emhttp/languages/en_US/helptext.txt
- emhttp/plugins/dynamix/PowerButton.page
- etc/rc.d/rc.acpid
- emhttp/plugins/dynamix/PowerModeCpu.page
| if [ -s "$PAYLOAD/text_files.txt" ]; then | ||
| # elogind owns the physical power key unless a drop-in tells it to ignore it; | ||
| # it only reads logind.conf.d/ at startup, so reload it when that changes. | ||
| if grep -qE 'etc/elogind/|rc\.d/rc\.elogind$' "$PAYLOAD/text_files.txt" && [ -x /etc/rc.d/rc.elogind ]; then | ||
| echo "Reloading elogind (session/power-key policy changed)..." | ||
| /etc/rc.d/rc.elogind restart >/dev/null 2>&1 || true | ||
| fi | ||
| # rc.acpid installs Unraid's ACPI handler over the stock one at (re)start. | ||
| if grep -qE 'etc/acpi/|rc\.d/rc\.acpid$' "$PAYLOAD/text_files.txt" && [ -x /etc/rc.d/rc.acpid ]; then | ||
| echo "Restarting acpid (ACPI handler changed)..." | ||
| /etc/rc.d/rc.acpid restart >/dev/null 2>&1 || true | ||
| fi | ||
| fi |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
does restarting elogind service terminate active login sessions
💡 Result:
Yes, restarting the elogind service typically causes the loss of all existing login sessions [1]. Elogind acts as a system daemon that manages user logins, tracks sessions, and maintains seat information [2][3]. When the service is restarted via the standard service manager, it generally triggers a stop operation that cleans up these sessions and seats, effectively terminating them [1][2]. Key technical considerations include: - Session Data Loss: Restarting the elogind service often results in the system failing to recognize previously active sessions, causing them to be considered stale or lost [4][5]. - Preferred Alternatives: To refresh configuration changes without terminating sessions, the command loginctl reload is recommended instead of restarting the service [1]. - Potential for Instability: Even if session processes (like the desktop environment or user shells) continue to run, the loss of elogind's tracking information can lead to various issues, such as failure to access system resources (e.g., audio, removable media) or improper handling of power management and shutdown requests [1][4][6][7]. In some specialized configurations, users may attempt to work around this by using specific signals to prevent the daemon from clearing session data upon exit, though this is generally discouraged and may not reliably preserve all session functionality across different distributions and software environments [4][6][2].
Citations:
- 1: https://wiki.gentoo.org/wiki/Elogind/en
- 2: https://man.voidlinux.org/elogind.8
- 3: https://manpages.debian.org/unstable/elogind/elogind.8.en.html
- 4: Session lost when elogind restarted elogind/elogind#104
- 5: https://lists.snapcraft.io/archives/foundations-bugs/2021-September/461520.html
- 6: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916247
- 7: Restarting elogind causes SDDM to kill the user session elogind/elogind#110
🏁 Script executed:
#!/bin/bash
set -euo pipefail
git ls-files '.github/scripts/generate-pr-plugin.sh' 'README.md' 2>/dev/null || true
wc -l .github/scripts/generate-pr-plugin.sh
sed -n '260,310p' .github/scripts/generate-pr-plugin.sh
rg -n "elogind|loginctl reload|rc\.elogind" .github/scripts README.md .github -S || trueRepository: unraid/webgui
Length of output: 4019
Avoid restarting elogind live This restarts elogind and can drop active login sessions; use a non-disruptive reload path or defer the change until reboot.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/scripts/generate-pr-plugin.sh around lines 283 - 295, Update the
elogind handling block in the payload-change logic to avoid invoking
`/etc/rc.d/rc.elogind restart`, which can terminate active sessions. Use the
supported non-disruptive reload mechanism, or defer elogind configuration
changes until reboot; leave the separate acpid restart behavior unchanged.
| *) | ||
| # Extension point: plugin-provided action handler. | ||
| if [[ -n $behavior && -x $PLUGIN_DIR/$behavior ]]; then | ||
| logger -t acpid "Power button: running plugin action '$behavior'" | ||
| "$PLUGIN_DIR/$behavior" | ||
| else | ||
| logger -t acpid "Power button: unknown action '$behavior', ignoring" | ||
| fi | ||
| ;; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Unexpected config values don't fall back to shutdown, contradicting the documented default.
The PR spec states the power button "defaults to shutdown for unset or unexpected values," but this code only defaults to shutdown when behavior is empty (${behavior:-shutdown} at line 68). Once inside run_powerbutton, a non-empty value that matches no built-in and has no executable under $PLUGIN_DIR falls into the *) branch and merely logs "unknown action ... ignoring" — the button silently does nothing instead of shutting down. A corrupted or stale dynamix.cfg value (e.g. from a removed plugin) would leave the physical power button unresponsive.
🔧 Proposed fix
else
- logger -t acpid "Power button: unknown action '$behavior', ignoring"
+ logger -t acpid "Power button: unknown action '$behavior', defaulting to shutdown"
+ /sbin/init 0
fi📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| *) | |
| # Extension point: plugin-provided action handler. | |
| if [[ -n $behavior && -x $PLUGIN_DIR/$behavior ]]; then | |
| logger -t acpid "Power button: running plugin action '$behavior'" | |
| "$PLUGIN_DIR/$behavior" | |
| else | |
| logger -t acpid "Power button: unknown action '$behavior', ignoring" | |
| fi | |
| ;; | |
| *) | |
| # Extension point: plugin-provided action handler. | |
| if [[ -n $behavior && -x $PLUGIN_DIR/$behavior ]]; then | |
| logger -t acpid "Power button: running plugin action '$behavior'" | |
| "$PLUGIN_DIR/$behavior" | |
| else | |
| logger -t acpid "Power button: unknown action '$behavior', defaulting to shutdown" | |
| /sbin/init 0 | |
| fi | |
| ;; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@etc/acpi/unraid_power_handler.sh` around lines 41 - 49, Update the
unknown-action fallback in run_powerbutton so non-empty values that match
neither a built-in action nor an executable plugin invoke the documented
shutdown behavior instead of being ignored. Preserve the plugin execution path
for valid executable handlers and retain shutdown handling for unset values.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Unsanitized config value used as a path component enables path traversal.
$behavior comes straight from dynamix.cfg (line 67) and is concatenated into $PLUGIN_DIR/$behavior with only an -x existence check — no validation that it excludes /. A value like powerbutton="../../../some/other/executable" would pass the -x check and get executed by root on every power-button press, reaching outside the intended /etc/acpi/powerbutton.d/ extension point. PowerButton.page's client-side validation isn't visible in this batch, so the handler shouldn't rely on it being the only guard.
🔒 Proposed fix
*)
# Extension point: plugin-provided action handler.
- if [[ -n $behavior && -x $PLUGIN_DIR/$behavior ]]; then
+ if [[ -n $behavior && $behavior != */* && -x $PLUGIN_DIR/$behavior ]]; then📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| *) | |
| # Extension point: plugin-provided action handler. | |
| if [[ -n $behavior && -x $PLUGIN_DIR/$behavior ]]; then | |
| logger -t acpid "Power button: running plugin action '$behavior'" | |
| "$PLUGIN_DIR/$behavior" | |
| else | |
| logger -t acpid "Power button: unknown action '$behavior', ignoring" | |
| fi | |
| ;; | |
| *) | |
| # Extension point: plugin-provided action handler. | |
| if [[ -n $behavior && $behavior != */* && -x $PLUGIN_DIR/$behavior ]]; then | |
| logger -t acpid "Power button: running plugin action '$behavior'" | |
| "$PLUGIN_DIR/$behavior" | |
| else | |
| logger -t acpid "Power button: unknown action '$behavior', ignoring" | |
| fi | |
| ;; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@etc/acpi/unraid_power_handler.sh` around lines 41 - 49, Validate the
config-derived behavior value before using it in the plugin path within the
wildcard action branch: accept only a simple executable name with no slash or
path traversal components, and ignore invalid values. Keep the existing
executable check, logging, and invocation behavior for validated plugin names,
using the behavior handling in the power-button case as the change point.
Summary
Implements OS-463: a native WebUI setting to control what the physical power button does, so an accidental bump on small-form-factor hardware (NUCs, etc.) no longer forces a shutdown.
The existing Power Mode settings page is renamed to Power Options and split into two tabs:
Power Button actions
Core ships only the trivially-safe primitives:
/sbin/init 0) — preserves today's behavior/sbin/init 6)The choice is saved to
[powermode] powerbutton=indynamix.cfg(on the flash, so it persists) and read live on each press, so changes take effect with no reload or reboot. Unset/unexpected values fall back to Shut down.Two handlers, both neutralized
Hardware testing surfaced that a single power press fires two independent events:
/etc/acpi/acpi_handler.sh. We install our setting-aware handler over the stock Slackware one at boot viarc.acpid(acpid_configure), so it wins regardless of package install order — mirroring howrc.cpufreqapplies the[powermode]governor at boot.Power Buttoninput device (PNP0C0C); its defaultHandlePowerKey=poweroffshut the box down regardless of acpid. A shippedlogind.conf.ddrop-in setsHandlePowerKey=ignore, making acpid the sole authority.Both were verified on real hardware (elogind D-Bus
HandlePowerKeynow reportsignore).Plugin extension hook
Actions that need their own setup or are hardware-fragile (suspend, running a script) are not baked into core. Instead the power button is extensible so plugins add actions in their own repos:
PowerButton.pageincludesplugins/*/include/powerbutton-option.php(andpowerbutton-extra.phpfor action-specific fields).unraid_power_handler.shdispatches any non-builtin action to/etc/acpi/powerbutton.d/<action>.etc/acpi/powerbutton.d/README.Follow-up work to wire the first two consumers (tracked as sub-tasks of OS-463):
Files
emhttp/plugins/dynamix/PowerMode.page/Settings/PowerModeURLs still work)emhttp/plugins/dynamix/PowerModeCpu.pageemhttp/plugins/dynamix/PowerButton.pageetc/acpi/unraid_power_handler.shetc/acpi/powerbutton.d/READMEetc/rc.d/rc.acpidpowerbutton.d/at bootetc/elogind/logind.conf.d/20-unraid-powerbutton.confemhttp/languages/en_US/helptext.txtTesting
bash -nclean on the handler andrc.acpid;php -lclean on both page bodies.Notes for reviewers
etc/*files (acpi, elogind, rc.acpid) reach a system via the package build, not thedeploy_to_unraid.shdev script (which only syncsemhttp/).Summary by CodeRabbit