# SPDX-License-Identifier: AGPL-3.0-or-later
-# Copyright 2017-2025 MOSSDeF, Stan Grishin (stangri@melmac.ca).
+# Copyright 2017-2026 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.1.0
-PKG_RELEASE:=1
+PKG_VERSION:=1.1.1
+PKG_RELEASE:=9
+
+PKG_BUILD_DEPENDS:=jq/host
LUCI_TITLE:=Advanced Linksys Reboot Web UI
LUCI_URL:=https://github.com/stangri/luci-app-advanced-reboot/
include ../../luci.mk
+# Prune individual device JSON directories from the package image.
+# The default LuCI install logic from luci.mk copies everything under
+# htdocs/, root/, etc. We let it run, then remove folders we keep only
+# in source control.
+define Package/$(PKG_NAME)/install
+ $(call Package/$(PKG_NAME)/install/default,$(1))
+ @mkdir -p $(1)/usr/share/advanced-reboot
+ @if [ -d $(1)/usr/share/advanced-reboot/devices ] \
+ && ls $(1)/usr/share/advanced-reboot/devices/*.json >/dev/null 2>&1; then \
+ $(STAGING_DIR_HOST)/bin/jq -s '.' $(1)/usr/share/advanced-reboot/devices/*.json \
+ > $(1)/usr/share/advanced-reboot/devices.json; \
+ fi
+ @if [ -s $(1)/usr/share/advanced-reboot/devices.json ]; then \
+ $(RM) -r $(1)/usr/share/advanced-reboot/devices $(1)/usr/share/advanced-reboot/devices.disabled || true; \
+ fi
+endef
+
# call BuildPackage - OpenWrt buildroot signature
args[1]
);
},
+ BOARD_NAME_MATCH_FILE_READ: function (args) {
+ var b = args && args[0] ? args[0] : "";
+ return _("Error accessing the device definition for board: %s").format(b);
+ },
+ NO_BOARD_NAME_MATCH: function (args) {
+ var b = args && args[0] ? args[0] : "";
+ /* This entry is unused in generic error banner; we render a dedicated warning below. */
+ return _("Unknown or unsupported dual-partition device: %s").format(b);
+ },
+ INVALID_ARG: function (args) {
+ var d = args && args[0] ? args[0] : _("invalid argument");
+ return _("Invalid request: %s.").format(d);
+ },
+ PARTITION_NOT_FOUND: function (args) {
+ var n = args && args[0] ? args[0] : "?";
+ return _("Partition %s was not found in the device definition.").format(
+ n
+ );
+ },
+ ERR_SAVE_ENV: function (args) {
+ return _("Unable to save environment changes.");
+ },
+ NO_TARGET_FLAG: function (args) {
+ return _("Target partition flag is not defined for this device.");
+ },
},
callReboot: rpc.declare({
}),
callObtainDeviceInfo: rpc.declare({
- object: "luci.advanced_reboot",
+ object: "luci.advanced-reboot",
method: "obtain_device_info",
expect: {},
}),
- callTogglePartition: rpc.declare({
- object: "luci.advanced_reboot",
- method: "toggle_boot_partition",
+ callBootPartition: rpc.declare({
+ object: "luci.advanced-reboot",
+ method: "boot_partition",
+ params: ["number"],
expect: {},
}),
);
},
- 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) {
- if (!data[0] || !data[1]) {
- return ui.addNotification(
- null,
- E("p", _("No access to fw_printenv or fw_printenv!"))
- );
- }
+ handleAlternativeReboot: function () {
+ // accept either (ev, number) or (number, ev)
+ var pn = null;
+
+ 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) {
+ // fall back / safety
+ ui.addNotification(null, E("p", _("Missing partition number")));
+ return Promise.resolve();
+ }
+ return Promise.all([]).then(
+ L.bind(function (data) {
ui.showModal(
- _("Reboot Device to an Alternative Partition") + " - " + _("Confirm"),
+ _("Reboot Device to Partition: %s").format(
+ String(pn).padStart(2, "0")
+ ),
[
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.'
+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" }, [
"button",
{
class: "btn cbi-button cbi-button-positive important",
- click: L.bind(this.handleTogglePartition, this),
+ click: L.bind(function () {
+ this.callBootPartition(String(pn))
+ .then(
+ L.bind(function (res) {
+ ui.hideModal();
+ if (res && res.error) {
+ var fn = this.translateTable[res.error];
+ var a = Array.isArray(res.args) ? res.args : [];
+ if (res.detail) a = [res.detail].concat(a);
+
+ var msg =
+ typeof fn === "function"
+ ? fn(a)
+ : _("Unexpected error: %s").format(
+ String(res.error)
+ );
+
+ return ui.addNotification(null, E("p", msg));
+ }
+ return this.handleReboot();
+ }, this)
+ )
+ .catch(function (e) {
+ ui.addNotification(null, E("p", e.message));
+ });
+ }, this),
},
_("Proceed")
),
);
},
- parsePartitions: function (partitions) {
+ parsePartitions: function (partitions, activeNumber) {
var res = [];
+ var active = activeNumber != null ? String(Number(activeNumber)) : null;
- partitions.forEach(
+ (partitions || []).forEach(
L.bind(function (partition) {
- var func, text;
-
- if (partition.state == "Current") {
- func = "handleReboot";
- text = _("Reboot to current partition");
- } else {
- func = "handleAlternativeReboot";
- text = _("Reboot to alternative partition...");
- }
+ var isActive =
+ active != null && String(Number(partition.number)) === active;
+ var func = isActive ? "handleReboot" : "handleAlternativeReboot";
+ var status = isActive ? _("Current") : _("Alternative");
+ var text = isActive
+ ? _("Reboot to current partition")
+ : _("Reboot to this partition...");
+
+ var fwLabel = partition.label || _("Unknown");
+ fwLabel +=
+ partition.os && partition.os != ""
+ ? " (Linux " + partition.os + ")"
+ : "";
res.push([
- (partition.number + 0x100).toString(16).substr(-2).toUpperCase(),
- _(partition.state),
- partition.os
- .replace("Unknown", _("Unknown"))
- .replace("Compressed", _("Compressed")),
+ String(Number(partition.number || 0)).padStart(2, "0"),
+ status,
+ fwLabel,
E(
"button",
{
class: "btn cbi-button cbi-button-apply important",
- click: ui.createHandlerFn(this, func),
+ click: ui.createHandlerFn(
+ this,
+ func,
+ String(Number(partition.number))
+ ),
},
text
),
var body = E([E("h2", _("Advanced Reboot"))]);
+ var device_name = "";
+ var active_num = null;
+ var partitions = [];
+ if (device_info && device_info.device && device_info.partitions) {
+ var d = device_info.device;
+ device_name = [d.vendor || "", d.model || ""].filter(Boolean).join(" ");
+ active_num =
+ d.partition_active != null ? String(d.partition_active) : null;
+ partitions = device_info.partitions || [];
+ }
+
for (var config in changes || {}) {
body.appendChild(
E(
break;
}
- if (device_info.error)
- body.appendChild(
- E(
- "p",
- { class: "alert-message warning" },
- _("ERROR: ") + this.translateTable[device_info.error]()
- )
- );
+ /* Error handling */
+ if (device_info && device_info.error) {
+ if (device_info.error === "NO_BOARD_NAME_MATCH") {
+ var warnBoard = device_info.rom_board_name || "";
+ body.appendChild(
+ E(
+ "p",
+ { 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."
+ ).format(
+ warnBoard,
+ "<br /><br />",
+ "<br />",
+ '<a href="' +
+ pkg.URL +
+ '#how-to-add-a-new-device" target="_blank">',
+ "</a>"
+ )
+ )
+ );
+ } else {
+ var err = device_info.error;
+ var fn = this.translateTable[err];
+ var args = [];
+ if (device_info.detail) args = [device_info.detail];
+ else if (device_info.rom_board_name)
+ args = [device_info.rom_board_name];
+
+ if (typeof fn === "function") {
+ body.appendChild(
+ E("p", { class: "alert-message warning" }, _("ERROR: ") + fn(args))
+ );
+ } else {
+ body.appendChild(
+ E(
+ "p",
+ { class: "alert-message warning" },
+ _("ERROR: %s").format(err)
+ )
+ );
+ }
+ }
+ }
- body.appendChild(
- E("h3", (device_info.device_name || "") + _(" Partitions"))
- );
- if (device_info.device_name) {
+ body.appendChild(E("h3", (device_name || "") + _(" Partitions")));
+
+ if (
+ device_info &&
+ device_info.device &&
+ Array.isArray(partitions) &&
+ partitions.length
+ ) {
+ /* render table as before */
var partitions_table = E("table", { class: "table" }, [
E("tr", { class: "tr table-titles" }, [
E("th", { class: "th" }, [_("Partition")]),
cbi_update_table(
partitions_table,
- this.parsePartitions(device_info.partitions)
+ this.parsePartitions(partitions, active_num)
);
body.appendChild(partitions_table);
- } else {
+ } else if (!device_info || !device_info.error) {
+ /* no partitions and no explicit error */
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!")
+ _("Warning: Unable to obtain device information!")
)
);
}
+++ /dev/null
-#!/bin/sh
-# 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
-
-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() {
- local p1_mtd="$1" p2_mtd="$2"
- if [ "${p1_mtd:0:3}" = "mtd" ] && [ "${p2_mtd:0:3}" = "mtd" ] && \
- is_present 'ubiattach' && \
- is_present 'ubiblock' && \
- is_present 'mount'; then
- return 0
- else
- return 1
- fi
-}
-
-alt_partition_mount() {
- local ubi_dev op_ubi="$1" ubi_vol="${2:-0}"
- mkdir -p /var/alt_rom
- 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" >/dev/null 2>&1
- return 1
- fi
- 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
- 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}" >/dev/null 2>&1
- ubidetach -m "$op_ubi" >/dev/null 2>&1
- rm -rf /var/alt_rom
- fi
- i=$((i + 1))
- done
-}
-
-get_main_partition_os_info(){
- local cp_info
- if [ -s "/etc/os-release" ]; then
- cp_info="$(. /etc/os-release && echo "$PRETTY_NAME")"
- if [ "${cp_info//SNAPSHOT}" != "$cp_info" ]; then
- cp_info="$(. /etc/os-release && echo "${OPENWRT_RELEASE%%-*}")"
- fi
- fi
- echo "$cp_info"
-}
-
-get_alt_partition_os_info(){
- local op_info op_ubi="$1" vendor_name="$2" ubi_vol="$3"
- logger "attempting to mount alternative partition (mtd${op_ubi})"
- 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%%-*}")"
- fi
- fi
- if [ -s "/var/alt_rom/etc/partition_config/soft-version" ]; then
- op_info="${vendor_name:+$vendor_name }$(awk -F: '$1=="soft_ver" { print $2 ;}' /var/alt_rom/etc/partition_config/soft-version)"
- fi
- logger "attempting to unmount alternative partition (mtd${op_ubi})"
- alt_partition_unmount "$op_ubi" "$ubi_vol"
- echo "$op_info"
-}
-
-find_device_data(){
- local boardNames filename i romBoardName="$1"
- for filename in "${devices_dir}"*.json; do
- [ "$filename" = "${devices_dir}*.json" ] && return
- json_load_file "$filename"
- json_get_values boardNames 'boardNames'
- json_cleanup
- for i in $boardNames; do
- if [ "$i" = "$romBoardName" ]; then
- echo "$filename"
- return
- fi
- done
- done
-}
-
-print_json() { json_init; json_add_string "$1" "$2"; json_dump; json_cleanup; }
-
-obtain_device_info(){
- local romBoardName p zyxelFlagPartition i
- local vendorName deviceName partition1MTD partition2MTD labelOffset
- local opOffset ubiVolume
- local bootEnv1 bootEnv1Partition1Value bootEnv1Partition2Value
- local bootEnv2 bootEnv2Partition1Value bootEnv2Partition2Value
- local p1_label p1_version p2_label p2_version p1_os p2_os
- local current_partition op_ubi cp_info op_info
-
- romBoardName="$(cat /tmp/sysinfo/board_name)"
- if [ -z "$romBoardName" ]; then
- print_json 'error' 'NO_BOARD_NAME'
- return
- fi
-
- p="$(find_device_data "$romBoardName")"
- if [ -z "$p" ] || [ ! -s "$p" ]; then
- print_json 'rom_board_name' "$romBoardName"
- return
- fi
-
- json_load_file "$p"
- for i in vendorName deviceName partition1MTD partition2MTD labelOffset \
- bootEnv1 bootEnv1Partition1Value bootEnv1Partition2Value \
- bootEnv2 bootEnv2Partition1Value bootEnv2Partition2Value \
- opOffset ubiVolume; do
- json_get_var $i "$i"
- done
- json_cleanup
-
- if [ -n "$labelOffset" ]; then
- if [ -n "$partition1MTD" ]; then
- 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
- if [ "${p1_label//OpenWrt}" != "$p1_label" ]; then p1_os="OpenWrt"; fi
- if [ -n "$vendorName" ] && [ "${p1_label//$vendorName}" != "$p1_label" ]; then
- p1_os="$vendorName"
- fi
- fi
- if [ -z "$p1_os" ]; then
- p1_os="${vendorName:-Unknown}/Unknown"
- fi
- fi
-
- if [ -n "$partition2MTD" ]; then
- 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
- if [ "${p2_label//OpenWrt}" != "$p2_label" ]; then p2_os="OpenWrt"; fi
- if [ -n "$vendorName" ] && [ "${p2_label//$vendorName}" != "$p2_label" ]; then
- p2_os="$vendorName"
- fi
- fi
- if [ -z "$p2_os" ]; then
- p2_os="${vendorName:-Unknown}/Unknown"
- fi
- fi
- else
- p1_os="${vendorName}/Unknown (Compressed)"
- p2_os="${vendorName}/Unknown (Compressed)"
- fi
-
- if [ -n "$bootEnv1" ]; then
- if [ -x "/usr/sbin/fw_printenv" ] && [ -x "/usr/sbin/fw_setenv" ]; then
- current_partition="$(/usr/sbin/fw_printenv -n "${bootEnv1}")"
- fi
- else
- for i in '0:dual_flag' '0:DUAL_FLAG'; do
- zyxelFlagPartition="$(find_mtd_part "$i" 2>/dev/null)"
- [ -n "$zyxelFlagPartition" ] && break
- done
- if [ -z "$zyxelFlagPartition" ]; then
- print_json 'error' 'NO_DUAL_FLAG'
- logger "Unable to find Dual Boot Environment or Dual Boot Flag Partition."
- return
- elif [ ! -b "$zyxelFlagPartition" ]; then
- print_json 'error' 'NO_DUAL_FLAG_BLOCK'
- logger "The Dual Boot Flag Partition: $zyxelFlagPartition is not block device."
- return
- else
- current_partition="$(dd if="${zyxelFlagPartition}" bs=1 count=1 2>/dev/null | hexdump -n 1 -e '1/1 "%d"')"
- fi
- fi
-
- 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=$(( p2num + opOffset ))
- else
- 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")"
- if [ "$current_partition" = "$bootEnv1Partition1Value" ]; then
- p1_os="${cp_info:-$p1_os}"
- p2_os="${op_info:-$p2_os}"
- else
- p1_os="${op_info:-$p1_os}"
- p2_os="${cp_info:-$p2_os}"
- fi
- fi
- if [ -n "$p1_os" ] && [ -n "$p1_version" ]; then
- p1_os="$p1_os (Linux ${p1_version})"
- fi
- if [ -n "$p2_os" ] && [ -n "$p2_version" ]; then
- p2_os="$p2_os (Linux ${p2_version})"
- fi
-
- json_init
- json_add_int 'current_partition' "$current_partition"
- json_add_string 'device_name' "$vendorName $deviceName"
- json_add_array 'partitions'
- json_add_object
- if [ "$bootEnv1Partition1Value" = "$current_partition" ]; then
- json_add_string 'state' "Current"
- else
- json_add_string 'state' "Alternative"
- fi
- json_add_string 'os' "$p1_os"
- json_add_int 'number' "$bootEnv1Partition1Value"
- json_close_object
- json_add_object
- if [ "$bootEnv1Partition2Value" = "$current_partition" ]; then
- json_add_string 'state' "Current"
- else
- json_add_string 'state' "Alternative"
- fi
- json_add_string 'os' "$p2_os"
- json_add_int 'number' "$bootEnv1Partition2Value"
- json_close_object
- json_close_array
- json_add_string 'rom_board_name' "$romBoardName"
- json_dump; json_cleanup;
-}
-
-toggle_boot_partition(){
- local zyxelFlagPartition i zyxelBootFlag zyxelNewBootFlag curEnvSetting newEnvSetting
- local romBoardName p
- local bev1 bev2 bev1p1 bev1p2 bev2p1 bev2p2
- local vendorName deviceName partition1MTD partition2MTD labelOffset
- local bootEnv1 bootEnv1Partition1Value bootEnv1Partition2Value
- local bootEnv2 bootEnv2Partition1Value bootEnv2Partition2Value
-
- romBoardName="$(cat /tmp/sysinfo/board_name)"
- if [ -z "$romBoardName" ]; then
- print_json 'error' 'NO_BOARD_NAME'
- return
- fi
-
- p="$(find_device_data "$romBoardName")"
- if [ -z "$p" ] || [ ! -s "$p" ]; then
- print_json 'rom_board_name' "$romBoardName"
- return
- fi
-
- json_load_file "$p"
- for i in vendorName deviceName partition1MTD partition2MTD labelOffset \
- bootEnv1 bootEnv1Partition1Value bootEnv1Partition2Value \
- bootEnv2 bootEnv2Partition1Value bootEnv2Partition2Value; do
- json_get_var $i "$i"
- done
- json_cleanup
-
- bev1="$bootEnv1"
- bev2="$bootEnv2"
-
- if [ -n "${bev1}${bev2}" ]; then # Linksys devices
- if [ -n "$bev1" ]; then
- curEnvSetting="$(fw_printenv -n "${bev1}")"
- if [ -z "$curEnvSetting" ]; then
- logger "$(printf "Unable to obtain firmware environment variable: %s." "$bev1")"
- json_init
- json_add_string 'error' 'NO_FIRM_ENV'
- json_add_array 'args'
- json_add_string "$bev1"
- json_close_array
- json_add_string 'rom_board_name' "$romBoardName"
- json_dump; json_cleanup;
- return
- else
- bev1p1="$bootEnv1Partition1Value"
- bev1p2="$bootEnv1Partition2Value"
- if [ "$curEnvSetting" = "$bev1p1" ]; then
- newEnvSetting="$bev1p2"
- else
- newEnvSetting="$bev1p1"
- fi
- if ! fw_setenv "$bev1" "$newEnvSetting"; then
- logger "$(printf "Unable to set firmware environment variable: %s to %s." "$bev1" "$newEnvSetting")"
- json_init
- json_add_string 'error' 'ERR_SET_ENV'
- json_add_array 'args'
- json_add_string "$bev1"
- json_add_string "$newEnvSetting"
- json_close_array
- json_add_string 'rom_board_name' "$romBoardName"
- json_dump; json_cleanup;
- return
- fi
- fi
- fi
- if [ -n "$bev2" ]; then
- curEnvSetting="$(fw_printenv -n "${bev2}")"
- if [ -z "$curEnvSetting" ]; then
- logger "$(printf "Unable to obtain firmware environment variable: %s." "$bev2")"
- json_init
- json_add_string 'error' 'NO_FIRM_ENV'
- json_add_array 'args'
- json_add_string "$bev2"
- json_close_array
- json_add_string 'rom_board_name' "$romBoardName"
- json_dump; json_cleanup;
- return
- else
- bev2p1="$bootEnv2Partition1Value"
- bev2p2="$bootEnv2Partition2Value"
- if [ "$curEnvSetting" = "$bev2p1" ]; then
- newEnvSetting="$bev2p2"
- else
- newEnvSetting="$bev2p1"
- fi
- if ! fw_setenv "$bev2" "$newEnvSetting"; then
- logger "$(printf "Unable to set firmware environment variable: %s to %s." "$bev2" "$newEnvSetting")"
- json_init
- json_add_string 'error' 'ERR_SET_ENV'
- json_add_array 'args'
- json_add_string "$bev2"
- json_add_string "$newEnvSetting"
- json_close_array
- json_add_string 'rom_board_name' "$romBoardName"
- json_dump >&4; json_cleanup;
- return
- fi
- fi
- fi
- json_init
- json_dump; json_cleanup;
- else # NetGear device
- for i in '0:dual_flag' '0:DUAL_FLAG'; do
- zyxelFlagPartition="$(find_mtd_part "$i" 2>/dev/null)"
- [ -n "$zyxelFlagPartition" ] && break
- done
- if [ -z "$zyxelFlagPartition" ]; then
- print_json 'error' 'NO_DUAL_FLAG'
- logger "Unable to find Dual Boot Environment or Dual Boot Flag Partition."
- return
- elif [ ! -b "$zyxelFlagPartition" ]; then
- print_json 'error' 'NO_DUAL_FLAG_BLOCK'
- logger "The Dual Boot Flag Partition: $zyxelFlagPartition is not block device."
- return
- else
- zyxelBootFlag="$(dd if="${zyxelFlagPartition}" bs=1 count=1 2>/dev/null | hexdump -n 1 -e '1/1 "%d"')"
- if [ "$zyxelBootFlag" = "1" ]; then
- zyxelNewBootFlag="\\xff"
- else
- zyxelNewBootFlag="\\x01"
- fi
- if [ -n "$zyxelNewBootFlag" ]; then
- if ! printf "%b" "$zyxelNewBootFlag" > "$zyxelFlagPartition"; then
- logger "$(printf "Unable to set Dual Boot Flag Partition entry for partition: %s." "$zyxelFlagPartition")"
- json_init
- json_add_string 'error' 'ERR_SET_DUAL_FLAG'
- json_add_array 'args'
- json_add_string "$zyxelFlagPartition"
- json_close_array
- json_add_string 'rom_board_name' "$romBoardName"
- json_dump; json_cleanup;
- return
- fi
- fi
- fi
- json_init
- json_dump >&4; json_cleanup;
- fi
-}
-
-case "$1" in
- list)
- json_init
- json_add_object "obtain_device_info"
- json_close_object
- json_add_object "toggle_boot_partition"
- json_close_object
- json_dump
- json_cleanup
- ;;
- call)
- case "$2" in
- obtain_device_info)
- obtain_device_info;;
- toggle_boot_partition)
- toggle_boot_partition;;
- esac
- ;;
-esac
{
- "vendorName": "Linksys",
- "deviceName": "EA9500",
- "boardName": "linksys-panamera",
- "partition1MTD": "mtd3",
- "partition2MTD": "mtd6",
- "labelOffset": 28,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
-}
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA9500",
+ "board": []
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [1],
+ "mtd": "mtd3",
+ "labelOffsetBytes": 28
+ },
+ {
+ "number": 2,
+ "param_values": [2],
+ "mtd": "mtd6",
+ "labelOffsetBytes": 28
+ }
+ ]
+}
\ No newline at end of file
{
- "vendorName": "Netgear",
- "deviceName": "WAC510",
- "boardNames": [ "netgear,wac510" ],
- "partition1MTD": "mtd9",
- "partition2MTD": "mtd10",
- "labelOffset": null,
- "bootEnv1": "primary",
- "bootEnv1Partition1Value": 0,
- "bootEnv1Partition2Value": 3800000,
- "bootEnv2": "secondary",
- "bootEnv2Partition1Value": 3800000,
- "bootEnv2Partition2Value": 0
+ "device": {
+ "vendor": "Netgear",
+ "model": "WAC510",
+ "board": [
+ "netgear,wac510"
+ ]
+ },
+ "commands": {
+ "params": [
+ "primary",
+ "secondary"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [0, 3800000],
+ "mtd": "mtd9",
+ "labelOffsetBytes": null
+ },
+ {
+ "number": 2,
+ "param_values": [3800000, 0],
+ "mtd": "mtd10",
+ "labelOffsetBytes": null
+ }
+ ]
}
--- /dev/null
+{
+ "device": {
+ "vendor": "Xiaomi",
+ "model": "AX3600",
+ "board": [
+ "xiaomi,ax3600"
+ ]
+ },
+ "commands": {
+ "params": [
+ "flag_boot_rootfs",
+ "flag_last_success"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 0,
+ 0
+ ],
+ "mtd": "mtd12",
+ "labelOffsetBytes": 266432
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 1,
+ 1
+ ],
+ "mtd": "mtd13",
+ "labelOffsetBytes": 266432
+ }
+ ]
+}
--- /dev/null
+{
+ "device": {
+ "vendor": "Xiaomi",
+ "model": "AX9000",
+ "board": [
+ "xiaomi,ax9000"
+ ]
+ },
+ "commands": {
+ "params": [
+ "flag_boot_rootfs",
+ "flag_last_success"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 0,
+ 0
+ ],
+ "mtd": "mtd20",
+ "labelOffsetBytes": 266432
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 1,
+ 1
+ ],
+ "mtd": "mtd21",
+ "labelOffsetBytes": 266432
+ }
+ ]
+}
--- /dev/null
+[
+ {
+ "device": {
+ "vendor": "D-Link",
+ "model": "DGS-1210-28",
+ "board": [
+ "d-link,dgs-1210-28"
+ ]
+ },
+ "commands": {
+ "params": [
+ "bootcmd",
+ "image"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [],
+ "mtd": "mtd5",
+ "labelOffsetBytes": null
+ },
+ {
+ "number": 2,
+ "param_values": [
+ "run addargs\\; bootm 0xb4e80000",
+ "/dev/mtdblock7"
+ ],
+ "mtd": "mtd9",
+ "labelOffsetBytes": null
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "E4200v2/EA4500",
+ "board": [
+ "linksys-viper",
+ "linksys,viper"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd3",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "E4200v2",
+ "board": [
+ "linksys-e4200v2",
+ "linksys,e4200-v2"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd3",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "E7350",
+ "board": [
+ "linksys,e7350"
+ ]
+ },
+ "commands": {
+ "params": [
+ "bootimage"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd3",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd6",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA3500",
+ "board": [
+ "linksys-audi",
+ "linksys,audi",
+ "linksys-ea3500",
+ "linksys,ea3500"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd3",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA4500",
+ "board": [
+ "linksys-ea4500",
+ "linksys,ea4500"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd3",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA6350v3",
+ "board": [
+ "linksys-ea6350v3",
+ "linksys,ea6350v3"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd10",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd12",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA6350v4",
+ "board": [
+ "linksys,ea6350-v4"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd7",
+ "labelOffsetBytes": 32
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA7300v1",
+ "board": [
+ "linksys,ea7300-v1"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd7",
+ "labelOffsetBytes": 32
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA7300v2",
+ "board": [
+ "linksys,ea7300-v2"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd7",
+ "labelOffsetBytes": 32
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA7500v1",
+ "board": [
+ "linksys,ea7500-v1"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd13",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd15",
+ "labelOffsetBytes": 32
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA7500v2",
+ "board": [
+ "linksys,ea7500-v2"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd7",
+ "labelOffsetBytes": 32
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA8100v1",
+ "board": [
+ "linksys,ea8100-v1"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd7",
+ "labelOffsetBytes": 32
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA8100v2",
+ "board": [
+ "linksys,ea8100-v2"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd7",
+ "labelOffsetBytes": 32
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA8300",
+ "board": [
+ "linksys-ea8300",
+ "linksys,ea8300"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd10",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd12",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA8500",
+ "board": [
+ "linksys-ea8500",
+ "linksys,ea8500"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd13",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd15",
+ "labelOffsetBytes": 32
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "MR5500",
+ "board": [
+ "linksys,mr5500"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd12",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd14",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "MR7350",
+ "board": [
+ "linksys,mr7350"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd14",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd16",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "MR7500",
+ "board": [
+ "linksys,mr7500"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd13",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd15",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "MR8300",
+ "board": [
+ "linksys-mr8300",
+ "linksys,mr8300"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd10",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd12",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "MR9000 (Dallas)",
+ "board": [
+ "linksys,mr9000"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd10",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd12",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "MX2000",
+ "board": [
+ "linksys,mx2000"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd12",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd14",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "MX4200v1",
+ "board": [
+ "linksys,mx4200v1"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd21",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd23",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "MX4200v2",
+ "board": [
+ "linksys,mx4200v2"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd21",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd23",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "MX4300",
+ "board": [
+ "linksys,mx4300"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd21",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd23",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "MX5300",
+ "board": [
+ "linksys,mx5300"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd21",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd23",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "MX5500",
+ "board": [
+ "linksys,mx5500"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd12",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd14",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "MX8500",
+ "board": [
+ "linksys,mx8500"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd21",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd23",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "SPNMX56",
+ "board": [
+ "linksys,spnmx56"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd12",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd14",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "WHW01 V1 (Velop)",
+ "board": [
+ "linksys,whw01"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd9",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd11",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "WHW03 (Velop)",
+ "board": [
+ "linksys,whw03"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mmcblk0p14",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mmcblk0p16",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "WHW03 V2 (Velop)",
+ "board": [
+ "linksys-whw03v2",
+ "linksys,whw03v2"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd9",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd11",
+ "labelOffsetBytes": 192
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "WRT1200AC",
+ "board": [
+ "linksys-caiman",
+ "linksys,caiman",
+ "linksys,wrt1200ac"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd4",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd6",
+ "labelOffsetBytes": 32
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "WRT1900ACv1",
+ "board": [
+ "linksys-mamba",
+ "linksys,mamba",
+ "linksys,wrt1900ac-v1"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd4",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd6",
+ "labelOffsetBytes": 32
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "WRT1900ACS",
+ "board": [
+ "linksys-shelby",
+ "linksys,shelby",
+ "linksys,wrt1900acs"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd4",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd6",
+ "labelOffsetBytes": 32
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "WRT1900ACv2",
+ "board": [
+ "linksys-cobra",
+ "linksys,cobra",
+ "linksys,wrt1900ac-v2"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd4",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd6",
+ "labelOffsetBytes": 32
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "WRT3200ACM",
+ "board": [
+ "linksys-rango",
+ "linksys,rango",
+ "linksys,wrt3200acm"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd7",
+ "labelOffsetBytes": 32
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Linksys",
+ "model": "WRT32X",
+ "board": [
+ "linksys-venom",
+ "linksys,venom",
+ "linksys,wrt32x"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": null
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd7",
+ "labelOffsetBytes": null
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "MERCUSYS",
+ "model": "MR90X v1",
+ "board": [
+ "mercusys,mr90x-v1"
+ ]
+ },
+ "commands": {
+ "params": [
+ "tp_boot_idx"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 0
+ ],
+ "mtd": "mtd2",
+ "labelOffsetBytes": null,
+ "altMountOptions": {
+ "mtdOffset": 0,
+ "ubiVolume": 2
+ }
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd3",
+ "labelOffsetBytes": null,
+ "altMountOptions": {
+ "mtdOffset": 0,
+ "ubiVolume": 2
+ }
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "Netgear",
+ "model": "GS308T v1",
+ "board": [
+ "netgear,gs308t-v1"
+ ]
+ },
+ "commands": {
+ "params": [
+ "bootpartition"
+ ],
+ "get": "fw_printsys",
+ "set": "fw_setsys",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 0
+ ],
+ "mtd": "mtd6",
+ "labelOffsetBytes": null
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd9",
+ "labelOffsetBytes": null
+ }
+ ]
+ },
+ {
+ "device": {
+ "vendor": "ZyXEL",
+ "model": "NBG6817",
+ "board": [
+ "nbg6817",
+ "zyxel,nbg6817"
+ ]
+ },
+ "commands": {
+ "params": [],
+ "get": null,
+ "set": null,
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ "ff"
+ ],
+ "mtd": "mmcblk0p4",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ "01"
+ ],
+ "mtd": "mmcblk0p7",
+ "labelOffsetBytes": 32
+ }
+ ]
+ }
+]
--- /dev/null
+# Tabs only for indentation, spaces ok in comments.
+
+# jq -f _device_json_transform.jq old.json
+# Transform from the old schema:
+# {
+# "vendorName": "...",
+# "deviceName": "...",
+# "boardNames": ["..."],
+# "partition1MTD": "mtdX",
+# "partition2MTD": "mtdY",
+# "labelOffset": 32,
+# "bootEnv1": "boot_part",
+# "bootEnv1Partition1Value": 1,
+# "bootEnv1Partition2Value": 2,
+# "bootEnv2": "bootcmd",
+# "bootEnv2Partition1Value": "run nandboot",
+# "bootEnv2Partition2Value": "run altnandboot",
+# "opOffset": 0,
+# "ubiVolume": 2
+# }
+#
+# …to the new schema:
+# {
+# "device": { "vendor": "...", "model": "...", "board": ["..."] },
+# "commands": { "params": [...], "get": "fw_printenv", "set": "fw_setenv", "save": null },
+# "partitions": [
+# { "number": 1, "param_values": [...], "mtd": "mtdX", "labelOffsetBytes": <int|null>, "altMountOptions": {...|null} },
+# { "number": 2, "param_values": [...], "mtd": "mtdY", "labelOffsetBytes": <int|null>, "altMountOptions": {...|null} }
+# ]
+# }
+
+. as $in
+| ([$in.bootEnv1, $in.bootEnv2] | map(select(. != null))) as $params
+| {
+ device: {
+ vendor: $in.vendorName,
+ model: $in.deviceName,
+ board: (if ($in.boardNames | type) == "array" then $in.boardNames else [$in.boardNames] end)
+ },
+ commands: {
+ params: $params,
+ get: "fw_printenv",
+ set: "fw_setenv",
+ save: null
+ },
+ partitions: [
+ (if $in.partition1MTD != null then
+ {
+ number: 1,
+ param_values: (
+ # Align to commands.params: value for param[0], param[1], ...
+ # Only include entries that exist (skip nulls)
+ [
+ (if ($params | length) > 0 then $in.bootEnv1Partition1Value else empty end),
+ (if ($params | length) > 1 then $in.bootEnv2Partition1Value else empty end)
+ ] | map(select(. != null))
+ ),
+ mtd: $in.partition1MTD,
+ labelOffsetBytes: ($in.labelOffset // null)
+ } + (
+ if ($in.opOffset != null or $in.ubiVolume != null) then
+ { altMountOptions: { mtdOffset: ($in.opOffset // null), ubiVolume: ($in.ubiVolume // null) } }
+ else
+ {}
+ end
+ )
+ else empty end),
+ (if $in.partition2MTD != null then
+ {
+ number: 2,
+ param_values: (
+ [
+ (if ($params | length) > 0 then $in.bootEnv1Partition2Value else empty end),
+ (if ($params | length) > 1 then $in.bootEnv2Partition2Value else empty end)
+ ] | map(select(. != null))
+ ),
+ mtd: $in.partition2MTD,
+ labelOffsetBytes: ($in.labelOffset // null)
+ } + (
+ if ($in.opOffset != null or $in.ubiVolume != null) then
+ { altMountOptions: { mtdOffset: ($in.opOffset // null), ubiVolume: ($in.ubiVolume // null) } }
+ else
+ {}
+ end
+ )
+ else empty end)
+ ]
+}
{
- "vendorName": "D-Link",
- "deviceName": "DGS-1210-28",
- "boardNames": [ "d-link,dgs-1210-28" ],
- "partition1MTD": "mtd5",
- "partition2MTD": "mtd9",
- "labelOffset": null,
- "bootEnv1": "bootcmd",
- "bootEnv1Partition1Value": null,
- "bootEnv1Partition2Value": "run addargs\\; bootm 0xb4e80000",
- "bootEnv2": "image",
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": "/dev/mtdblock7"
+ "device": {
+ "vendor": "D-Link",
+ "model": "DGS-1210-28",
+ "board": [
+ "d-link,dgs-1210-28"
+ ]
+ },
+ "commands": {
+ "params": [
+ "bootcmd",
+ "image"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [],
+ "mtd": "mtd5",
+ "labelOffsetBytes": null
+ },
+ {
+ "number": 2,
+ "param_values": [
+ "run addargs\\; bootm 0xb4e80000",
+ "/dev/mtdblock7"
+ ],
+ "mtd": "mtd9",
+ "labelOffsetBytes": null
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "E4200v2/EA4500",
- "boardNames": [ "linksys-viper", "linksys,viper" ],
- "partition1MTD": "mtd3",
- "partition2MTD": "mtd5",
- "labelOffset": 32,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": "bootcmd",
- "bootEnv2Partition1Value": "run nandboot",
- "bootEnv2Partition2Value": "run altnandboot"
+ "device": {
+ "vendor": "Linksys",
+ "model": "E4200v2/EA4500",
+ "board": [
+ "linksys-viper",
+ "linksys,viper"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd3",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "E4200v2",
- "boardNames": [
- "linksys-e4200v2",
- "linksys,e4200-v2"
- ],
- "partition1MTD": "mtd3",
- "partition2MTD": "mtd5",
- "labelOffset": 32,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": "bootcmd",
- "bootEnv2Partition1Value": "run nandboot",
- "bootEnv2Partition2Value": "run altnandboot"
+ "device": {
+ "vendor": "Linksys",
+ "model": "E4200v2",
+ "board": [
+ "linksys-e4200v2",
+ "linksys,e4200-v2"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd3",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "E7350",
- "boardNames": [ "linksys,e7350" ],
- "partition1MTD": "mtd3",
- "partition2MTD": "mtd6",
- "labelOffset": 192,
- "bootEnv1": "bootimage",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "E7350",
+ "board": [
+ "linksys,e7350"
+ ]
+ },
+ "commands": {
+ "params": [
+ "bootimage"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd3",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd6",
+ "labelOffsetBytes": 192
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "EA3500",
- "boardNames": [ "linksys-audi", "linksys,audi", "linksys-ea3500", "linksys,ea3500" ],
- "partition1MTD": "mtd3",
- "partition2MTD": "mtd5",
- "labelOffset": 32,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": "bootcmd",
- "bootEnv2Partition1Value": "run nandboot",
- "bootEnv2Partition2Value": "run altnandboot"
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA3500",
+ "board": [
+ "linksys-audi",
+ "linksys,audi",
+ "linksys-ea3500",
+ "linksys,ea3500"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd3",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ }
+ ]
}
-
{
- "vendorName": "Linksys",
- "deviceName": "EA4500",
- "boardNames": [ "linksys-ea4500", "linksys,ea4500" ],
- "partition1MTD": "mtd3",
- "partition2MTD": "mtd5",
- "labelOffset": 32,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": "bootcmd",
- "bootEnv2Partition1Value": "run nandboot",
- "bootEnv2Partition2Value": "run altnandboot"
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA4500",
+ "board": [
+ "linksys-ea4500",
+ "linksys,ea4500"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd3",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "EA6350v3",
- "boardNames": [ "linksys-ea6350v3", "linksys,ea6350v3" ],
- "partition1MTD": "mtd10",
- "partition2MTD": "mtd12",
- "labelOffset": 192,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA6350v3",
+ "board": [
+ "linksys-ea6350v3",
+ "linksys,ea6350v3"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd10",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd12",
+ "labelOffsetBytes": 192
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "EA6350v4",
- "boardNames": [ "linksys,ea6350-v4" ],
- "partition1MTD": "mtd5",
- "partition2MTD": "mtd7",
- "labelOffset": 32,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA6350v4",
+ "board": [
+ "linksys,ea6350-v4"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd7",
+ "labelOffsetBytes": 32
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "EA7300v1",
- "boardNames": [ "linksys,ea7300-v1" ],
- "partition1MTD": "mtd5",
- "partition2MTD": "mtd7",
- "labelOffset": 32,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": "bootcmd",
- "bootEnv2Partition1Value": "run nandboot",
- "bootEnv2Partition2Value": "run altnandboot"
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA7300v1",
+ "board": [
+ "linksys,ea7300-v1"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd7",
+ "labelOffsetBytes": 32
+ }
+ ]
}
-
{
- "vendorName": "Linksys",
- "deviceName": "EA7300v2",
- "boardNames": [ "linksys,ea7300-v2" ],
- "partition1MTD": "mtd5",
- "partition2MTD": "mtd7",
- "labelOffset": 32,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": "bootcmd",
- "bootEnv2Partition1Value": "run nandboot",
- "bootEnv2Partition2Value": "run altnandboot"
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA7300v2",
+ "board": [
+ "linksys,ea7300-v2"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd7",
+ "labelOffsetBytes": 32
+ }
+ ]
}
-
{
- "vendorName": "Linksys",
- "deviceName": "EA7500v1",
- "boardNames": [ "linksys,ea7500-v1" ],
- "partition1MTD": "mtd13",
- "partition2MTD": "mtd15",
- "labelOffset": 32,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA7500v1",
+ "board": [
+ "linksys,ea7500-v1"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd13",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd15",
+ "labelOffsetBytes": 32
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "EA7500v2",
- "boardNames": [ "linksys,ea7500-v2" ],
- "partition1MTD": "mtd5",
- "partition2MTD": "mtd7",
- "labelOffset": 32,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": "bootcmd",
- "bootEnv2Partition1Value": "run nandboot",
- "bootEnv2Partition2Value": "run altnandboot"
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA7500v2",
+ "board": [
+ "linksys,ea7500-v2"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd7",
+ "labelOffsetBytes": 32
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "EA8100v1",
- "boardNames": [ "linksys,ea8100-v1" ],
- "partition1MTD": "mtd5",
- "partition2MTD": "mtd7",
- "labelOffset": 32,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA8100v1",
+ "board": [
+ "linksys,ea8100-v1"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd7",
+ "labelOffsetBytes": 32
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "EA8100v2",
- "boardNames": [ "linksys,ea8100-v2" ],
- "partition1MTD": "mtd5",
- "partition2MTD": "mtd7",
- "labelOffset": 32,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA8100v2",
+ "board": [
+ "linksys,ea8100-v2"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd7",
+ "labelOffsetBytes": 32
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "EA8300",
- "boardNames": [ "linksys-ea8300", "linksys,ea8300" ],
- "partition1MTD": "mtd10",
- "partition2MTD": "mtd12",
- "labelOffset": 192,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA8300",
+ "board": [
+ "linksys-ea8300",
+ "linksys,ea8300"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd10",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd12",
+ "labelOffsetBytes": 192
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "EA8500",
- "boardNames": [ "linksys-ea8500", "linksys,ea8500" ],
- "partition1MTD": "mtd13",
- "partition2MTD": "mtd15",
- "labelOffset": 32,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "EA8500",
+ "board": [
+ "linksys-ea8500",
+ "linksys,ea8500"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd13",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd15",
+ "labelOffsetBytes": 32
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "MR5500",
- "boardNames": [ "linksys,mr5500" ],
- "partition1MTD": "mtd12",
- "partition2MTD": "mtd14",
- "labelOffset": 192,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "MR5500",
+ "board": [
+ "linksys,mr5500"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd12",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd14",
+ "labelOffsetBytes": 192
+ }
+ ]
}
{
- "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
-}
\ No newline at end of file
+ "device": {
+ "vendor": "Linksys",
+ "model": "MR7350",
+ "board": [
+ "linksys,mr7350"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd14",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd16",
+ "labelOffsetBytes": 192
+ }
+ ]
+}
{
- "vendorName": "Linksys",
- "deviceName": "MR7500",
- "boardNames": [ "linksys,mr7500" ],
- "partition1MTD": "mtd13",
- "partition2MTD": "mtd15",
- "labelOffset": 192,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "MR7500",
+ "board": [
+ "linksys,mr7500"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd13",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd15",
+ "labelOffsetBytes": 192
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "MR8300",
- "boardNames": [ "linksys-mr8300", "linksys,mr8300" ],
- "partition1MTD": "mtd10",
- "partition2MTD": "mtd12",
- "labelOffset": 192,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "MR8300",
+ "board": [
+ "linksys-mr8300",
+ "linksys,mr8300"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd10",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd12",
+ "labelOffsetBytes": 192
+ }
+ ]
}
--- /dev/null
+{
+ "device": {
+ "vendor": "Linksys",
+ "model": "MR9000 (Dallas)",
+ "board": [
+ "linksys,mr9000"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd10",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd12",
+ "labelOffsetBytes": 192
+ }
+ ]
+}
{
- "vendorName": "Linksys",
- "deviceName": "MX2000",
- "boardNames": [ "linksys,mx2000" ],
- "partition1MTD": "mtd12",
- "partition2MTD": "mtd14",
- "labelOffset": 192,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "MX2000",
+ "board": [
+ "linksys,mx2000"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd12",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd14",
+ "labelOffsetBytes": 192
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "MX4200v1",
- "boardNames": [ "linksys,mx4200v1" ],
- "partition1MTD": "mtd21",
- "partition2MTD": "mtd23",
- "labelOffset": 192,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "MX4200v1",
+ "board": [
+ "linksys,mx4200v1"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd21",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd23",
+ "labelOffsetBytes": 192
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "MX4200v2",
- "boardNames": [ "linksys,mx4200v2" ],
- "partition1MTD": "mtd21",
- "partition2MTD": "mtd23",
- "labelOffset": 192,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "MX4200v2",
+ "board": [
+ "linksys,mx4200v2"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd21",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd23",
+ "labelOffsetBytes": 192
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "MX4300",
- "boardNames": [ "linksys,mx4300" ],
- "partition1MTD": "mtd21",
- "partition2MTD": "mtd23",
- "labelOffset": 192,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "MX4300",
+ "board": [
+ "linksys,mx4300"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd21",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd23",
+ "labelOffsetBytes": 192
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "MX5300",
- "boardNames": [ "linksys,mx5300" ],
- "partition1MTD": "mtd21",
- "partition2MTD": "mtd23",
- "labelOffset": 192,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "MX5300",
+ "board": [
+ "linksys,mx5300"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd21",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd23",
+ "labelOffsetBytes": 192
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "MX5500",
- "boardNames": [ "linksys,mx5500" ],
- "partition1MTD": "mtd12",
- "partition2MTD": "mtd14",
- "labelOffset": 192,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "MX5500",
+ "board": [
+ "linksys,mx5500"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd12",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd14",
+ "labelOffsetBytes": 192
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "MX8500",
- "boardNames": [ "linksys,mx8500" ],
- "partition1MTD": "mtd21",
- "partition2MTD": "mtd23",
- "labelOffset": 192,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "MX8500",
+ "board": [
+ "linksys,mx8500"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd21",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd23",
+ "labelOffsetBytes": 192
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "SPNMX56",
- "boardNames": [ "linksys,spnmx56" ],
- "partition1MTD": "mtd12",
- "partition2MTD": "mtd14",
- "labelOffset": 192,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "SPNMX56",
+ "board": [
+ "linksys,spnmx56"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd12",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd14",
+ "labelOffsetBytes": 192
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "WHW01 V1 (Velop)",
- "boardNames": [ "linksys,whw01" ],
- "partition1MTD": "mtd9",
- "partition2MTD": "mtd11",
- "labelOffset": 192,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "WHW01 V1 (Velop)",
+ "board": [
+ "linksys,whw01"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd9",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd11",
+ "labelOffsetBytes": 192
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "WHW03 (Velop)",
- "boardNames": [ "linksys,whw03" ],
- "partition1MTD": "mmcblk0p14",
- "partition2MTD": "mmcblk0p16",
- "labelOffset": 192,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "WHW03 (Velop)",
+ "board": [
+ "linksys,whw03"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mmcblk0p14",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mmcblk0p16",
+ "labelOffsetBytes": 192
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "WHW03 V2 (Velop)",
- "boardNames": [ "linksys-whw03v2", "linksys,whw03v2" ],
- "partition1MTD": "mtd9",
- "partition2MTD": "mtd11",
- "labelOffset": 192,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "Linksys",
+ "model": "WHW03 V2 (Velop)",
+ "board": [
+ "linksys-whw03v2",
+ "linksys,whw03v2"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd9",
+ "labelOffsetBytes": 192
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2
+ ],
+ "mtd": "mtd11",
+ "labelOffsetBytes": 192
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "WRT1200AC",
- "boardNames": [ "linksys-caiman", "linksys,caiman", "linksys,wrt1200ac" ],
- "partition1MTD": "mtd4",
- "partition2MTD": "mtd6",
- "labelOffset": 32,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": "bootcmd",
- "bootEnv2Partition1Value": "run nandboot",
- "bootEnv2Partition2Value": "run altnandboot"
+ "device": {
+ "vendor": "Linksys",
+ "model": "WRT1200AC",
+ "board": [
+ "linksys-caiman",
+ "linksys,caiman",
+ "linksys,wrt1200ac"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd4",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd6",
+ "labelOffsetBytes": 32
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "WRT1900ACv1",
- "boardNames": [ "linksys-mamba", "linksys,mamba", "linksys,wrt1900ac-v1" ],
- "partition1MTD": "mtd4",
- "partition2MTD": "mtd6",
- "labelOffset": 32,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": "bootcmd",
- "bootEnv2Partition1Value": "run nandboot",
- "bootEnv2Partition2Value": "run altnandboot"
+ "device": {
+ "vendor": "Linksys",
+ "model": "WRT1900ACv1",
+ "board": [
+ "linksys-mamba",
+ "linksys,mamba",
+ "linksys,wrt1900ac-v1"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd4",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd6",
+ "labelOffsetBytes": 32
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "WRT1900ACS",
- "boardNames": [ "linksys-shelby", "linksys,shelby", "linksys,wrt1900acs" ],
- "partition1MTD": "mtd4",
- "partition2MTD": "mtd6",
- "labelOffset": 32,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": "bootcmd",
- "bootEnv2Partition1Value": "run nandboot",
- "bootEnv2Partition2Value": "run altnandboot"
+ "device": {
+ "vendor": "Linksys",
+ "model": "WRT1900ACS",
+ "board": [
+ "linksys-shelby",
+ "linksys,shelby",
+ "linksys,wrt1900acs"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd4",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd6",
+ "labelOffsetBytes": 32
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "WRT1900ACv2",
- "boardNames": [ "linksys-cobra", "linksys,cobra", "linksys,wrt1900ac-v2" ],
- "partition1MTD": "mtd4",
- "partition2MTD": "mtd6",
- "labelOffset": 32,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": "bootcmd",
- "bootEnv2Partition1Value": "run nandboot",
- "bootEnv2Partition2Value": "run altnandboot"
+ "device": {
+ "vendor": "Linksys",
+ "model": "WRT1900ACv2",
+ "board": [
+ "linksys-cobra",
+ "linksys,cobra",
+ "linksys,wrt1900ac-v2"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd4",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd6",
+ "labelOffsetBytes": 32
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "WRT3200ACM",
- "boardNames": [ "linksys-rango", "linksys,rango", "linksys,wrt3200acm" ],
- "partition1MTD": "mtd5",
- "partition2MTD": "mtd7",
- "labelOffset": 32,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": "bootcmd",
- "bootEnv2Partition1Value": "run nandboot",
- "bootEnv2Partition2Value": "run altnandboot"
+ "device": {
+ "vendor": "Linksys",
+ "model": "WRT3200ACM",
+ "board": [
+ "linksys-rango",
+ "linksys,rango",
+ "linksys,wrt3200acm"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd7",
+ "labelOffsetBytes": 32
+ }
+ ]
}
{
- "vendorName": "Linksys",
- "deviceName": "WRT32X",
- "boardNames": [ "linksys-venom", "linksys,venom", "linksys,wrt32x" ],
- "partition1MTD": "mtd5",
- "partition2MTD": "mtd7",
- "labelOffset": null,
- "bootEnv1": "boot_part",
- "bootEnv1Partition1Value": 1,
- "bootEnv1Partition2Value": 2,
- "bootEnv2": "bootcmd",
- "bootEnv2Partition1Value": "run nandboot",
- "bootEnv2Partition2Value": "run altnandboot"
+ "device": {
+ "vendor": "Linksys",
+ "model": "WRT32X",
+ "board": [
+ "linksys-venom",
+ "linksys,venom",
+ "linksys,wrt32x"
+ ]
+ },
+ "commands": {
+ "params": [
+ "boot_part",
+ "bootcmd"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 1,
+ "run nandboot"
+ ],
+ "mtd": "mtd5",
+ "labelOffsetBytes": null
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 2,
+ "run altnandboot"
+ ],
+ "mtd": "mtd7",
+ "labelOffsetBytes": null
+ }
+ ]
}
{
- "vendorName": "MERCUSYS",
- "deviceName": "MR90X v1",
- "boardNames": [ "mercusys,mr90x-v1" ],
- "partition1MTD": "mtd2",
- "partition2MTD": "mtd3",
- "opOffset": 0,
- "ubiVolume": 2,
- "labelOffset": null,
- "bootEnv1": "tp_boot_idx",
- "bootEnv1Partition1Value": 0,
- "bootEnv1Partition2Value": 1,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "MERCUSYS",
+ "model": "MR90X v1",
+ "board": [
+ "mercusys,mr90x-v1"
+ ]
+ },
+ "commands": {
+ "params": [
+ "tp_boot_idx"
+ ],
+ "get": "fw_printenv",
+ "set": "fw_setenv",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 0
+ ],
+ "mtd": "mtd2",
+ "labelOffsetBytes": null,
+ "altMountOptions": {
+ "mtdOffset": 0,
+ "ubiVolume": 2
+ }
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd3",
+ "labelOffsetBytes": null,
+ "altMountOptions": {
+ "mtdOffset": 0,
+ "ubiVolume": 2
+ }
+ }
+ ]
}
--- /dev/null
+{
+ "device": {
+ "vendor": "Netgear",
+ "model": "GS308T v1",
+ "board": [
+ "netgear,gs308t-v1"
+ ]
+ },
+ "commands": {
+ "params": [
+ "bootpartition"
+ ],
+ "get": "fw_printsys",
+ "set": "fw_setsys",
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ 0
+ ],
+ "mtd": "mtd6",
+ "labelOffsetBytes": null
+ },
+ {
+ "number": 2,
+ "param_values": [
+ 1
+ ],
+ "mtd": "mtd9",
+ "labelOffsetBytes": null
+ }
+ ]
+}
+++ /dev/null
-{
- "vendorName": "Xiaomi",
- "deviceName": "AX3600",
- "boardNames": [ "xiaomi,ax3600" ],
- "partition1MTD": "mtd12",
- "partition2MTD": "mtd13",
- "labelOffset": 266432,
- "bootEnv1": "flag_boot_rootfs",
- "bootEnv1Partition1Value": 0,
- "bootEnv1Partition2Value": 1,
- "bootEnv2": "flag_last_success",
- "bootEnv2Partition1Value": 0,
- "bootEnv2Partition2Value": 1
-}
+++ /dev/null
-{
- "vendorName": "Xiaomi",
- "deviceName": "AX9000",
- "boardNames": [ "xiaomi,ax9000" ],
- "partition1MTD": "mtd20",
- "partition2MTD": "mtd21",
- "labelOffset": 266432,
- "bootEnv1": "flag_boot_rootfs",
- "bootEnv1Partition1Value": 0,
- "bootEnv1Partition2Value": 1,
- "bootEnv2": "flag_last_success",
- "bootEnv2Partition1Value": 0,
- "bootEnv2Partition2Value": 1
-}
{
- "vendorName": "ZyXEL",
- "deviceName": "NBG6817",
- "boardNames": [ "nbg6817", "zyxel,nbg6817" ],
- "partition1MTD": "mmcblk0p4",
- "partition2MTD": "mmcblk0p7",
- "labelOffset": 32,
- "bootEnv1": null,
- "bootEnv1Partition1Value": 255,
- "bootEnv1Partition2Value": 1,
- "bootEnv2": null,
- "bootEnv2Partition1Value": null,
- "bootEnv2Partition2Value": null
+ "device": {
+ "vendor": "ZyXEL",
+ "model": "NBG6817",
+ "board": [
+ "nbg6817",
+ "zyxel,nbg6817"
+ ]
+ },
+ "commands": {
+ "params": [],
+ "get": null,
+ "set": null,
+ "save": null
+ },
+ "partitions": [
+ {
+ "number": 1,
+ "param_values": [
+ "ff"
+ ],
+ "mtd": "mmcblk0p4",
+ "labelOffsetBytes": 32
+ },
+ {
+ "number": 2,
+ "param_values": [
+ "01"
+ ],
+ "mtd": "mmcblk0p7",
+ "labelOffsetBytes": 32
+ }
+ ]
}
{
- "admin/system/advanced_reboot": {
+ "admin/system/advanced-reboot": {
"title": "Advanced Reboot",
"order": 90,
"action": {
"type": "view",
- "path": "system/advanced_reboot"
+ "path": "system/advanced-reboot"
},
"depends": {
"acl": [ "luci-app-advanced-reboot" ]
{
"luci-app-advanced-reboot": {
- "description": "Grant UCI and file access for luci-app-advanced-reboot",
+ "description": "Grant file access for luci-app-advanced-reboot",
"read": {
"ubus": {
- "luci.advanced_reboot": [ "obtain_device_info", "toggle_boot_partition" ],
+ "luci.advanced-reboot": [ "obtain_device_info", "boot_partition" ],
"system": [ "reboot" ]
},
"file": {
- "/usr/sbin/fw_printenv": [ "list" ],
- "/usr/sbin/fw_setenv": [ "list" ],
- "/sbin/poweroff": [ "list", "exec" ]
+ "/bin/dd": [ "list", "exec" ],
+ "/bin/grep": [ "list", "exec" ],
+ "/bin/mount": [ "list", "exec" ],
+ "/bin/sed": [ "list", "exec" ],
+ "/bin/sh": [ "list", "exec" ],
+ "/bin/umount": [ "list", "exec" ],
+ "/bin/uname": [ "list", "exec" ],
+ "/etc/os-release": [ "read" ],
+ "/lib/functions.sh": [ "read" ],
+ "/proc/mounts": [ "read" ],
+ "/proc/version": [ "read" ],
+ "/sbin/poweroff": [ "list", "exec" ],
+ "/tmp/sysinfo/board_name": [ "read" ],
+ "/usr/bin/hexdump": [ "list", "exec" ],
+ "/usr/bin/logger": [ "list", "exec" ],
+ "/usr/bin/printf": [ "list", "exec" ],
+ "/usr/bin/tr": [ "list", "exec" ],
+ "/usr/sbin/fw_printenv": [ "list", "exec" ],
+ "/usr/sbin/fw_printsys": [ "list", "exec" ],
+ "/usr/sbin/fw_setenv": [ "list", "exec" ],
+ "/usr/sbin/fw_setsys": [ "list", "exec" ],
+ "/usr/sbin/ubiblock": [ "list", "exec" ],
+ "/usr/sbin/ubiattach": [ "list", "exec" ],
+ "/usr/sbin/ubidetach": [ "list", "exec" ]
}
}
}
--- /dev/null
+/* luci.advanced-reboot.uc — ucode port of luci.advanced-reboot
+ * Copyright 2025-2026 MOSSDeF, Stan Grishin (stangri@melmac.ca)
+ *
+ * Exposes ubus object: luci.advanced-reboot
+ * Methods:
+ * - obtain_device_info
+ * - boot_partition
+ * Tests:
+ * ubus -v list luci.advanced-reboot
+ * ubus -S call luci.advanced-reboot obtain_device_info
+ * ubus -S call luci.advanced-reboot boot_partition '{ "number": "1" }'
+ * ubus -S call luci.advanced-reboot boot_partition '{ "number": "2" }'
+ *
+ * Schema for device JSON files (new):
+ * {
+ * "device": { "vendor": "Vendor", "model": "Model", "board": ["vendor,model"] },
+ * "commands": {
+ * "params": ["<env1>", "<env2>"],
+ * "get": "fw_printenv",
+ * "set": "fw_setenv",
+ * "save": null
+ * },
+ * "partitions": [
+ * { "number": 1, "param_values": [v1, w1], "mtd": "mtdX", "labelOffsetBytes": <int|null>, "altMountOptions": { "mtdOffset": <int>, "ubiVolume": <int> } },
+ * { "number": 2, "param_values": [v2, w2], "mtd": "mtdY", "labelOffsetBytes": <int|null> }
+ * ]
+ * }
+ *
+ * Notes:
+ * - `altMountOptions` is optional; when absent, defaults are mtdOffset=1, ubiVolume=0.
+ * - `param_values[i]` aligns with `commands.params[i]`.
+ */
+
+"use strict";
+
+import * as fs from "fs";
+let DEVICES_DIR = "/usr/share/advanced-reboot/devices/";
+let DEVICES_JSON = "/usr/share/advanced-reboot/devices.json";
+
+function file_exists(p) {
+ try {
+ return fs.stat(p) != null;
+ } catch (e) {
+ return false;
+ }
+}
+
+function shellquote(s) {
+ return `'${replace(s ?? "", "'", "'\\''")}'`;
+}
+
+function command(cmd) {
+ return trim(fs.popen(cmd)?.read?.("all"));
+}
+
+function log(msg) {
+ command("logger -t advanced-reboot -- " + shellquote("" + msg));
+}
+
+/* Check whether an executable is available on PATH.
+ *
+ * @param {String} name Program name (e.g., "ubus").
+ * @returns {Boolean} true if found (exit 0), false otherwise.
+ */
+function has_cmd(name) {
+ let r = command("command -v " + name + " >/dev/null 2>&1; echo $?");
+ return r == "0";
+}
+
+/* Read the current board identifier.
+ *
+ * Source: /tmp/sysinfo/board_name produced by procd.
+ *
+ * @returns {String|null} Board name (e.g., "linksys,mx4200") or null if missing.
+ */
+function get_board_name() {
+ return trim(fs.readfile("/tmp/sysinfo/board_name"));
+}
+
+/* Locate the device descriptor matching a given board name.
+ *
+ * Tries the consolidated devices.json first, then falls back to per-file *.json
+ * in /usr/share/advanced-reboot/devices/.
+ *
+ * @param {String} romBoardName Value from /tmp/sysinfo/board_name.
+ * @returns {Object|null} Device object with {device, commands, partitions} or null.
+ */
+function find_device_info(romBoardName) {
+ let rb = trim(romBoardName ?? "");
+
+ // Read one big JSON file instead of many small ones
+ let txt = fs.readfile(DEVICES_JSON);
+ if (!txt) return null;
+
+ // devices.json : [ { device: {...} }, { device: {...} }, ... ]
+ let arr = json(txt);
+ if (!arr || type(arr) != "array") return null;
+
+ // Loop over each object in the array
+ for (let obj in arr) {
+ if (!obj || !obj.device) continue;
+
+ let boards = obj.device.board;
+ if (!boards) continue;
+
+ // normalise to array
+ if (type(boards) != "array") boards = ["" + boards];
+
+ for (let i = 0; i < length(boards); i++) {
+ let s = "" + boards[i];
+ if (s == rb) return obj;
+ }
+ }
+ // Fallback: old schema with many small files
+ let list = fs.glob(DEVICES_DIR + "*.json");
+ for (let f in list) {
+ let ftxt = fs.readfile(f);
+ if (!ftxt) continue;
+ let obj = json(ftxt);
+ if (!obj || !obj.device) continue;
+ let boards = obj.device.board;
+ if (!boards) continue;
+ if (type(boards) != "array") boards = ["" + boards];
+ for (let i = 0; i < length(boards); i++) {
+ let s = "" + boards[i];
+ if (s == rb) return obj;
+ }
+ }
+ return null;
+}
+
+/* Convert an mtd name like "mtd5" to its numeric index (5).
+ *
+ * @param {String} mtdName
+ * @returns {Number|null} Parsed index or null for invalid input.
+ */
+function mtd_index(mtdName) {
+ let m = match("" + mtdName, /^mtd([0-9]+)/);
+ if (m && m[1]) {
+ let n = int(m[1]);
+ return n == n ? n : null;
+ }
+ return null;
+}
+
+/* Read OS label and (optionally) kernel version from a root path.
+ *
+ * Reads PRETTY_NAME from etc/os-release; normalizes snapshot labels using
+ * /etc/openwrt_release if present. When path=="/", also extracts kernel
+ * version from /proc/version (or uname -r).
+ *
+ * @param {String} path Root of the filesystem to inspect ("/" or mount point).
+ * @returns {{label:String|null, os:String|null}}
+ */
+function get_volume_info(path) {
+ let root = path ?? "/";
+ /* ensure trailing slash exactly once */
+ if (!match(root, /\/$/)) root = root + "/";
+
+ let label;
+ let pretty = command(
+ ". " +
+ shellquote(root + "etc/os-release") +
+ ' 2>/dev/null; echo "$PRETTY_NAME" 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 == "/") {
+ let pv = fs.readfile("/proc/version");
+ if (pv) {
+ let m = match(pv, /^Linux version ([^ ]+)/);
+ if (m && m[1]) kver = m[1];
+ }
+ if (!kver) {
+ let r = command("uname -r 2>/dev/null");
+ if (r) kver = r;
+ }
+ }
+ return { label: label == "" ? null : label, os: kver };
+}
+
+/* Convenience wrapper to get volume info for the current rootfs.
+ *
+ * @returns {{label:String|null, os:String|null}}
+ */
+function get_partition_info_current() {
+ return get_volume_info("/");
+}
+
+/* Determine if an alternate partition can be mounted.
+ *
+ * Requires: ubiattach, ubiblock, and mount commands available.
+ * Expects the `partitions` arg to be an array of mtd names (e.g., ["mtd5"]).
+ *
+ * @param {Array} partitions
+ * @returns {Boolean} true if tooling is present and input looks like mtd names.
+ */
+function is_alt_mountable(partitions) {
+ if (!partitions || type(partitions) != "array") return false;
+ for (let i = 0; i < length(partitions); i++) {
+ if (!match("" + partitions[i], /^mtd/)) return false;
+ }
+ return has_cmd("ubiattach") && has_cmd("ubiblock") && has_cmd("mount");
+}
+
+/* Attach a UBI MTD device and mount an alternative root read-only.
+ *
+ * Mount point: /var/alt_rom
+ *
+ * @param {Number|String} op_ubi UBI mtd index to attach (e.g., 6).
+ * @param {Number|String} ubi_vol UBI volume index (default 0).
+ * @returns {Boolean} true if mounted successfully, false otherwise.
+ * @sideeffects Creates/removes /var/alt_rom; calls ubiattach/ubiblock/mount.
+ */
+function alt_partition_mount(op_ubi, ubi_vol) {
+ log(
+ "attempting to mount alternative partition: UBI=" +
+ op_ubi +
+ ", Volume=" +
+ ubi_vol
+ );
+ log("ignore kernel messages below");
+ command("mkdir -p /var/alt_rom");
+ command("umount /var/alt_rom");
+ command("ubidetach -m " + op_ubi + " >/dev/null 2>&1");
+ let out = command(
+ "ubiattach -m " +
+ op_ubi +
+ " 2>/dev/null | sed -n 's/^UBI device number\\s*\\([0-9]*\\),.*$/\\1/p'"
+ );
+ log("mounted alternative partition UBI device number: " + out);
+ let dev = out && length(out) ? int(out) : null;
+ if (dev == null) {
+ command("ubidetach -m " + op_ubi + " >/dev/null 2>&1");
+ return false;
+ }
+ let vol = ubi_vol == null ? 0 : int(ubi_vol);
+ let blk = "/dev/ubiblock" + dev + "_" + vol;
+ command("ubiblock --create /dev/ubi" + dev + "_" + vol + " >/dev/null 2>&1");
+ let rc = command(
+ "mount -t squashfs -r " + blk + " /var/alt_rom >/dev/null 2>&1; echo $?"
+ );
+ return rc == "0";
+}
+
+/* Unmount and detach any UBI devices associated with a given MTD index.
+ *
+ * Also removes possible ubiblock nodes for the device.
+ *
+ * @param {Number|String} op_ubi UBI mtd index previously attached.
+ * @param {Number|String} ubi_vol UBI volume index (ignored during cleanup).
+ * @returns {void}
+ * @sideeffects umounts /var/alt_rom, ubidetach, removes ubiblock nodes.
+ */
+function alt_partition_unmount(op_ubi, ubi_vol) {
+ let mtdCount = command(
+ 'ubinfo | grep "Present UBI devices" | tr "," "\\n" | grep -c "ubi"'
+ );
+ mtdCount = int(mtdCount) || 10;
+ command("umount /var/alt_rom");
+ for (let i = 0; i <= mtdCount; i++) {
+ let mtd = fs.readfile("/sys/devices/virtual/ubi/ubi" + i + "/mtd_num");
+ if (!mtd) break;
+ mtd = trim(mtd);
+ if (mtd == "" + op_ubi) {
+ /* remove any ubiblock nodes on this ubi dev */
+ for (let vid = 0; vid < 16; vid++)
+ command(
+ "ubiblock --remove /dev/ubi" + i + "_" + vid + " >/dev/null 2>&1"
+ );
+ command("ubidetach -m " + op_ubi + " >/dev/null 2>&1");
+ command("rm -rf /var/alt_rom");
+ }
+ }
+}
+
+/* Get label/OS info from an alternative partition, using UBI mount flow.
+ *
+ * Falls back to {label:null, os:null} if mount fails.
+ *
+ * @param {Number|String} op_ubi UBI mtd index to attach.
+ * @param {String|null} vendor_name Vendor string (currently unused here).
+ * @param {Number|String} ubi_vol UBI volume index (default 0).
+ * @returns {{label:String|null, os:String|null}}
+ */
+function get_partition_info_alt(op_ubi, vendor_name, ubi_vol) {
+ let mounted = alt_partition_mount(op_ubi, ubi_vol);
+ if (mounted) {
+ /* Read info from mounted alt root */
+ let info = get_volume_info("/var/alt_rom/");
+ alt_partition_unmount(op_ubi, ubi_vol);
+ return info ?? { label: null, os: null };
+ } else {
+ alt_partition_unmount(op_ubi, ubi_vol);
+ }
+ return { label: null, os: null };
+}
+
+/* Fallback: probe an MTD partition directly for label/kernel hints.
+ *
+ * Uses `dd` to read bytes at labelOffset and inspects for OpenWrt/vendor tokens
+ * and kernel version strings.
+ *
+ * @param {String} mtd MTD name (e.g., "mtd9").
+ * @param {Number} offset Byte offset of label within the partition.
+ * @param {String|null} vendor Vendor label to look for.
+ * @returns {{label:String|null, os:String|null}}
+ */
+function get_partition_info_fallback(mtd, offset, vendor) {
+ let label;
+ let os;
+ let tag = command("dd if=/dev/" + mtd + " bs=1 skip=" + offset + " count=64");
+ if (tag) {
+ let m1 = match(tag, /Linux version ([^ \n]+)/);
+ if (m1 && m1[1]) os = m1[1];
+ else {
+ let m2 = match(tag, /Linux-([0-9.]+)/);
+ if (m2 && m2[1]) os = m2[1];
+ }
+ if (match(tag, /OpenWrt/)) {
+ label = "OpenWrt";
+ } else if (vendor && vendor != "" && match(tag, regexp(vendor))) {
+ label = vendor;
+ } else {
+ label = "Unknown";
+ }
+ } else {
+ label = vendor ? vendor + " (Compressed)" : "Unknown (Compressed)";
+ }
+ return { label: label, os: os };
+}
+
+function read_dual_flag_mtd() {
+ for (let name in ["0:dual_flag", "0:DUAL_FLAG"]) {
+ let dev = command(". /lib/functions.sh; find_mtd_part " + shellquote(name));
+ if (dev) return dev;
+ }
+ return null;
+}
+
+/* Read the single-byte dual-boot flag value from a block device.
+ *
+ * @param {String} dev Path to the block (e.g., /dev/mtdX) returned by find_mtd_part.
+ * @returns {String|null} Lowercase hex byte (e.g., "00", "01") or null on error.
+ */
+function read_dual_flag_value(dev) {
+ if (!dev || dev == "" || !file_exists(dev)) return null;
+ let r = command(
+ "dd if=" +
+ shellquote(dev) +
+ " bs=1 count=1 2>/dev/null | hexdump -n 1 -e '" +
+ '1/1 "%02x"' +
+ "'"
+ );
+ return r || null;
+}
+
+/* Write a single-byte dual-boot flag value to a block device.
+ *
+ * @param {String} dev Device path (e.g., /dev/mtdX).
+ * @param {String} cur Hex byte without prefix (e.g., "01"); will be written as \\x01.
+ * @returns {Boolean} true if write succeeded, false otherwise.
+ * @sideeffects Overwrites one byte on the target device.
+ */
+function write_dual_flag_value(dev, cur) {
+ cur = "\\x" + cur;
+ let rc = command(
+ "printf %b " +
+ shellquote(cur) +
+ " > " +
+ shellquote(dev) +
+ " 2>/dev/null; echo $?"
+ );
+ return rc == "0";
+}
+
+/* Gather device and partition information for UI/RPC.
+ *
+ * Detects active partition, attempts to label both current and alternate
+ * partitions via UBI mount (if supported) with a raw-label fallback.
+ *
+ * @returns {{
+ * device:{vendor:String, model:String, board:String, partition_active:String|null},
+ * partitions:Array<{number:String,label:String|null,os:String|null,mtd:String|null}>
+ * }} or {error:String,...} on failure.
+ */
+function obtain_device_info() {
+ let board = get_board_name();
+ if (!board) return { error: "NO_BOARD_NAME" };
+
+ let d = find_device_info(board);
+ if (!d) return { error: "NO_BOARD_NAME_MATCH", rom_board_name: board };
+
+ /* parse new-schema device object */
+ let dev = d.device ?? {};
+ let cmds = d.commands ?? {};
+ let parts = d.partitions && type(d.partitions) == "array" ? d.partitions : [];
+ let getcmd = cmds.get ?? "fw_printenv";
+ let active_num = null;
+
+ /* read current values for all params */
+ let curvals = [];
+
+ if (cmds.params && type(cmds.params) == "array" && length(cmds.params) > 0) {
+ for (let i = 0; i < length(cmds.params); i++) {
+ let p = cmds.params[i];
+ let v = null;
+ if (p)
+ v = command(getcmd + " -n " + shellquote(p) + " 2>/dev/null") || null;
+ push(curvals, v);
+ }
+ } else {
+ let df = read_dual_flag_mtd();
+ let v = null;
+ 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 };
+ v = read_dual_flag_value(df);
+ push(curvals, v);
+ }
+
+ let out_parts = [];
+ for (let i = 0; i < length(parts); i++) {
+ let p = parts[i] ?? {};
+ let num = p.number != null ? p.number : i;
+ let mtd = p.mtd ?? null;
+ let info = {};
+ let v;
+
+ if ("" + curvals[0] == "" + p.param_values[0]) {
+ /* current partition */
+ active_num = num;
+ info = get_partition_info_current();
+ } else if (mtd && is_alt_mountable([mtd])) {
+ /* attempt alt mount if we have mount options (or defaults) and tools */
+ let amo = p.altMountOptions ?? {};
+ let mtdOff = amo.mtdOffset == null ? 1 : int(amo.mtdOffset);
+ let ubiVol = amo.ubiVolume == null ? 0 : int(amo.ubiVolume);
+ let idx = mtd_index(mtd);
+ if (idx != null) {
+ let op_ubi = idx + mtdOff;
+ info = get_partition_info_alt(op_ubi, dev.vendor ?? null, ubiVol);
+ if (info && info.label == null && info.os == null) info = {};
+ }
+ }
+ /* raw-label fallback if needed */
+ if (mtd && p.labelOffsetBytes != null) {
+ if (!info?.label || !info?.os) {
+ let fb = get_partition_info_fallback(
+ mtd,
+ p.labelOffsetBytes,
+ dev.vendor
+ );
+ if (!info) {
+ info = fb;
+ } else {
+ if (fb && fb.label && (info.label == null || info.label == "")) {
+ info.label = fb.label;
+ }
+ if (fb && fb.os && (info.os == null || info.os == "")) {
+ info.os = fb.os;
+ }
+ }
+ }
+ }
+ push(out_parts, {
+ number: "" + num,
+ label: info ? info.label : null,
+ os: info ? info.os : null,
+ mtd: mtd,
+ });
+ }
+
+ return {
+ device: {
+ vendor: dev.vendor ?? "",
+ model: dev.model ?? "",
+ board: board ?? "",
+ partition_active: active_num != null ? "" + active_num : null,
+ },
+ partitions: out_parts,
+ };
+}
+
+/* Switch active boot partition by updating bootloader env or dual-flag.
+ *
+ * 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
+ * @returns {Object} {} on success; {error:..., ...} on failure.
+ * @sideeffects Calls fw_setenv/fw_saveenv or writes to dual-flag MTD.
+ */
+function boot_partition(req) {
+ /* extract target partition number from RPC args */
+ let number;
+ if (req && req.number != null) number = int(req.number);
+ if (!number)
+ return {
+ error: "INVALID_ARG",
+ detail: "number is required and must be numeric",
+ };
+
+ let board = get_board_name();
+ if (!board) return { error: "NO_BOARD_NAME" };
+
+ let d = find_device_info(board);
+ if (!d) return { error: "NO_BOARD_NAME_MATCH", rom_board_name: board };
+
+ let dev = d.device ?? {};
+ let cmds = d.commands ?? {};
+ let parts = d.partitions && type(d.partitions) == "array" ? d.partitions : [];
+ let params = cmds.params && type(cmds.params) == "array" ? cmds.params : [];
+ let setcmd = cmds.set ?? "fw_setenv";
+ let savecmd = cmds.save ?? null;
+ let target = null;
+
+ for (let i = 0; i < length(parts); i++) {
+ let p = parts[i] ?? {};
+ let num = p.number != null ? p.number : i;
+ if (num == number) {
+ target = p;
+ break;
+ }
+ }
+
+ if (!target) return { error: "PARTITION_NOT_FOUND", args: ["" + number] };
+
+ /* Set this partition active */
+ if (length(params) > 0) {
+ for (let j = 0; j < length(params); j++) {
+ let param = params[j];
+ let value = target.param_values ? target.param_values[j] : null;
+ 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 (rc != "0") return { error: "ERR_SAVE_ENV", rom_board_name: board };
+ }
+ } else {
+ let df = read_dual_flag_mtd();
+ 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 };
+ if (!write_dual_flag_value(df, target.param_values[0]))
+ return { error: "ERR_SET_DUAL_FLAG", args: [df], rom_board_name: board };
+ }
+ return {};
+}
+
+const methods = {
+ obtain_device_info: { call: obtain_device_info },
+ boot_partition: { args: { number: "String" }, call: boot_partition },
+};
+
+return { "luci.advanced-reboot": methods };