luci-app-advanced-reboot: bugfix: actual partition switch

At some point after r7, when I no longer had the dual boot device readily
available for testing, a regression was introduced that the RPCD script
would not actually perform the partition switch.
Thanks to @bd0426 for report and @Jackie264 for fixing the issue.

advanced-reboot.js
* simplify partition number validation in handleAlternativeReboot
* reformat text copy

RPCD script
* obtain OpenWrt version from "$OPENWRT_RELEASE" not "$PRETTY_NAME" for
  the snapshot compatibility
* refactor parameter processing for boot_partition function
* add logging/better output on error in boot_partition

test.sh
* introduce a test file for heartbeat check of the RPCD script

Signed-off-by: Stan Grishin <stangri@melmac.ca>
This commit is contained in:
Stan Grishin
2026-01-21 03:31:28 +00:00
parent aca7cc1756
commit 6b271164d8
4 changed files with 85 additions and 74 deletions

View File

@@ -7,7 +7,7 @@ PKG_NAME:=luci-app-advanced-reboot
PKG_LICENSE:=AGPL-3.0-or-later
PKG_MAINTAINER:=Stan Grishin <stangri@melmac.ca>
PKG_VERSION:=1.1.1
PKG_RELEASE:=9
PKG_RELEASE:=15
PKG_BUILD_DEPENDS:=jq/host

View File

@@ -108,8 +108,8 @@ return view.extend({
E(
"p",
_(
'WARNING: Power off might result in a reboot on a device which doesn\'t support power off.<br /><br />\
Click "Proceed" below to power off your device.'
"WARNING: Power off might result in a reboot on a device which doesn't support power off.<br /><br />" +
"Click \"Proceed\" below to power off your device."
)
),
E("div", { class: "right" }, [
@@ -192,7 +192,9 @@ return view.extend({
"p",
{ class: "spinning" },
_(
"The system is rebooting to an alternative partition now.<br /> DO NOT POWER OFF THE DEVICE!<br /> Wait a few minutes before you try to reconnect. It might be necessary to renew the address of your computer to reach the device again, depending on your settings."
"The system is rebooting to an alternative partition now.<br /> DO NOT POWER OFF THE DEVICE!<br /> " +
"Wait a few minutes before you try to reconnect." +
" It might be necessary to renew the address of your computer to reach the device again, depending on your settings."
)
),
]);
@@ -216,23 +218,10 @@ return view.extend({
);
},
handleAlternativeReboot: function () {
// accept either (ev, number) or (number, ev)
var pn = null;
handleAlternativeReboot: function (number, ev) {
var pn = Number(number);
for (var i = 0; i < arguments.length; i++) {
var a = arguments[i];
if (typeof a === "number" && !Number.isNaN(a)) {
pn = a;
break;
}
if (typeof a === "string" && a !== "" && !Number.isNaN(Number(a))) {
pn = Number(a);
break;
}
}
if (pn == null) {
if (Number.isNaN(pn)) {
// fall back / safety
ui.addNotification(null, E("p", _("Missing partition number")));
return Promise.resolve();
@@ -247,12 +236,12 @@ return view.extend({
E(
"p",
_(
'WARNING: An alternative partition might have its own settings and completely different firmware.<br /><br />\
As your network configuration and WiFi SSID/password on alternative partition might be different,\
you might have to adjust your computer settings to be able to access your device once it reboots.<br /><br />\
Please also be aware that alternative partition firmware might not provide an easy way to switch active partition\
and boot back to the currently active partition.<br /><br />\
Click "Proceed" below to reboot device to the selected partition.'
"WARNING: An alternative partition might have its own settings and completely different firmware.<br /><br />" +
"As your network configuration and WiFi SSID/password on alternative partition might be different," +
" you might have to adjust your computer settings to be able to access your device once it reboots.<br /><br />" +
"Please also be aware that alternative partition firmware might not provide an easy way to switch active partition" +
" and boot back to the currently active partition.<br /><br />" +
"Click \"Proceed\" below to reboot device to the selected partition."
)
),
E("div", { class: "right" }, [
@@ -283,8 +272,8 @@ Click "Proceed" below to reboot device to the selected partition.'
typeof fn === "function"
? fn(a)
: _("Unexpected error: %s").format(
String(res.error)
);
String(res.error)
);
return ui.addNotification(null, E("p", msg));
}
@@ -395,18 +384,18 @@ Click "Proceed" below to reboot device to the selected partition.'
{ class: "alert-message warning" },
_(
"Warning: Device (%s) is unknown or isn't a dual-firmware device!" +
"%s" +
"If you are seeing this on an OpenWrt dual-firmware supported device," +
"%s" +
"please refer to " +
"%sHow to add a new device section of the README%s."
"%s" +
"If you are seeing this on an OpenWrt dual-firmware supported device," +
"%s" +
"please refer to " +
"%sHow to add a new device section of the README%s."
).format(
warnBoard,
"<br /><br />",
"<br />",
'<a href="' +
pkg.URL +
'#how-to-add-a-new-device" target="_blank">',
pkg.URL +
'#how-to-add-a-new-device" target="_blank">',
"</a>"
)
)
@@ -474,18 +463,18 @@ Click "Proceed" below to reboot device to the selected partition.'
body.appendChild(
poweroff_supported
? E(
"button",
{
class: "btn cbi-button cbi-button-apply important",
click: ui.createHandlerFn(this, "handlePowerOff"),
},
_("Perform power off...")
)
"button",
{
class: "btn cbi-button cbi-button-apply important",
click: ui.createHandlerFn(this, "handlePowerOff"),
},
_("Perform power off...")
)
: E(
"p",
{ class: "alert-message warning" },
_("Warning: This system does not support powering off!")
)
"p",
{ class: "alert-message warning" },
_("Warning: This system does not support powering off!")
)
);
return body;

View File

@@ -161,17 +161,9 @@ function get_volume_info(path) {
let pretty = command(
". " +
shellquote(root + "etc/os-release") +
' 2>/dev/null; echo "$PRETTY_NAME" 2>/dev/null'
' 2>/dev/null; echo "$OPENWRT_RELEASE" 2>/dev/null'
);
if (pretty) label = trim(pretty);
if (label && match(label, /SNAPSHOT/)) {
let rel = command(
'grep -m1 "^DISTRIB_RELEASE=" ' +
shellquote(root + "etc/openwrt_release") +
" 2>/dev/null | awk -F= '{gsub(/[\"'']/, \"\", $2); print $2}'"
);
if (rel) label = "OpenWrt " + trim(rel);
}
let kver = null;
if (root == "/") {
@@ -496,18 +488,31 @@ function obtain_device_info() {
* Accepts ubus args: { "number": "<partition-number>" }.
* Uses the device schema to map partition numbers to env values or dual-flag bytes.
*
* @param {{args:{number:String|Number}}} req
* @param {{number:String}} req
* @returns {Object} {} on success; {error:..., ...} on failure.
* @sideeffects Calls fw_setenv/fw_saveenv or writes to dual-flag MTD.
*/
function boot_partition(req) {
log("boot_partition req=" + sprintf("%J", req?.args));
/* extract target partition number from RPC args */
let number;
if (req && req.number != null) number = int(req.number);
if (!number)
let val;
if (type(req) == "array" && length(req) > 0)
val = req[0]?.number;
else if (type(req?.args) == "object")
val = req.args.number;
else if (type(req) == "object")
val = req.number;
if (val != null) val = "" + val;
if (val != null && match(val, /^[0-9]+$/))
number = int(val);
if (number == null)
return {
error: "INVALID_ARG",
detail: "number is required and must be numeric",
detail: "number is required and must be numeric (got: " + sprintf("%J", req?.args) + ")",
};
let board = get_board_name();
@@ -540,23 +545,32 @@ function boot_partition(req) {
for (let j = 0; j < length(params); j++) {
let param = params[j];
let value = target.param_values ? target.param_values[j] : null;
let rc = "0";
if (param == null || param == "") continue;
if (value == null) continue;
let rc = command(
setcmd +
" " +
shellquote(param) +
" " +
shellquote("" + value) +
" 2>/dev/null; echo $?"
);
if (rc != "0")
return {
error: "ERR_SET_ENV",
args: [param, "" + value],
rom_board_name: board,
};
if (savecmd) rc = command(savecmd + " 2>/dev/null; echo $?");
if (setcmd) {
let cmd = setcmd +
" " +
shellquote(param) +
" " +
shellquote("" + value) +
" 2>/dev/null; echo $?";
log("boot_partition running: " + cmd);
rc = command(cmd);
if (rc != "0")
return {
error: "ERR_SET_ENV",
args: [param, "" + value],
rom_board_name: board,
};
}
if (savecmd) {
let cmd = savecmd + " 2>/dev/null; echo $?";
log("boot_partition running: " + cmd);
rc = command(cmd);
}
if (rc != "0") return { error: "ERR_SAVE_ENV", rom_board_name: board };
}
} else {
@@ -564,6 +578,9 @@ function boot_partition(req) {
if (!df) return { error: "NO_DUAL_FLAG", rom_board_name: board };
if (!file_exists(df))
return { error: "NO_DUAL_FLAG_BLOCK", rom_board_name: board };
log("boot_partition setting dual flag: " + df + " to " + target.param_values[0]);
if (!write_dual_flag_value(df, target.param_values[0]))
return { error: "ERR_SET_DUAL_FLAG", args: [df], rom_board_name: board };
}

View File

@@ -0,0 +1,5 @@
#!/bin/sh
ubus -S call luci.advanced-reboot obtain_device_info | grep 'NO_BOARD_NAME_MATCH' && \
ubus -S call luci.advanced-reboot boot_partition '{ "number": "1" }' | grep 'NO_BOARD_NAME_MATCH' && \
ubus -S call luci.advanced-reboot boot_partition '{ "number": "2" }' | grep 'NO_BOARD_NAME_MATCH'