luci-app-advanced-reboot: bugfix: actual partition switch
authorStan Grishin <stangri@melmac.ca>
Wed, 21 Jan 2026 03:31:28 +0000 (03:31 +0000)
committerStan Grishin <stangri@melmac.ca>
Wed, 21 Jan 2026 03:31:36 +0000 (03:31 +0000)
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>
applications/luci-app-advanced-reboot/Makefile
applications/luci-app-advanced-reboot/htdocs/luci-static/resources/view/system/advanced-reboot.js
applications/luci-app-advanced-reboot/root/usr/share/rpcd/ucode/luci.advanced-reboot
applications/luci-app-advanced-reboot/test.sh [new file with mode: 0644]

index 30ac0c145850e071fb72890750c56b907bfd9e8c..606e2d969b28c6f766d747f5bf9bf5692410758d 100644 (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
 
index 51c09af70d317a01a98d0d6c4d5d34172ca98d39..2351bf15d750896ea89e7cb50551cb46f9657f39 100644 (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;
index 10673dee67220321d8da11fd9d4515d8083d09d9..5c316ec69b513a1e896fe18b968f3428048db369 100644 (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 };
        }
diff --git a/applications/luci-app-advanced-reboot/test.sh b/applications/luci-app-advanced-reboot/test.sh
new file mode 100644 (file)
index 0000000..273eeb8
--- /dev/null
@@ -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'