luci-app-advanced-reboot: update to 1.1.0-1

Makefile:
- update SPDX license identified and copyright
- update documentation link

README:
- add short README with the link to full documentation

System View javascript:
- switch from single to double quotes
- update documentation link
- more readable translateTable
- better code readability for
  - callPowerOff
  - handlePowerOff
  - handleReboot
  - handleTogglePartition
  - handleAlternativeReboot
  - parsePartitions
  - some visual elements

RPCD Script:
- more resilient to unexpected CLI output
- add debugger function to ease development/debugging
- better check if `/var/alt_rom` is mounted before calling umount
- better handling of MTD indices

Device Support:
- add Linksys MR7350 which slipped thru the cracks

Signed-off-by: Stan Grishin <stangri@melmac.ca>
This commit is contained in:
Stan Grishin
2025-08-12 08:31:10 +00:00
parent af2ca3d33f
commit a353d15b55
5 changed files with 384 additions and 189 deletions

View File

@@ -1,19 +1,19 @@
# Copyright 2017-2024 MOSSDeF, Stan Grishin (stangri@melmac.ca).
# This is free software, licensed under AGPL-3.0-or-later.
# SPDX-License-Identifier: AGPL-3.0-or-later
# Copyright 2017-2025 MOSSDeF, Stan Grishin (stangri@melmac.ca).
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-advanced-reboot
PKG_LICENSE:=AGPL-3.0-or-later
PKG_MAINTAINER:=Stan Grishin <stangri@melmac.ca>
PKG_VERSION:=1.0.1
PKG_RELEASE:=21
PKG_VERSION:=1.1.0
PKG_RELEASE:=1
LUCI_TITLE:=Advanced Linksys Reboot Web UI
LUCI_URL:=https://github.com/stangri/luci-app-advanced-reboot/
LUCI_DESCRIPTION:=Provides Web UI (found under System/Advanced Reboot) to reboot supported Linksys and ZyXEL routers to\
an alternative partition. Also provides Web UI to shut down (power off) your device. Supported dual-partition\
routers are listed at https://docs.openwrt.melmac.net/luci-app-advanced-reboot/
routers are listed at https://docs.openwrt.melmac.ca/luci-app-advanced-reboot/
LUCI_DEPENDS:=+luci-base +jshn
define Package/$(PKG_NAME)/config

View File

@@ -1,3 +1,28 @@
# README
# luci-app-advanced-reboot
Documentation for this project is available at [https://docs.openwrt.melmac.net/luci-app-advanced-reboot/](https://docs.openwrt.melmac.net/luci-app-advanced-reboot/).
`luci-app-advanced-reboot` is a LuCI (web interface) application for OpenWrt that provides an easy way to reboot your router into an alternative firmware partition (for dual-partition devices) or perform other advanced reboot operations directly from the web UI.
## Features
- Detects supported dual-partition devices.
- Displays current and alternative firmware details.
- Allows rebooting into the alternative partition without using SSH.
- Supports switching between OpenWrt and vendor firmware (if present).
## Installation
You can install this package from the official OpenWrt package repositories or from the Melmac OpenWrt repository:
```sh
opkg update
opkg install luci-app-advanced-reboot
```
## Documentation
Full documentation is available at:
[https://docs.openwrt.melmac.ca/luci-app-advanced-reboot/](https://docs.openwrt.melmac.ca/luci-app-advanced-reboot/)
## License
This project is licensed under the terms of the GNU General Public License v3.0 (GPL-3.0).

View File

@@ -1,241 +1,380 @@
'use strict';
'require view';
'require rpc';
'require ui';
'require uci';
'require fs';
"use strict";
"require view";
"require rpc";
"require ui";
"require uci";
"require fs";
var pkg = {
get Name() { return 'luci-app-advanced-reboot'; },
get URL() { return 'https://docs.openwrt.melmac.net/' + pkg.Name + '/'; }
get Name() {
return "luci-app-advanced-reboot";
},
get URL() {
return "https://docs.openwrt.melmac.ca/" + pkg.Name + "/";
},
};
return view.extend({
translateTable: {
NO_BOARD_NAME : function(args) { return _('Unable to find Device Board Name.')},
NO_DUAL_FLAG: function (args) { return _('Unable to find Dual Boot Flag Partition.') },
NO_DUAL_FLAG_BLOCK: function (args) { return _('The Dual Boot Flag Partition: %s is not a block device.').format(args[0])},
ERR_SET_DUAL_FLAG : function(args) { return _('Unable to set Dual Boot Flag Partition entry for partition: %s.').format(args[0])},
NO_FIRM_ENV : function(args) { return _('Unable to obtain firmware environment variable: %s.').format(args[0])},
ERR_SET_ENV : function(args) { return _('Unable to set firmware environment variable: %s to %s.').format(args[0],args[1])}
NO_BOARD_NAME: function (args) {
return _("Unable to find Device Board Name.");
},
NO_DUAL_FLAG: function (args) {
return _("Unable to find Dual Boot Flag Partition.");
},
NO_DUAL_FLAG_BLOCK: function (args) {
return _(
"The Dual Boot Flag Partition: %s is not a block device."
).format(args[0]);
},
ERR_SET_DUAL_FLAG: function (args) {
return _(
"Unable to set Dual Boot Flag Partition entry for partition: %s."
).format(args[0]);
},
NO_FIRM_ENV: function (args) {
return _("Unable to obtain firmware environment variable: %s.").format(
args[0]
);
},
ERR_SET_ENV: function (args) {
return _("Unable to set firmware environment variable: %s to %s.").format(
args[0],
args[1]
);
},
},
callReboot: rpc.declare({
object: 'system',
method: 'reboot',
expect: { result: 0 }
object: "system",
method: "reboot",
expect: { result: 0 },
}),
callObtainDeviceInfo: rpc.declare({
object: 'luci.advanced_reboot',
method: 'obtain_device_info',
expect: { }
object: "luci.advanced_reboot",
method: "obtain_device_info",
expect: {},
}),
callTogglePartition: rpc.declare({
object: 'luci.advanced_reboot',
method: 'toggle_boot_partition',
expect: { }
object: "luci.advanced_reboot",
method: "toggle_boot_partition",
expect: {},
}),
callPowerOff: function() {
return fs.exec('/sbin/poweroff').then(function() {
ui.showModal(_('Shutting down...'), [
E('p', { 'class': 'spinning' }, _('The system is shutting down now.<br /> DO NOT POWER OFF THE DEVICE!<br /> It might be necessary to renew the address of your computer to reach the device again, depending on your settings.'))
callPowerOff: function () {
return fs.exec("/sbin/poweroff").then(function () {
ui.showModal(_("Shutting down..."), [
E(
"p",
{ class: "spinning" },
_(
"The system is shutting down now.<br /> DO NOT POWER OFF THE DEVICE!<br /> It might be necessary to renew the address of your computer to reach the device again, depending on your settings."
)
),
]);
})
});
},
handlePowerOff: function() {
ui.showModal(_('Power Off Device'), [
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.")),
E('div', { 'class': 'right' }, [
E('button', {
'class': 'btn',
'click': ui.hideModal
}, _('Cancel')), ' ',
E('button', {
'class': 'btn cbi-button cbi-button-positive important',
'click': L.bind(this.callPowerOff, this)
}, _('Proceed'))
])
handlePowerOff: function () {
ui.showModal(_("Power Off Device"), [
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.'
)
),
E("div", { class: "right" }, [
E(
"button",
{
class: "btn",
click: ui.hideModal,
},
_("Cancel")
),
" ",
E(
"button",
{
class: "btn cbi-button cbi-button-positive important",
click: L.bind(this.callPowerOff, this),
},
_("Proceed")
),
]),
]);
},
handleReboot: function(ev) {
return this.callReboot().then(function(res) {
handleReboot: function (ev) {
return this.callReboot()
.then(function (res) {
if (res != 0) {
ui.addNotification(null, E('p', _('The reboot command failed with code %d').format(res)));
L.raise('Error', 'Reboot failed');
ui.addNotification(
null,
E("p", _("The reboot command failed with code %d").format(res))
);
L.raise("Error", "Reboot failed");
}
ui.showModal(_('Rebooting…'), [
E('p', { 'class': 'spinning' }, _('Waiting for device...'))
ui.showModal(_("Rebooting…"), [
E("p", { class: "spinning" }, _("Waiting for device...")),
]);
window.setTimeout(function() {
ui.showModal(_('Rebooting…'), [
E('p', { 'class': 'spinning alert-message warning' },
_('Device unreachable! Still waiting for device...'))
window.setTimeout(function () {
ui.showModal(_("Rebooting…"), [
E(
"p",
{ class: "spinning alert-message warning" },
_("Device unreachable! Still waiting for device...")
),
]);
}, 150000);
ui.awaitReconnect();
})
.catch(function(e) { ui.addNotification(null, E('p', e.message)) });
.catch(function (e) {
ui.addNotification(null, E("p", e.message));
});
},
handleTogglePartition: function(ev) {
return this.callTogglePartition().then(L.bind(function(res) {
handleTogglePartition: function (ev) {
return this.callTogglePartition().then(
L.bind(function (res) {
if (res.error) {
ui.hideModal()
return ui.addNotification(null, E('p', this.translateTable[res.error](res.args)));
ui.hideModal();
return ui.addNotification(
null,
E("p", this.translateTable[res.error](res.args))
);
}
return this.callReboot().then(function(res) {
return this.callReboot()
.then(function (res) {
if (res != 0) {
ui.addNotification(null, E('p', _('The reboot command failed with code %d').format(res)));
L.raise('Error', 'Reboot failed');
ui.addNotification(
null,
E("p", _("The reboot command failed with code %d").format(res))
);
L.raise("Error", "Reboot failed");
}
ui.showModal(_('Rebooting…'), [
E('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.'))
ui.showModal(_("Rebooting…"), [
E(
"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."
)
),
]);
window.setTimeout(function() {
ui.showModal(_('Rebooting…'), [
E('p', { 'class': 'spinning alert-message warning' },
_('Device unreachable! Still waiting for device...'))
window.setTimeout(function () {
ui.showModal(_("Rebooting…"), [
E(
"p",
{ class: "spinning alert-message warning" },
_("Device unreachable! Still waiting for device...")
),
]);
}, 150000);
ui.awaitReconnect();
})
.catch(function(e) { ui.addNotification(null, E('p', e.message)) });
}, this));
.catch(function (e) {
ui.addNotification(null, E("p", e.message));
});
}, this)
);
},
handleAlternativeReboot: function(ev) {
handleAlternativeReboot: function (ev) {
return Promise.all([
L.resolveDefault(fs.stat('/usr/sbin/fw_printenv'), null),
L.resolveDefault(fs.stat('/usr/sbin/fw_setenv'), null),
]).then(L.bind(function (data) {
L.resolveDefault(fs.stat("/usr/sbin/fw_printenv"), null),
L.resolveDefault(fs.stat("/usr/sbin/fw_setenv"), null),
]).then(
L.bind(function (data) {
if (!data[0] || !data[1]) {
return ui.addNotification(null, E('p', _('No access to fw_printenv or fw_printenv!')));
return ui.addNotification(
null,
E("p", _("No access to fw_printenv or fw_printenv!"))
);
}
ui.showModal(_('Reboot Device to an Alternative Partition') + " - " + _("Confirm"), [
E('p', _("WARNING: An alternative partition might have its own settings and completely different firmware.<br /><br />\
ui.showModal(
_("Reboot Device to an Alternative Partition") + " - " + _("Confirm"),
[
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 an alternative partition.")),
E('div', { 'class': 'right' }, [
E('button', {
'class': 'btn',
'click': ui.hideModal
}, _('Cancel')), ' ',
E('button', {
'class': 'btn cbi-button cbi-button-positive important',
'click': L.bind(this.handleTogglePartition, this)
}, _('Proceed'))
])
]);
}, this))
Click "Proceed" below to reboot device to an alternative partition.'
)
),
E("div", { class: "right" }, [
E(
"button",
{
class: "btn",
click: ui.hideModal,
},
_("Cancel")
),
" ",
E(
"button",
{
class: "btn cbi-button cbi-button-positive important",
click: L.bind(this.handleTogglePartition, this),
},
_("Proceed")
),
]),
]
);
}, this)
);
},
parsePartitions: function(partitions) {
parsePartitions: function (partitions) {
var res = [];
partitions.forEach(L.bind(function(partition) {
partitions.forEach(
L.bind(function (partition) {
var func, text;
if (partition.state == 'Current') {
func = 'handleReboot';
text = _('Reboot to current partition');
if (partition.state == "Current") {
func = "handleReboot";
text = _("Reboot to current partition");
} else {
func = 'handleAlternativeReboot';
text = _('Reboot to alternative partition...');
func = "handleAlternativeReboot";
text = _("Reboot to alternative partition...");
}
res.push([
(partition.number+0x100).toString(16).substr(-2).toUpperCase(),
(partition.number + 0x100).toString(16).substr(-2).toUpperCase(),
_(partition.state),
partition.os.replace("Unknown", _("Unknown")).replace("Compressed", _("Compressed")),
E('button', {
'class': 'btn cbi-button cbi-button-apply important',
'click': ui.createHandlerFn(this, func)
}, text)
])
}, this));
partition.os
.replace("Unknown", _("Unknown"))
.replace("Compressed", _("Compressed")),
E(
"button",
{
class: "btn cbi-button cbi-button-apply important",
click: ui.createHandlerFn(this, func),
},
text
),
]);
}, this)
);
return res;
},
load: function() {
load: function () {
return Promise.all([
uci.changes(),
L.resolveDefault(fs.stat('/sbin/poweroff'), null),
this.callObtainDeviceInfo()
L.resolveDefault(fs.stat("/sbin/poweroff"), null),
this.callObtainDeviceInfo(),
]);
},
render: function(data) {
render: function (data) {
var changes = data[0],
poweroff_supported = data[1] != null ? true : false,
device_info = data[2];
var body = E([
E('h2', _('Advanced Reboot'))
]);
var body = E([E("h2", _("Advanced Reboot"))]);
for (var config in (changes || {})) {
body.appendChild(E('p', { 'class': 'alert-message warning' },
_('Warning: There are unsaved changes that will get lost on reboot!')));
for (var config in changes || {}) {
body.appendChild(
E(
"p",
{ class: "alert-message warning" },
_("Warning: There are unsaved changes that will get lost on reboot!")
)
);
break;
}
if (device_info.error)
body.appendChild(E('p', { 'class' : 'alert-message warning'}, _("ERROR: ") + this.translateTable[device_info.error]()));
body.appendChild(
E(
"p",
{ class: "alert-message warning" },
_("ERROR: ") + this.translateTable[device_info.error]()
)
);
body.appendChild(E('h3', (device_info.device_name || '') + _(' Partitions')));
body.appendChild(
E("h3", (device_info.device_name || "") + _(" Partitions"))
);
if (device_info.device_name) {
var partitions_table = E('table', { 'class': 'table' }, [
E('tr', { 'class': 'tr table-titles' }, [
E('th', { 'class': 'th' }, [ _('Partition') ]),
E('th', { 'class': 'th' }, [ _('Status') ]),
E('th', { 'class': 'th' }, [ _('Firmware') ]),
E('th', { 'class': 'th' }, [ _('Reboot') ])
])
var partitions_table = E("table", { class: "table" }, [
E("tr", { class: "tr table-titles" }, [
E("th", { class: "th" }, [_("Partition")]),
E("th", { class: "th" }, [_("Status")]),
E("th", { class: "th" }, [_("Firmware")]),
E("th", { class: "th" }, [_("Reboot")]),
]),
]);
cbi_update_table(partitions_table, this.parsePartitions(device_info.partitions));
cbi_update_table(
partitions_table,
this.parsePartitions(device_info.partitions)
);
body.appendChild(partitions_table);
} else {
body.appendChild(E('p', { 'class' : 'alert-message warning'},
device_info.rom_board_name ? _("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.").format(device_info.rom_board_name, "<br /><br />", "<br />",
"<a href=\"" + pkg.URL + "#how-to-add-a-new-device\" target=\"_blank\">", "</a>" )
: _('Warning: Unable to obtain device information!')
));
body.appendChild(
E(
"p",
{ class: "alert-message warning" },
device_info.rom_board_name
? _(
"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."
).format(
device_info.rom_board_name,
"<br /><br />",
"<br />",
'<a href="' +
pkg.URL +
'#how-to-add-a-new-device" target="_blank">',
"</a>"
)
: _("Warning: Unable to obtain device information!")
)
);
}
body.appendChild(E('hr'));
body.appendChild(E("hr"));
body.appendChild(
poweroff_supported ? E('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!'))
poweroff_supported
? E(
"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!")
)
);
return body;
@@ -243,5 +382,5 @@ return view.extend({
handleSaveApply: null,
handleSave: null,
handleReset: null
handleReset: null,
});

View File

@@ -1,13 +1,23 @@
#!/bin/sh
# Copyright 2017-2020 Stan Grishin (stangri@melmac.ca)
# Copyright 2017-2025 Stan Grishin (stangri@melmac.ca)
# shellcheck disable=SC2039,SC1091,SC3043,SC3057,SC3060
# TechRef: https://openwrt.org/docs/techref/rpcd
# TESTS
# ubus -v list luci.advanced_reboot
# ubus -S call luci.advanced_reboot obtain_device_info '{"name": "advanced-reboot" }'
# ubus -S call luci.advanced_reboot toggle_boot_partition '{"name": "advanced-reboot" }'
readonly devices_dir="/usr/share/advanced-reboot/devices/"
. /lib/functions.sh
. /usr/share/libubox/jshn.sh
logger() { /usr/bin/logger -t advanced-reboot "$1"; }
packageName='advanced-reboot'
debug() { local i j; for i in "$@"; do eval "j=\$$i"; logger "${packageName:+-t $packageName}" "${i}: ${j} "; done; }
logger() { /usr/bin/logger -t advanced-reboot "$*"; }
is_present() { command -v "$1" >/dev/null 2>&1; }
is_alt_mountable() {
@@ -25,29 +35,29 @@ is_alt_mountable() {
alt_partition_mount() {
local ubi_dev op_ubi="$1" ubi_vol="${2:-0}"
mkdir -p /var/alt_rom
ubi_dev="$(ubiattach -m "$op_ubi")"
ubi_dev="$(ubiattach -m "$op_ubi" 2>/dev/null)"
ubi_dev="$(echo "$ubi_dev" | sed -n "s/^UBI device number\s*\(\d*\),.*$/\1/p")"
if [ -z "$ubi_dev" ]; then
ubidetach -m "$op_ubi"
ubidetach -m "$op_ubi" >/dev/null 2>&1
return 1
fi
ubiblock --create "/dev/ubi${ubi_dev}_${ubi_vol}" && \
mount -t squashfs -r "/dev/ubiblock${ubi_dev}_${ubi_vol}" /var/alt_rom
ubiblock --create "/dev/ubi${ubi_dev}_${ubi_vol}" >/dev/null 2>&1 && \
mount -t squashfs -r "/dev/ubiblock${ubi_dev}_${ubi_vol}" /var/alt_rom >/dev/null 2>&1
}
alt_partition_unmount() {
local mtdCount i=0 op_ubi="$1" ubi_vol="${2:-0}"
mtdCount="$(ubinfo | grep 'Present UBI devices' | tr ',' '\n' | grep -c 'ubi')"
[ -z "$mtdCount" ] && mtdCount=10
[ -d /var/alt_rom ] && umount /var/alt_rom
grep -qs '/var/alt_rom ' /proc/mounts && umount /var/alt_rom
while [ "$i" -le "$mtdCount" ]; do
if [ ! -e "/sys/devices/virtual/ubi/ubi${i}/mtd_num" ]; then
break
fi
ubi_mtd="$(cat /sys/devices/virtual/ubi/ubi${i}/mtd_num)"
if [ -n "$ubi_mtd" ] && [ "$ubi_mtd" = "$op_ubi" ]; then
ubiblock --remove /dev/ubi${i}_${ubi_vol}
ubidetach -m "$op_ubi"
ubiblock --remove "/dev/ubi${i}_${ubi_vol}" >/dev/null 2>&1
ubidetach -m "$op_ubi" >/dev/null 2>&1
rm -rf /var/alt_rom
fi
i=$((i + 1))
@@ -71,6 +81,7 @@ get_alt_partition_os_info(){
alt_partition_unmount "$op_ubi" "$ubi_vol"
alt_partition_mount "$op_ubi" "$ubi_vol"
if [ -s "/var/alt_rom/etc/os-release" ]; then
# shellcheck disable=SC2031
op_info="$(. /var/alt_rom/etc/os-release && echo "$PRETTY_NAME")"
if [ "${op_info//SNAPSHOT}" != "$op_info" ]; then
op_info="$(. /var/alt_rom/etc/os-release && echo "${OPENWRT_RELEASE%%-*}")"
@@ -134,7 +145,7 @@ obtain_device_info(){
if [ -n "$labelOffset" ]; then
if [ -n "$partition1MTD" ]; then
p1_label="$(dd if="/dev/${partition1MTD}" bs=1 skip="${labelOffset}" count=64 2>/dev/null)"
p1_label="$(dd if="/dev/${partition1MTD}" bs=1 skip="${labelOffset}" count=64 2>/dev/null | tr -d '\0')"
if [ -n "$p1_label" ]; then
p1_version="$(echo "$p1_label" | sed -n "s/\(.*\)Linux-\([0-9.]\+\).*$/\2/p")"
if [ "${p1_label//LEDE}" != "$p1_label" ]; then p1_os="LEDE"; fi
@@ -149,7 +160,7 @@ obtain_device_info(){
fi
if [ -n "$partition2MTD" ]; then
p2_label="$(dd if="/dev/${partition2MTD}" bs=1 skip="${labelOffset}" count=64 2>/dev/null)"
p2_label="$(dd if="/dev/${partition2MTD}" bs=1 skip="${labelOffset}" count=64 2>/dev/null | tr -d '\0')"
if [ -n "$p2_label" ]; then
p2_version="$(echo "$p2_label" | sed -n "s/\(.*\)Linux-\([0-9.]\+\).*$/\2/p")"
if [ "${p2_label//LEDE}" != "$p2_label" ]; then p2_os="LEDE"; fi
@@ -192,13 +203,19 @@ obtain_device_info(){
if is_alt_mountable "$partition1MTD" "$partition2MTD"; then
opOffset="${opOffset:-1}"
ubiVolume="${ubiVolume:-0}"
# Robustly extract numeric MTD indices (handles mtd2, mtd22, mtd22ro, etc.)
local p1num p2num
p1num="${partition1MTD#mtd}"; p1num="${p1num%%[^0-9]*}"
p2num="${partition2MTD#mtd}"; p2num="${p2num%%[^0-9]*}"
[ -n "$p1num" ] || p1num=0
[ -n "$p2num" ] || p2num=0
if [ "$current_partition" = "$bootEnv1Partition1Value" ]; then
op_ubi=$(( ${partition2MTD:3:3} + $opOffset ))
op_ubi=$(( p2num + opOffset ))
else
op_ubi=$(( ${partition1MTD:3:3} + $opOffset ))
op_ubi=$(( p1num + opOffset ))
fi
cp_info="$(get_main_partition_os_info $op_ubi)"
op_info="$(get_alt_partition_os_info $op_ubi $vendorName $ubiVolume)"
cp_info="$(get_main_partition_os_info "$op_ubi")"
op_info="$(get_alt_partition_os_info "$op_ubi" "$vendorName" "$ubiVolume")"
if [ "$current_partition" = "$bootEnv1Partition1Value" ]; then
p1_os="${cp_info:-$p1_os}"
p2_os="${op_info:-$p2_os}"
@@ -336,7 +353,7 @@ toggle_boot_partition(){
json_add_string "$newEnvSetting"
json_close_array
json_add_string 'rom_board_name' "$romBoardName"
json_dump; json_cleanup;
json_dump >&4; json_cleanup;
return
fi
fi
@@ -378,7 +395,7 @@ toggle_boot_partition(){
fi
fi
json_init
json_dump; json_cleanup;
json_dump >&4; json_cleanup;
fi
}

View File

@@ -0,0 +1,14 @@
{
"vendorName": "Linksys",
"deviceName": "MR7350",
"boardNames": [ "linksys,mr7350" ],
"partition1MTD": "mtd14",
"partition2MTD": "mtd16",
"labelOffset": 192,
"bootEnv1": "boot_part",
"bootEnv1Partition1Value": 1,
"bootEnv1Partition2Value": 2,
"bootEnv2": null,
"bootEnv2Partition1Value": null,
"bootEnv2Partition2Value": null
}