From: Stan Grishin Date: Mon, 15 Jun 2026 19:41:25 +0000 (+0000) Subject: luci-app-advanced-reboot: update to 1.1.2-6 X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=f85102548ee8325bfd581a0327b210b5f7670829;p=openwrt-luci.git luci-app-advanced-reboot: update to 1.1.2-6 Update to 1.1.2-6. The headline change is a security fix for GHSA-vj96-f37g-37f6. - Security (GHSA-vj96-f37g-37f6, high): the previous read ACL granted file.exec on /bin/sh (and dd, mount, sed, fw_setenv, etc.), so a user delegated read-only access to this app could execute arbitrary commands as root. Device-info gathering is now handled server-side in the ucode rpcd backend, the broad file-exec grants are removed, and the privileged actions(boot_partition, system reboot, poweroff) are moved into a dedicated write block. - New device support: Linksys EA7500v3, Linksys MX6200 (with a device helper script), and Zyxel WSM20. - Tests: added a ucode test suite (error handling, obtain_device_info, and boot_partition) with a mock fs layer and a runner. - Build: dropped the jq/host build dependency. Build/Prepare now merges the per-device JSON files into devices.json with printf/cat, so the merged file is no longer committed and the separate install hook is gone. - Maintenance: project moved to the mossdef-org org; melmac.ca URLs updated to mossdef.org across the Makefile, README, and LuCI view. Signed-off-by: Stan Grishin --- diff --git a/applications/luci-app-advanced-reboot/Makefile b/applications/luci-app-advanced-reboot/Makefile index 606e2d969b..e0e581d329 100644 --- a/applications/luci-app-advanced-reboot/Makefile +++ b/applications/luci-app-advanced-reboot/Makefile @@ -6,16 +6,14 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-advanced-reboot PKG_LICENSE:=AGPL-3.0-or-later PKG_MAINTAINER:=Stan Grishin -PKG_VERSION:=1.1.1 -PKG_RELEASE:=15 - -PKG_BUILD_DEPENDS:=jq/host +PKG_VERSION:=1.1.2 +PKG_RELEASE:=6 LUCI_TITLE:=Advanced Linksys Reboot Web UI -LUCI_URL:=https://github.com/stangri/luci-app-advanced-reboot/ +LUCI_URL:=https://github.com/mossdef-org/luci-app-advanced-reboot/ LUCI_DESCRIPTION:=Provides Web UI (found under System/Advanced Reboot) to reboot supported Linksys and ZyXEL routers to\ an alternative partition. Also provides Web UI to shut down (power off) your device. Supported dual-partition\ - routers are listed at https://docs.openwrt.melmac.ca/luci-app-advanced-reboot/ + routers are listed at https://docs.mossdef.org/luci-app-advanced-reboot/ LUCI_DEPENDS:=+luci-base +jshn define Package/$(PKG_NAME)/config @@ -26,23 +24,28 @@ help Version: $(PKG_VERSION)-$(PKG_RELEASE) endef -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; \ +# Consolidate individual device JSON files into devices.json in the build tree. +# luci.mk's Build/Prepare calls Build/Prepare/$(LUCI_NAME) as a per-package hook. +# The merged file lands in root/ so luci.mk's install step copies it automatically. +define Build/Prepare/luci-app-advanced-reboot + @if [ -d $(PKG_BUILD_DIR)/root/usr/share/advanced-reboot/devices ] \ + && ls $(PKG_BUILD_DIR)/root/usr/share/advanced-reboot/devices/*.json >/dev/null 2>&1; then \ + sep=''; printf '[' > $(PKG_BUILD_DIR)/root/usr/share/advanced-reboot/devices.json; \ + for f in $(PKG_BUILD_DIR)/root/usr/share/advanced-reboot/devices/*.json; do \ + printf '%s' "$$$$sep" >> $(PKG_BUILD_DIR)/root/usr/share/advanced-reboot/devices.json; \ + cat "$$$$f" >> $(PKG_BUILD_DIR)/root/usr/share/advanced-reboot/devices.json; \ + sep=','; \ + done; \ + printf ']' >> $(PKG_BUILD_DIR)/root/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; \ + @rm -rf $(PKG_BUILD_DIR)/root/usr/share/advanced-reboot/devices.disabled + @if grep -q '"device"' $(PKG_BUILD_DIR)/root/usr/share/advanced-reboot/devices.json 2>/dev/null; then \ + rm -rf $(PKG_BUILD_DIR)/root/usr/share/advanced-reboot/devices; \ + else \ + rm -f $(PKG_BUILD_DIR)/root/usr/share/advanced-reboot/devices.json; \ fi endef +include ../../luci.mk + # call BuildPackage - OpenWrt buildroot signature diff --git a/applications/luci-app-advanced-reboot/README.md b/applications/luci-app-advanced-reboot/README.md index c647595665..644df678f7 100644 --- a/applications/luci-app-advanced-reboot/README.md +++ b/applications/luci-app-advanced-reboot/README.md @@ -21,7 +21,7 @@ opkg install luci-app-advanced-reboot ## Documentation Full documentation is available at: -[https://docs.openwrt.melmac.ca/luci-app-advanced-reboot/](https://docs.openwrt.melmac.ca/luci-app-advanced-reboot/) +[https://docs.mossdef.org/luci-app-advanced-reboot/](https://docs.mossdef.org/luci-app-advanced-reboot/) ## License diff --git a/applications/luci-app-advanced-reboot/htdocs/luci-static/resources/view/system/advanced-reboot.js b/applications/luci-app-advanced-reboot/htdocs/luci-static/resources/view/system/advanced-reboot.js index 2351bf15d7..92b6ba6f72 100644 --- a/applications/luci-app-advanced-reboot/htdocs/luci-static/resources/view/system/advanced-reboot.js +++ b/applications/luci-app-advanced-reboot/htdocs/luci-static/resources/view/system/advanced-reboot.js @@ -10,7 +10,7 @@ var pkg = { return "luci-app-advanced-reboot"; }, get URL() { - return "https://docs.openwrt.melmac.ca/" + pkg.Name + "/"; + return "https://docs.mossdef.org/" + pkg.Name + "/"; }, }; @@ -65,6 +65,11 @@ return view.extend({ ERR_SAVE_ENV: function (args) { return _("Unable to save environment changes."); }, + ERR_SET_HELPER: function (args) { + return _( + "Unable to run device helper: %s for partition: %s." + ).format(args[0], args[1]); + }, NO_TARGET_FLAG: function (args) { return _("Target partition flag is not defined for this device."); }, diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.disabled/linksys-ea9500.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.disabled/linksys-ea9500.json index f952abecf2..99033f01f2 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.disabled/linksys-ea9500.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.disabled/linksys-ea9500.json @@ -15,15 +15,25 @@ "partitions": [ { "number": 1, - "param_values": [1], - "mtd": "mtd3", - "labelOffsetBytes": 28 + "param_values": [ + 1 + ], + "firmware": { + "kernel": "mtd3", + "kernel_label_offset": 28, + "rootfs": "mtd4" + } }, { "number": 2, - "param_values": [2], - "mtd": "mtd6", - "labelOffsetBytes": 28 + "param_values": [ + 2 + ], + "firmware": { + "kernel": "mtd6", + "kernel_label_offset": 28, + "rootfs": "mtd7" + } } ] -} \ No newline at end of file +} diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.disabled/netgear-wac510.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.disabled/netgear-wac510.json index e8792aaafe..06463f2013 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.disabled/netgear-wac510.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.disabled/netgear-wac510.json @@ -18,15 +18,23 @@ "partitions": [ { "number": 1, - "param_values": [0, 3800000], - "mtd": "mtd9", - "labelOffsetBytes": null + "param_values": [ + 0, + 3800000 + ], + "firmware": { + "rootfs": "mtd10" + } }, { "number": 2, - "param_values": [3800000, 0], - "mtd": "mtd10", - "labelOffsetBytes": null + "param_values": [ + 3800000, + 0 + ], + "firmware": { + "rootfs": "mtd11" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.disabled/xiaomi-ax3600.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.disabled/xiaomi-ax3600.json index 70bbbaf885..5d54bb65b4 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.disabled/xiaomi-ax3600.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.disabled/xiaomi-ax3600.json @@ -22,8 +22,11 @@ 0, 0 ], - "mtd": "mtd12", - "labelOffsetBytes": 266432 + "firmware": { + "kernel": "mtd12", + "kernel_label_offset": 266432, + "rootfs": "mtd13" + } }, { "number": 2, @@ -31,8 +34,11 @@ 1, 1 ], - "mtd": "mtd13", - "labelOffsetBytes": 266432 + "firmware": { + "kernel": "mtd13", + "kernel_label_offset": 266432, + "rootfs": "mtd14" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.disabled/xiaomi-ax9000.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.disabled/xiaomi-ax9000.json index 285bf13aa2..ee9f55a524 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.disabled/xiaomi-ax9000.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.disabled/xiaomi-ax9000.json @@ -22,8 +22,11 @@ 0, 0 ], - "mtd": "mtd20", - "labelOffsetBytes": 266432 + "firmware": { + "kernel": "mtd20", + "kernel_label_offset": 266432, + "rootfs": "mtd21" + } }, { "number": 2, @@ -31,8 +34,11 @@ 1, 1 ], - "mtd": "mtd21", - "labelOffsetBytes": 266432 + "firmware": { + "kernel": "mtd21", + "kernel_label_offset": 266432, + "rootfs": "mtd22" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.json deleted file mode 100644 index 4a73edd289..0000000000 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices.json +++ /dev/null @@ -1,1506 +0,0 @@ -[ - { - "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 - } - ] - } -] diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/_device_json_transform.jq b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/_device_json_transform.jq deleted file mode 100644 index 23eb440329..0000000000 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/_device_json_transform.jq +++ /dev/null @@ -1,88 +0,0 @@ -# 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": , "altMountOptions": {...|null} }, -# { "number": 2, "param_values": [...], "mtd": "mtdY", "labelOffsetBytes": , "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) - ] -} diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/dlink-fgs1210-28.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/dlink-fgs1210-28.json index 8584916c20..77547d94d2 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/dlink-fgs1210-28.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/dlink-fgs1210-28.json @@ -19,8 +19,9 @@ { "number": 1, "param_values": [], - "mtd": "mtd5", - "labelOffsetBytes": null + "firmware": { + "rootfs": "mtd6" + } }, { "number": 2, @@ -28,8 +29,9 @@ "run addargs\\; bootm 0xb4e80000", "/dev/mtdblock7" ], - "mtd": "mtd9", - "labelOffsetBytes": null + "firmware": { + "rootfs": "mtd10" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-e4200v2-ea4500.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-e4200v2-ea4500.json index 361e183389..29c0d4702f 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-e4200v2-ea4500.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-e4200v2-ea4500.json @@ -23,8 +23,11 @@ 1, "run nandboot" ], - "mtd": "mtd3", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd3", + "kernel_label_offset": 32, + "rootfs": "mtd4" + } }, { "number": 2, @@ -32,8 +35,11 @@ 2, "run altnandboot" ], - "mtd": "mtd5", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd5", + "kernel_label_offset": 32, + "rootfs": "mtd6" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-e4200v2.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-e4200v2.json index dc11ac3b6b..b691cbeedd 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-e4200v2.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-e4200v2.json @@ -23,8 +23,11 @@ 1, "run nandboot" ], - "mtd": "mtd3", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd3", + "kernel_label_offset": 32, + "rootfs": "mtd4" + } }, { "number": 2, @@ -32,8 +35,11 @@ 2, "run altnandboot" ], - "mtd": "mtd5", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd5", + "kernel_label_offset": 32, + "rootfs": "mtd6" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-e7350.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-e7350.json index bd072c21ed..5a53dc6ce2 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-e7350.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-e7350.json @@ -20,16 +20,22 @@ "param_values": [ 1 ], - "mtd": "mtd3", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd3", + "kernel_label_offset": 192, + "rootfs": "mtd4" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd6", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd6", + "kernel_label_offset": 192, + "rootfs": "mtd7" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea3500.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea3500.json index 2db5615452..a7332d45e7 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea3500.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea3500.json @@ -25,8 +25,11 @@ 1, "run nandboot" ], - "mtd": "mtd3", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd3", + "kernel_label_offset": 32, + "rootfs": "mtd4" + } }, { "number": 2, @@ -34,8 +37,11 @@ 2, "run altnandboot" ], - "mtd": "mtd5", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd5", + "kernel_label_offset": 32, + "rootfs": "mtd6" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea4500.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea4500.json index f5b8d0318a..6aeb3ccee5 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea4500.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea4500.json @@ -23,8 +23,11 @@ 1, "run nandboot" ], - "mtd": "mtd3", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd3", + "kernel_label_offset": 32, + "rootfs": "mtd4" + } }, { "number": 2, @@ -32,8 +35,11 @@ 2, "run altnandboot" ], - "mtd": "mtd5", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd5", + "kernel_label_offset": 32, + "rootfs": "mtd6" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea6350v3.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea6350v3.json index 32f6cd108a..f7e0f1106a 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea6350v3.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea6350v3.json @@ -21,16 +21,22 @@ "param_values": [ 1 ], - "mtd": "mtd10", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd10", + "kernel_label_offset": 192, + "rootfs": "mtd11" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd12", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd12", + "kernel_label_offset": 192, + "rootfs": "mtd13" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea6350v4.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea6350v4.json index 74694d5e95..ee475eb0f5 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea6350v4.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea6350v4.json @@ -20,16 +20,22 @@ "param_values": [ 1 ], - "mtd": "mtd5", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd5", + "kernel_label_offset": 32, + "rootfs": "mtd6" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd7", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd7", + "kernel_label_offset": 32, + "rootfs": "mtd8" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7300v1.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7300v1.json index 580a3f55b8..31d8fee763 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7300v1.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7300v1.json @@ -22,8 +22,11 @@ 1, "run nandboot" ], - "mtd": "mtd5", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd5", + "kernel_label_offset": 32, + "rootfs": "mtd6" + } }, { "number": 2, @@ -31,8 +34,11 @@ 2, "run altnandboot" ], - "mtd": "mtd7", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd7", + "kernel_label_offset": 32, + "rootfs": "mtd8" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7300v2.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7300v2.json index 5513a7a6c8..b79d552b8e 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7300v2.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7300v2.json @@ -22,8 +22,11 @@ 1, "run nandboot" ], - "mtd": "mtd5", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd5", + "kernel_label_offset": 32, + "rootfs": "mtd6" + } }, { "number": 2, @@ -31,8 +34,11 @@ 2, "run altnandboot" ], - "mtd": "mtd7", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd7", + "kernel_label_offset": 32, + "rootfs": "mtd8" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7500v1.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7500v1.json index 9012333d83..7bfcbde6f6 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7500v1.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7500v1.json @@ -20,16 +20,22 @@ "param_values": [ 1 ], - "mtd": "mtd13", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd13", + "kernel_label_offset": 32, + "rootfs": "mtd14" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd15", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd15", + "kernel_label_offset": 32, + "rootfs": "mtd16" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7500v2.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7500v2.json index 8a7dcae180..2ed0b3dc69 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7500v2.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7500v2.json @@ -22,8 +22,11 @@ 1, "run nandboot" ], - "mtd": "mtd5", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd5", + "kernel_label_offset": 32, + "rootfs": "mtd6" + } }, { "number": 2, @@ -31,8 +34,11 @@ 2, "run altnandboot" ], - "mtd": "mtd7", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd7", + "kernel_label_offset": 32, + "rootfs": "mtd8" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7500v3.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7500v3.json new file mode 100644 index 0000000000..ca19a310ac --- /dev/null +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea7500v3.json @@ -0,0 +1,44 @@ +{ + "device": { + "vendor": "Linksys", + "model": "EA7500v3", + "board": [ + "linksys,ea7500-v3" + ] + }, + "commands": { + "params": [ + "boot_part", + "bootimage" + ], + "get": "fw_printenv", + "set": "fw_setenv", + "save": null + }, + "partitions": [ + { + "number": 1, + "param_values": [ + 1, + 1 + ], + "firmware": { + "kernel": "mtd3", + "kernel_label_offset": 32, + "rootfs": "mtd4" + } + }, + { + "number": 2, + "param_values": [ + 2, + 2 + ], + "firmware": { + "kernel": "mtd5", + "kernel_label_offset": 32, + "rootfs": "mtd6" + } + } + ] +} diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea8100v1.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea8100v1.json index f2f0489e41..5cfe6c6343 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea8100v1.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea8100v1.json @@ -20,16 +20,22 @@ "param_values": [ 1 ], - "mtd": "mtd5", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd5", + "kernel_label_offset": 32, + "rootfs": "mtd6" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd7", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd7", + "kernel_label_offset": 32, + "rootfs": "mtd8" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea8100v2.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea8100v2.json index cbed6e1cb5..9e655ecbb2 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea8100v2.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea8100v2.json @@ -20,16 +20,22 @@ "param_values": [ 1 ], - "mtd": "mtd5", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd5", + "kernel_label_offset": 32, + "rootfs": "mtd6" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd7", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd7", + "kernel_label_offset": 32, + "rootfs": "mtd8" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea8300.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea8300.json index 80518db673..d7f61d3985 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea8300.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea8300.json @@ -21,16 +21,22 @@ "param_values": [ 1 ], - "mtd": "mtd10", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd10", + "kernel_label_offset": 192, + "rootfs": "mtd11" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd12", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd12", + "kernel_label_offset": 192, + "rootfs": "mtd13" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea8500.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea8500.json index e2f7ccc508..a70e401958 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea8500.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-ea8500.json @@ -21,16 +21,22 @@ "param_values": [ 1 ], - "mtd": "mtd13", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd13", + "kernel_label_offset": 32, + "rootfs": "mtd14" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd15", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd15", + "kernel_label_offset": 32, + "rootfs": "mtd16" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr5500.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr5500.json index 13ff2d2f79..b0754c474e 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr5500.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr5500.json @@ -20,16 +20,22 @@ "param_values": [ 1 ], - "mtd": "mtd12", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd12", + "kernel_label_offset": 192, + "rootfs": "mtd13" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd14", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd14", + "kernel_label_offset": 192, + "rootfs": "mtd15" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr7350.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr7350.json index 68bff35efd..9d500c364b 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr7350.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr7350.json @@ -20,16 +20,22 @@ "param_values": [ 1 ], - "mtd": "mtd14", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd14", + "kernel_label_offset": 192, + "rootfs": "mtd15" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd16", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd16", + "kernel_label_offset": 192, + "rootfs": "mtd17" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr7500.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr7500.json index 4dc7309d73..2353f64ec1 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr7500.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr7500.json @@ -20,16 +20,22 @@ "param_values": [ 1 ], - "mtd": "mtd13", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd13", + "kernel_label_offset": 192, + "rootfs": "mtd14" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd15", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd15", + "kernel_label_offset": 192, + "rootfs": "mtd16" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr8300.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr8300.json index 625ab0fc75..3a66e32a12 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr8300.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr8300.json @@ -21,16 +21,22 @@ "param_values": [ 1 ], - "mtd": "mtd10", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd10", + "kernel_label_offset": 192, + "rootfs": "mtd11" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd12", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd12", + "kernel_label_offset": 192, + "rootfs": "mtd13" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr9000.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr9000.json index 763692bf10..ae89fd86aa 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr9000.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mr9000.json @@ -20,16 +20,22 @@ "param_values": [ 1 ], - "mtd": "mtd10", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd10", + "kernel_label_offset": 192, + "rootfs": "mtd11" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd12", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd12", + "kernel_label_offset": 192, + "rootfs": "mtd13" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx2000.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx2000.json index c10f8a9891..f0bf3e5b5a 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx2000.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx2000.json @@ -20,16 +20,22 @@ "param_values": [ 1 ], - "mtd": "mtd12", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd12", + "kernel_label_offset": 192, + "rootfs": "mtd13" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd14", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd14", + "kernel_label_offset": 192, + "rootfs": "mtd15" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx4200v1.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx4200v1.json index 735798e6c3..0be21758f4 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx4200v1.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx4200v1.json @@ -20,16 +20,22 @@ "param_values": [ 1 ], - "mtd": "mtd21", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd21", + "kernel_label_offset": 192, + "rootfs": "mtd22" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd23", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd23", + "kernel_label_offset": 192, + "rootfs": "mtd24" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx4200v2.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx4200v2.json index 906aa8414c..d1eaa653ac 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx4200v2.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx4200v2.json @@ -20,16 +20,22 @@ "param_values": [ 1 ], - "mtd": "mtd21", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd21", + "kernel_label_offset": 192, + "rootfs": "mtd22" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd23", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd23", + "kernel_label_offset": 192, + "rootfs": "mtd24" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx4300.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx4300.json index 0c494969d3..84fc45e56c 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx4300.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx4300.json @@ -20,16 +20,22 @@ "param_values": [ 1 ], - "mtd": "mtd21", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd21", + "kernel_label_offset": 192, + "rootfs": "mtd22" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd23", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd23", + "kernel_label_offset": 192, + "rootfs": "mtd24" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx5300.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx5300.json index d904eeea89..6d7d78c6c8 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx5300.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx5300.json @@ -20,16 +20,22 @@ "param_values": [ 1 ], - "mtd": "mtd21", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd21", + "kernel_label_offset": 192, + "rootfs": "mtd22" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd23", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd23", + "kernel_label_offset": 192, + "rootfs": "mtd24" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx5500.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx5500.json index 35407fc774..e79c1f5839 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx5500.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx5500.json @@ -20,16 +20,22 @@ "param_values": [ 1 ], - "mtd": "mtd12", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd12", + "kernel_label_offset": 192, + "rootfs": "mtd13" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd14", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd14", + "kernel_label_offset": 192, + "rootfs": "mtd15" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx6200.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx6200.json new file mode 100644 index 0000000000..56b7a4f00c --- /dev/null +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx6200.json @@ -0,0 +1,32 @@ +{ + "device": { + "vendor": "Linksys", + "model": "MX6200", + "board": ["linksys,mx6200"] + }, + "commands": { + "params": ["boot_part"], + "get": "fw_printenv", + "set": "fw_setenv", + "save": null, + "set_helper": "/usr/share/advanced-reboot/helpers/linksys-mx6200.sh" + }, + "partitions": [ + { + "number": 1, + "param_values": [1], + "firmware": { + "rootfs": "mtd19", + "rootfs_ubi_volume": 1 + } + }, + { + "number": 2, + "param_values": [2], + "firmware": { + "rootfs": "mtd19", + "rootfs_ubi_volume": 1 + } + } + ] +} diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx8500.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx8500.json index e9ab606179..5b976d8cd7 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx8500.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-mx8500.json @@ -20,16 +20,22 @@ "param_values": [ 1 ], - "mtd": "mtd21", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd21", + "kernel_label_offset": 192, + "rootfs": "mtd22" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd23", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd23", + "kernel_label_offset": 192, + "rootfs": "mtd24" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-spnmx56.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-spnmx56.json index 09bc2a2f78..110cddef38 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-spnmx56.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-spnmx56.json @@ -20,16 +20,22 @@ "param_values": [ 1 ], - "mtd": "mtd12", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd12", + "kernel_label_offset": 192, + "rootfs": "mtd13" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd14", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd14", + "kernel_label_offset": 192, + "rootfs": "mtd15" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-whw01v1.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-whw01v1.json index f1b73d38e0..962b7b3993 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-whw01v1.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-whw01v1.json @@ -20,16 +20,22 @@ "param_values": [ 1 ], - "mtd": "mtd9", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd9", + "kernel_label_offset": 192, + "rootfs": "mtd10" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd11", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd11", + "kernel_label_offset": 192, + "rootfs": "mtd12" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-whw03.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-whw03.json index 26b16e8a61..cc7fd86cc1 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-whw03.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-whw03.json @@ -20,16 +20,20 @@ "param_values": [ 1 ], - "mtd": "mmcblk0p14", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mmcblk0p14", + "kernel_label_offset": 192 + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mmcblk0p16", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mmcblk0p16", + "kernel_label_offset": 192 + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-whw03v2.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-whw03v2.json index 3bd967476c..748f2e25ac 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-whw03v2.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-whw03v2.json @@ -21,16 +21,22 @@ "param_values": [ 1 ], - "mtd": "mtd9", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd9", + "kernel_label_offset": 192, + "rootfs": "mtd10" + } }, { "number": 2, "param_values": [ 2 ], - "mtd": "mtd11", - "labelOffsetBytes": 192 + "firmware": { + "kernel": "mtd11", + "kernel_label_offset": 192, + "rootfs": "mtd12" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt1200ac.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt1200ac.json index 346891ae67..438422904e 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt1200ac.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt1200ac.json @@ -24,8 +24,11 @@ 1, "run nandboot" ], - "mtd": "mtd4", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd4", + "kernel_label_offset": 32, + "rootfs": "mtd5" + } }, { "number": 2, @@ -33,8 +36,11 @@ 2, "run altnandboot" ], - "mtd": "mtd6", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd6", + "kernel_label_offset": 32, + "rootfs": "mtd7" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt1900ac.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt1900ac.json index 8ccb6c7500..c8289f105a 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt1900ac.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt1900ac.json @@ -24,8 +24,11 @@ 1, "run nandboot" ], - "mtd": "mtd4", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd4", + "kernel_label_offset": 32, + "rootfs": "mtd5" + } }, { "number": 2, @@ -33,8 +36,11 @@ 2, "run altnandboot" ], - "mtd": "mtd6", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd6", + "kernel_label_offset": 32, + "rootfs": "mtd7" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt1900acs.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt1900acs.json index 42bb14b763..8c5b0575b9 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt1900acs.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt1900acs.json @@ -24,8 +24,11 @@ 1, "run nandboot" ], - "mtd": "mtd4", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd4", + "kernel_label_offset": 32, + "rootfs": "mtd5" + } }, { "number": 2, @@ -33,8 +36,11 @@ 2, "run altnandboot" ], - "mtd": "mtd6", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd6", + "kernel_label_offset": 32, + "rootfs": "mtd7" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt1900acv2.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt1900acv2.json index f585a542a4..6749cc4c19 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt1900acv2.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt1900acv2.json @@ -24,8 +24,11 @@ 1, "run nandboot" ], - "mtd": "mtd4", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd4", + "kernel_label_offset": 32, + "rootfs": "mtd5" + } }, { "number": 2, @@ -33,8 +36,11 @@ 2, "run altnandboot" ], - "mtd": "mtd6", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd6", + "kernel_label_offset": 32, + "rootfs": "mtd7" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt3200acm.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt3200acm.json index f7dc5e59cc..9c69fffdd7 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt3200acm.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt3200acm.json @@ -24,8 +24,11 @@ 1, "run nandboot" ], - "mtd": "mtd5", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd5", + "kernel_label_offset": 32, + "rootfs": "mtd6" + } }, { "number": 2, @@ -33,8 +36,11 @@ 2, "run altnandboot" ], - "mtd": "mtd7", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mtd7", + "kernel_label_offset": 32, + "rootfs": "mtd8" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt32x.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt32x.json index 5ef1ccf7f6..84028d09f1 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt32x.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/linksys-wrt32x.json @@ -24,8 +24,9 @@ 1, "run nandboot" ], - "mtd": "mtd5", - "labelOffsetBytes": null + "firmware": { + "rootfs": "mtd6" + } }, { "number": 2, @@ -33,8 +34,9 @@ 2, "run altnandboot" ], - "mtd": "mtd7", - "labelOffsetBytes": null + "firmware": { + "rootfs": "mtd8" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/mercusys-mr90xv1.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/mercusys-mr90xv1.json index 96a4b3d250..3c020a5ecc 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/mercusys-mr90xv1.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/mercusys-mr90xv1.json @@ -20,11 +20,9 @@ "param_values": [ 0 ], - "mtd": "mtd2", - "labelOffsetBytes": null, - "altMountOptions": { - "mtdOffset": 0, - "ubiVolume": 2 + "firmware": { + "rootfs": "mtd2", + "rootfs_ubi_volume": 2 } }, { @@ -32,11 +30,9 @@ "param_values": [ 1 ], - "mtd": "mtd3", - "labelOffsetBytes": null, - "altMountOptions": { - "mtdOffset": 0, - "ubiVolume": 2 + "firmware": { + "rootfs": "mtd3", + "rootfs_ubi_volume": 2 } } ] diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/netgear-gs308t-v1.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/netgear-gs308t-v1.json index b1143d3842..10b53126c8 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/netgear-gs308t-v1.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/netgear-gs308t-v1.json @@ -20,16 +20,18 @@ "param_values": [ 0 ], - "mtd": "mtd6", - "labelOffsetBytes": null + "firmware": { + "rootfs": "mtd7" + } }, { "number": 2, "param_values": [ 1 ], - "mtd": "mtd9", - "labelOffsetBytes": null + "firmware": { + "rootfs": "mtd10" + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/zyxel-nbg6817.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/zyxel-nbg6817.json index 966945d265..fedf46fdb3 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/zyxel-nbg6817.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/zyxel-nbg6817.json @@ -19,16 +19,20 @@ "param_values": [ "ff" ], - "mtd": "mmcblk0p4", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mmcblk0p4", + "kernel_label_offset": 32 + } }, { "number": 2, "param_values": [ "01" ], - "mtd": "mmcblk0p7", - "labelOffsetBytes": 32 + "firmware": { + "kernel": "mmcblk0p7", + "kernel_label_offset": 32 + } } ] } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/zyxel-wsm20.json b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/zyxel-wsm20.json new file mode 100644 index 0000000000..5e7bd5e7ea --- /dev/null +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/zyxel-wsm20.json @@ -0,0 +1,42 @@ +{ + "device": { + "vendor": "ZyXEL", + "model": "WSM20", + "board": [ + "zyxel,wsm20" + ] + }, + "commands": { + "params": [], + "get": null, + "set": null, + "save": null, + "dual_flag": { + "mtd": "persist", + "offset": 4 + } + }, + "partitions": [ + { + "number": 1, + "param_values": [ + "01" + ], + "firmware": { + "kernel": "mtd4", + "kernel_label_offset": 32, + "rootfs": "mtd5" + } + }, + { + "number": 2, + "param_values": [ + "02" + ], + "firmware": { + "kernel": "mtd6", + "kernel_label_offset": 32 + } + } + ] +} diff --git a/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/helpers/linksys-mx6200.sh b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/helpers/linksys-mx6200.sh new file mode 100755 index 0000000000..0c0ceb26ad --- /dev/null +++ b/applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/helpers/linksys-mx6200.sh @@ -0,0 +1,20 @@ +#!/bin/sh +# advanced-reboot helper for Linksys MX6200 +# Sets bootconfig partitions after fw_setenv boot_part has been called. +# Usage: linksys-mx6200.sh + +. /lib/upgrade/platform.sh + +case "$1" in + 1) + linksys_bootconfig_set_primaryboot "0:bootconfig" 0 + linksys_bootconfig_set_primaryboot "0:bootconfig1" 0 + ;; + 2) + linksys_bootconfig_set_primaryboot "0:bootconfig" 1 + linksys_bootconfig_set_primaryboot "0:bootconfig1" 1 + ;; + *) + exit 1 + ;; +esac diff --git a/applications/luci-app-advanced-reboot/root/usr/share/rpcd/acl.d/luci-app-advanced-reboot.json b/applications/luci-app-advanced-reboot/root/usr/share/rpcd/acl.d/luci-app-advanced-reboot.json index ed0b5d1bff..281d59c8d2 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/rpcd/acl.d/luci-app-advanced-reboot.json +++ b/applications/luci-app-advanced-reboot/root/usr/share/rpcd/acl.d/luci-app-advanced-reboot.json @@ -1,36 +1,18 @@ { "luci-app-advanced-reboot": { - "description": "Grant file access for luci-app-advanced-reboot", + "description": "Grant access for luci-app-advanced-reboot", "read": { "ubus": { - "luci.advanced-reboot": [ "obtain_device_info", "boot_partition" ], + "luci.advanced-reboot": [ "obtain_device_info" ] + } + }, + "write": { + "ubus": { + "luci.advanced-reboot": [ "boot_partition" ], "system": [ "reboot" ] }, "file": { - "/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" ] + "/sbin/poweroff": [ "list", "exec" ] } } } diff --git a/applications/luci-app-advanced-reboot/root/usr/share/rpcd/ucode/luci.advanced-reboot b/applications/luci-app-advanced-reboot/root/usr/share/rpcd/ucode/luci.advanced-reboot index 5c316ec69b..f903b6297e 100644 --- a/applications/luci-app-advanced-reboot/root/usr/share/rpcd/ucode/luci.advanced-reboot +++ b/applications/luci-app-advanced-reboot/root/usr/share/rpcd/ucode/luci.advanced-reboot @@ -18,17 +18,31 @@ * "params": ["", ""], * "get": "fw_printenv", * "set": "fw_setenv", - * "save": null + * "save": null, + * "set_helper": "/usr/share/advanced-reboot/helpers/.sh", + * "dual_flag": { "mtd": "", "offset": } * }, * "partitions": [ - * { "number": 1, "param_values": [v1, w1], "mtd": "mtdX", "labelOffsetBytes": , "altMountOptions": { "mtdOffset": , "ubiVolume": } }, - * { "number": 2, "param_values": [v2, w2], "mtd": "mtdY", "labelOffsetBytes": } + * { "number": 1, "param_values": [v1, w1], "firmware": { "kernel": "mtdX", "rootfs": "mtdY", "kernel_label_offset": , "rootfs_ubi_volume": } }, + * { "number": 2, "param_values": [v2, w2], "firmware": { ... } } * ] * } * * Notes: - * - `altMountOptions` is optional; when absent, defaults are mtdOffset=1, ubiVolume=0. * - `param_values[i]` aligns with `commands.params[i]`. + * - `set_helper` is optional; when present, the script is called with the partition + * number as its sole argument after the standard params have been set. + * - When `commands.params` is empty the dual-flag method is used: a single byte in + * an MTD partition selects the boot slot. `commands.dual_flag` is optional and + * customizes this: `mtd` is the partition name to locate via find_mtd_part + * (default: "0:dual_flag"/"0:DUAL_FLAG"), `offset` is the byte offset of the flag + * (default: 0). `param_values[0]` for each partition is the matching flag byte as + * two lowercase hex digits (e.g. "01"). Example: ZyXEL WSM20 stores the boot + * number at offset 4 of the "persist" partition (1 => first OS, 2 => second OS). + * - `firmware.kernel` is optional; the device to read raw label from at kernel_label_offset. + * - `firmware.rootfs` is optional; the device to UBI-mount for alt partition info. + * - `firmware.kernel_label_offset` is optional; byte offset for label probe (requires kernel). + * - `firmware.rootfs_ubi_volume` is optional; UBI volume index within rootfs (default 0). */ "use strict"; @@ -36,6 +50,10 @@ import * as fs from "fs"; let DEVICES_DIR = "/usr/share/advanced-reboot/devices/"; let DEVICES_JSON = "/usr/share/advanced-reboot/devices.json"; +/* Reset in alt_partition_mount() on each call; tracks whether the UBI device + * was already attached (e.g. by the kernel on IPQ5018) so alt_partition_unmount() knows + * not to detach it. */ +let alt_ubi_pre_attached = false; function file_exists(p) { try { @@ -90,28 +108,28 @@ function find_device_info(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; + if (txt) { + // devices.json : [ { device: {...} }, { device: {...} }, ... ] + let arr = json(txt); + if (arr && type(arr) == "array") { + // 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 + // Fallback: individual device JSON files let list = fs.glob(DEVICES_DIR + "*.json"); for (let f in list) { let ftxt = fs.readfile(f); @@ -188,6 +206,22 @@ function get_partition_info_current() { return get_volume_info("/"); } +/* Find the UBI device number for a given MTD index via sysfs. + * + * Checks /sys/class/ubi/ubiN/mtd_num entries to find a match. + * + * @param {Number|String} mtd_idx MTD index to look up. + * @returns {Number|null} UBI device number, or null if not found. + */ +function find_ubi_dev_by_mtd(mtd_idx) { + let out = command( + "for d in /sys/class/ubi/ubi[0-9]*; do " + + "[ \"$(cat \"$d/mtd_num\" 2>/dev/null)\" = \"" + mtd_idx + "\" ] && " + + "echo \"${d##*/ubi}\" && break; done" + ); + return out && length(out) ? int(out) : null; +} + /* Determine if an alternate partition can be mounted. * * Requires: ubiattach, ubiblock, and mount commands available. @@ -229,8 +263,18 @@ function alt_partition_mount(op_ubi, ubi_vol) { 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; + alt_ubi_pre_attached = false; + if (dev == null) { + /* ubiattach failed — MTD may already be attached (e.g. by kernel). + * Look up the existing UBI device number via sysfs. */ + dev = find_ubi_dev_by_mtd(op_ubi); + if (dev != null) { + alt_ubi_pre_attached = true; + log("found pre-attached UBI device " + dev + " for mtd" + op_ubi); + } + } + log("alternative partition UBI device number: " + dev); if (dev == null) { command("ubidetach -m " + op_ubi + " >/dev/null 2>&1"); return false; @@ -247,6 +291,7 @@ function alt_partition_mount(op_ubi, ubi_vol) { /* Unmount and detach any UBI devices associated with a given MTD index. * * Also removes possible ubiblock nodes for the device. + * Skips ubidetach when the UBI was pre-attached (not attached by us). * * @param {Number|String} op_ubi UBI mtd index previously attached. * @param {Number|String} ubi_vol UBI volume index (ignored during cleanup). @@ -254,25 +299,18 @@ function alt_partition_mount(op_ubi, ubi_vol) { * @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" - ); + let dev = find_ubi_dev_by_mtd(op_ubi); + if (dev != null) { + /* remove any ubiblock nodes on this ubi dev */ + for (let vid = 0; vid < 16; vid++) + command( + "ubiblock --remove /dev/ubi" + dev + "_" + vid + " >/dev/null 2>&1" + ); + if (!alt_ubi_pre_attached) command("ubidetach -m " + op_ubi + " >/dev/null 2>&1"); - command("rm -rf /var/alt_rom"); - } } + command("rm -rf /var/alt_rom"); } /* Get label/OS info from an alternative partition, using UBI mount flow. @@ -331,8 +369,16 @@ function get_partition_info_fallback(mtd, offset, vendor) { return { label: label, os: os }; } -function read_dual_flag_mtd() { - for (let name in ["0:dual_flag", "0:DUAL_FLAG"]) { +/* Locate the MTD block device holding the dual-boot flag. + * + * @param {String|null} mtd_name Partition name to look up via find_mtd_part. + * When null, falls back to the conventional + * "0:dual_flag"/"0:DUAL_FLAG" names. + * @returns {String|null} Device path (e.g., /dev/mtdblockN) or null if not found. + */ +function read_dual_flag_mtd(mtd_name) { + let names = mtd_name ? ["" + mtd_name] : ["0:dual_flag", "0:DUAL_FLAG"]; + for (let name in names) { let dev = command(". /lib/functions.sh; find_mtd_part " + shellquote(name)); if (dev) return dev; } @@ -341,15 +387,18 @@ function read_dual_flag_mtd() { /* 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. + * @param {String} dev Path to the block (e.g., /dev/mtdX) returned by find_mtd_part. + * @param {Number} offset Byte offset of the flag (default 0). * @returns {String|null} Lowercase hex byte (e.g., "00", "01") or null on error. */ -function read_dual_flag_value(dev) { +function read_dual_flag_value(dev, offset) { if (!dev || dev == "" || !file_exists(dev)) return null; + let off = offset != null ? int(offset) : 0; let r = command( "dd if=" + shellquote(dev) + - " bs=1 count=1 2>/dev/null | hexdump -n 1 -e '" + + " bs=1 count=1 skip=" + off + + " 2>/dev/null | hexdump -n 1 -e '" + '1/1 "%02x"' + "'" ); @@ -358,20 +407,36 @@ function read_dual_flag_value(dev) { /* 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. + * @param {String} dev Device path (e.g., /dev/mtdX). + * @param {String} cur Hex byte without prefix (e.g., "01"); written as \\x01. + * @param {Number} offset Byte offset of the flag (default 0). * @returns {Boolean} true if write succeeded, false otherwise. * @sideeffects Overwrites one byte on the target device. */ -function write_dual_flag_value(dev, cur) { +function write_dual_flag_value(dev, cur, offset) { + let off = offset != null ? int(offset) : 0; cur = "\\x" + cur; - let rc = command( - "printf %b " + - shellquote(cur) + - " > " + - shellquote(dev) + - " 2>/dev/null; echo $?" - ); + let rc; + if (off == 0) { + rc = command( + "printf %b " + + shellquote(cur) + + " > " + + shellquote(dev) + + " 2>/dev/null; echo $?" + ); + } else { + /* Patch a single byte in place without truncating the rest of the + * partition (matches upstream zyxel_mstc_upgrade_prepare). */ + rc = command( + "printf %b " + + shellquote(cur) + + " | dd of=" + + shellquote(dev) + + " bs=1 seek=" + off + + " count=1 conv=notrunc 2>/dev/null; echo $?" + ); + } return rc == "0"; } @@ -411,12 +476,13 @@ function obtain_device_info() { push(curvals, v); } } else { - let df = read_dual_flag_mtd(); + let dual = cmds.dual_flag ?? {}; + let df = read_dual_flag_mtd(dual.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); + v = read_dual_flag_value(df, dual.offset); push(curvals, v); } @@ -424,32 +490,31 @@ function obtain_device_info() { 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 fw = p.firmware ?? {}; + let kernel = fw.kernel ?? null; + let rootfs = fw.rootfs ?? null; + let label_offset = fw.kernel_label_offset ?? null; + let ubi_vol = fw.rootfs_ubi_volume ?? 0; 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); + } else if (rootfs && is_alt_mountable([rootfs])) { + /* attempt alt mount for rootfs */ + let idx = mtd_index(rootfs); if (idx != null) { - let op_ubi = idx + mtdOff; - info = get_partition_info_alt(op_ubi, dev.vendor ?? null, ubiVol); + info = get_partition_info_alt(idx, dev.vendor ?? null, ubi_vol); if (info && info.label == null && info.os == null) info = {}; } } - /* raw-label fallback if needed */ - if (mtd && p.labelOffsetBytes != null) { + /* raw-label fallback from kernel partition */ + if (kernel && label_offset != null) { if (!info?.label || !info?.os) { let fb = get_partition_info_fallback( - mtd, - p.labelOffsetBytes, + kernel, + label_offset, dev.vendor ); if (!info) { @@ -468,7 +533,7 @@ function obtain_device_info() { number: "" + num, label: info ? info.label : null, os: info ? info.os : null, - mtd: mtd, + mtd: kernel ?? rootfs, }); } @@ -573,15 +638,33 @@ function boot_partition(req) { } if (rc != "0") return { error: "ERR_SAVE_ENV", rom_board_name: board }; } + + /* Run device-specific helper if defined */ + let helper = cmds.set_helper; + if (helper && helper != "" && + match(helper, /^\/usr\/share\/advanced-reboot\/helpers\/[^\/]+$/)) { + let cmd = shellquote(helper) + + " " + shellquote("" + number) + + " 2>/dev/null; echo $?"; + log("boot_partition running helper: " + cmd); + let rc = command(cmd); + if (rc != "0") + return { + error: "ERR_SET_HELPER", + args: [helper, "" + number], + rom_board_name: board, + }; + } } else { - let df = read_dual_flag_mtd(); + let dual = cmds.dual_flag ?? {}; + let df = read_dual_flag_mtd(dual.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 }; log("boot_partition setting dual flag: " + df + " to " + target.param_values[0]); - if (!write_dual_flag_value(df, target.param_values[0])) + if (!write_dual_flag_value(df, target.param_values[0], dual.offset)) return { error: "ERR_SET_DUAL_FLAG", args: [df], rom_board_name: board }; } return {}; diff --git a/applications/luci-app-advanced-reboot/tests/01_error_handling/01_no_board_name b/applications/luci-app-advanced-reboot/tests/01_error_handling/01_no_board_name new file mode 100644 index 0000000000..12f00d0ed6 --- /dev/null +++ b/applications/luci-app-advanced-reboot/tests/01_error_handling/01_no_board_name @@ -0,0 +1,12 @@ +Test obtain_device_info when board_name file is missing. + +-- Testcase -- +let ar = require('advanced_reboot'); +let api = ar["luci.advanced-reboot"]; +let result = api.obtain_device_info.call(); +printf("%J\n", result); +-- End -- + +-- Expect stdout -- +{ "error": "NO_BOARD_NAME" } +-- End -- diff --git a/applications/luci-app-advanced-reboot/tests/01_error_handling/02_no_device_match b/applications/luci-app-advanced-reboot/tests/01_error_handling/02_no_device_match new file mode 100644 index 0000000000..2eb36bf156 --- /dev/null +++ b/applications/luci-app-advanced-reboot/tests/01_error_handling/02_no_device_match @@ -0,0 +1,16 @@ +Test obtain_device_info when board name has no matching device config. + +-- File fs/open~_tmp_sysinfo_board_name.txt -- +unknown,device +-- End -- + +-- Testcase -- +let ar = require('advanced_reboot'); +let api = ar["luci.advanced-reboot"]; +let result = api.obtain_device_info.call(); +printf("%J\n", result); +-- End -- + +-- Expect stdout -- +{ "error": "NO_BOARD_NAME_MATCH", "rom_board_name": "unknown,device" } +-- End -- diff --git a/applications/luci-app-advanced-reboot/tests/01_error_handling/03_invalid_boot_arg b/applications/luci-app-advanced-reboot/tests/01_error_handling/03_invalid_boot_arg new file mode 100644 index 0000000000..70ff4c2721 --- /dev/null +++ b/applications/luci-app-advanced-reboot/tests/01_error_handling/03_invalid_boot_arg @@ -0,0 +1,28 @@ +Test boot_partition with missing or non-numeric number argument. + +-- File fs/open~_tmp_sysinfo_board_name.txt -- +linksys,e7350 +-- End -- + +-- Testcase -- +let ar = require('advanced_reboot'); +let api = ar["luci.advanced-reboot"]; + +// No args at all +let r1 = api.boot_partition.call(); +printf("no_args: %s\n", r1.error); + +// Empty object +let r2 = api.boot_partition.call({ args: {} }); +printf("empty: %s\n", r2.error); + +// Non-numeric +let r3 = api.boot_partition.call({ args: { number: "abc" } }); +printf("abc: %s\n", r3.error); +-- End -- + +-- Expect stdout -- +no_args: INVALID_ARG +empty: INVALID_ARG +abc: INVALID_ARG +-- End -- diff --git a/applications/luci-app-advanced-reboot/tests/01_error_handling/04_partition_not_found b/applications/luci-app-advanced-reboot/tests/01_error_handling/04_partition_not_found new file mode 100644 index 0000000000..d7781ff0a6 --- /dev/null +++ b/applications/luci-app-advanced-reboot/tests/01_error_handling/04_partition_not_found @@ -0,0 +1,20 @@ +Test boot_partition with a valid numeric partition that does not exist on the device. + +-- File fs/open~_tmp_sysinfo_board_name.txt -- +linksys,e7350 +-- End -- + +-- File fs/popen~fw_printenv_-n_bootimage_2_dev_null.txt -- +1 +-- End -- + +-- Testcase -- +let ar = require('advanced_reboot'); +let api = ar["luci.advanced-reboot"]; +let result = api.boot_partition.call({ args: { number: "9" } }); +printf("%J\n", result); +-- End -- + +-- Expect stdout -- +{ "error": "PARTITION_NOT_FOUND", "args": [ "9" ] } +-- End -- diff --git a/applications/luci-app-advanced-reboot/tests/02_obtain_device_info/01_linksys_e7350 b/applications/luci-app-advanced-reboot/tests/02_obtain_device_info/01_linksys_e7350 new file mode 100644 index 0000000000..ba248e377c --- /dev/null +++ b/applications/luci-app-advanced-reboot/tests/02_obtain_device_info/01_linksys_e7350 @@ -0,0 +1,57 @@ +Test obtain_device_info for Linksys E7350 with partition 1 active. +Uses fw_printenv params and kernel label fallback for alt partition. + +-- File fs/open~_tmp_sysinfo_board_name.txt -- +linksys,e7350 +-- End -- + +-- File fs/popen~fw_printenv_-n_bootimage_2_dev_null.txt -- +1 +-- End -- + +-- File fs/popen~_etc_os-release_2_dev_null_echo_OPENWRT_RELEASE_2_dev_null.txt -- +OpenWrt SNAPSHOT r28105-abcdef0123 +-- End -- + +-- File fs/open~_proc_version.txt -- +Linux version 6.6.63 (builder@buildhost) (aarch64-openwrt-linux-musl-gcc) #0 +-- End -- + +-- File fs/popen~dd_if_dev_mtd3_bs_1_skip_192_count_64.txt -- +Linux version 6.6.63 OpenWrt +-- End -- + +-- File fs/popen~dd_if_dev_mtd6_bs_1_skip_192_count_64.txt -- +Linux version 6.6.50 OpenWrt +-- End -- + +-- Testcase -- +let ar = require('advanced_reboot'); +let api = ar["luci.advanced-reboot"]; +let result = api.obtain_device_info.call(); + +// Verify device info +printf("vendor: %s\n", result.device.vendor); +printf("model: %s\n", result.device.model); +printf("board: %s\n", result.device.board); +printf("active: %s\n", result.device.partition_active); +printf("partitions: %d\n", length(result.partitions)); + +// Partition 1 (current) +let p1 = result.partitions[0]; +printf("p1: number=%s label=%s os=%s\n", p1.number, p1.label, p1.os); + +// Partition 2 (alternate — label from dd fallback) +let p2 = result.partitions[1]; +printf("p2: number=%s label=%s os=%s\n", p2.number, p2.label, p2.os); +-- End -- + +-- Expect stdout -- +vendor: Linksys +model: E7350 +board: linksys,e7350 +active: 1 +partitions: 2 +p1: number=1 label=OpenWrt SNAPSHOT r28105-abcdef0123 os=6.6.63 +p2: number=2 label=OpenWrt os=6.6.50 +-- End -- diff --git a/applications/luci-app-advanced-reboot/tests/02_obtain_device_info/02_zyxel_nbg6817 b/applications/luci-app-advanced-reboot/tests/02_obtain_device_info/02_zyxel_nbg6817 new file mode 100644 index 0000000000..475b7f843d --- /dev/null +++ b/applications/luci-app-advanced-reboot/tests/02_obtain_device_info/02_zyxel_nbg6817 @@ -0,0 +1,58 @@ +Test obtain_device_info for ZyXEL NBG6817 using the dual-flag method. +Partition 1 active (dual flag reads "ff" which matches partition 1's param_values). + +-- File fs/open~_tmp_sysinfo_board_name.txt -- +zyxel,nbg6817 +-- End -- + +-- File fs/popen~_lib_functions_sh_find_mtd_part_0_dual_flag_.txt -- +/dev/mtdblock12 +-- End -- + +-- File fs/popen~dd_if_dev_mtdblock12_bs_1_count_1_skip_0_2_dev_null_hexdump_-n_1_-e_1_1_02x_.txt -- +ff +-- End -- + +-- File fs/popen~_etc_os-release_2_dev_null_echo_OPENWRT_RELEASE_2_dev_null.txt -- +OpenWrt 24.10.0 r28427-6df0e3d02a +-- End -- + +-- File fs/open~_proc_version.txt -- +Linux version 6.6.63 (builder@buildhost) (arm-openwrt-linux-muslgnueabi-gcc) #0 +-- End -- + +-- File fs/popen~dd_if_dev_mmcblk0p4_bs_1_skip_32_count_64.txt -- +Linux version 6.6.63 OpenWrt +-- End -- + +-- File fs/popen~dd_if_dev_mmcblk0p7_bs_1_skip_32_count_64.txt -- +Linux-6.6.50 ZyXEL +-- End -- + +-- Testcase -- +let ar = require('advanced_reboot'); +let api = ar["luci.advanced-reboot"]; +let result = api.obtain_device_info.call(); + +printf("vendor: %s\n", result.device.vendor); +printf("model: %s\n", result.device.model); +printf("board: %s\n", result.device.board); +printf("active: %s\n", result.device.partition_active); +printf("partitions: %d\n", length(result.partitions)); + +let p1 = result.partitions[0]; +printf("p1: number=%s label=%s os=%s\n", p1.number, p1.label, p1.os); + +let p2 = result.partitions[1]; +printf("p2: number=%s label=%s os=%s\n", p2.number, p2.label, p2.os); +-- End -- + +-- Expect stdout -- +vendor: ZyXEL +model: NBG6817 +board: zyxel,nbg6817 +active: 1 +partitions: 2 +p1: number=1 label=OpenWrt 24.10.0 r28427-6df0e3d02a os=6.6.63 +p2: number=2 label=ZyXEL os=6.6.50 +-- End -- diff --git a/applications/luci-app-advanced-reboot/tests/02_obtain_device_info/03_zyxel_wsm20 b/applications/luci-app-advanced-reboot/tests/02_obtain_device_info/03_zyxel_wsm20 new file mode 100644 index 0000000000..9df51b24ea --- /dev/null +++ b/applications/luci-app-advanced-reboot/tests/02_obtain_device_info/03_zyxel_wsm20 @@ -0,0 +1,55 @@ +Test obtain_device_info for ZyXEL WSM20 using the dual-flag method with a +custom MTD partition ("persist") and byte offset (4). +Partition 1 active (the flag byte at offset 4 reads "01", matching partition 1). + +-- File fs/open~_tmp_sysinfo_board_name.txt -- +zyxel,wsm20 +-- End -- + +-- File fs/popen~_lib_functions_sh_find_mtd_part_persist_.txt -- +/dev/mtdblock7 +-- End -- + +-- File fs/popen~dd_if_dev_mtdblock7_bs_1_count_1_skip_4_2_dev_null_hexdump_-n_1_-e_1_1_02x_.txt -- +01 +-- End -- + +-- File fs/popen~_etc_os-release_2_dev_null_echo_OPENWRT_RELEASE_2_dev_null.txt -- +OpenWrt 25.12.2 r32802-f505120278 +-- End -- + +-- File fs/open~_proc_version.txt -- +Linux version 6.12.74 (builder@buildhost) (mipsel-openwrt-linux-musl-gcc) #0 +-- End -- + +-- File fs/popen~dd_if_dev_mtd6_bs_1_skip_32_count_64.txt -- +Linux-6.6.50 ZyXEL +-- End -- + +-- Testcase -- +let ar = require('advanced_reboot'); +let api = ar["luci.advanced-reboot"]; +let result = api.obtain_device_info.call(); + +printf("vendor: %s\n", result.device.vendor); +printf("model: %s\n", result.device.model); +printf("board: %s\n", result.device.board); +printf("active: %s\n", result.device.partition_active); +printf("partitions: %d\n", length(result.partitions)); + +let p1 = result.partitions[0]; +printf("p1: number=%s label=%s os=%s\n", p1.number, p1.label, p1.os); + +let p2 = result.partitions[1]; +printf("p2: number=%s label=%s os=%s\n", p2.number, p2.label, p2.os); +-- End -- + +-- Expect stdout -- +vendor: ZyXEL +model: WSM20 +board: zyxel,wsm20 +active: 1 +partitions: 2 +p1: number=1 label=OpenWrt 25.12.2 r32802-f505120278 os=6.12.74 +p2: number=2 label=ZyXEL os=6.6.50 +-- End -- diff --git a/applications/luci-app-advanced-reboot/tests/03_boot_partition/01_linksys_e7350_switch b/applications/luci-app-advanced-reboot/tests/03_boot_partition/01_linksys_e7350_switch new file mode 100644 index 0000000000..acb880941c --- /dev/null +++ b/applications/luci-app-advanced-reboot/tests/03_boot_partition/01_linksys_e7350_switch @@ -0,0 +1,24 @@ +Test boot_partition for Linksys E7350: switch to partition 2 (success). + +-- File fs/open~_tmp_sysinfo_board_name.txt -- +linksys,e7350 +-- End -- + +-- File fs/popen~fw_printenv_-n_bootimage_2_dev_null.txt -- +1 +-- End -- + +-- File fs/popen~fw_setenv_bootimage_2_2_dev_null_echo_.txt -- +0 +-- End -- + +-- Testcase -- +let ar = require('advanced_reboot'); +let api = ar["luci.advanced-reboot"]; +let result = api.boot_partition.call({ args: { number: "2" } }); +printf("%J\n", result); +-- End -- + +-- Expect stdout -- +{ } +-- End -- diff --git a/applications/luci-app-advanced-reboot/tests/03_boot_partition/02_set_env_failure b/applications/luci-app-advanced-reboot/tests/03_boot_partition/02_set_env_failure new file mode 100644 index 0000000000..6cc906d989 --- /dev/null +++ b/applications/luci-app-advanced-reboot/tests/03_boot_partition/02_set_env_failure @@ -0,0 +1,26 @@ +Test boot_partition when fw_setenv fails (non-zero exit code). + +-- File fs/open~_tmp_sysinfo_board_name.txt -- +linksys,e7350 +-- End -- + +-- File fs/popen~fw_printenv_-n_bootimage_2_dev_null.txt -- +1 +-- End -- + +-- File fs/popen~fw_setenv_bootimage_2_2_dev_null_echo_.txt -- +1 +-- End -- + +-- Testcase -- +let ar = require('advanced_reboot'); +let api = ar["luci.advanced-reboot"]; +let result = api.boot_partition.call({ args: { number: "2" } }); +printf("error: %s\n", result.error); +printf("args: %J\n", result.args); +-- End -- + +-- Expect stdout -- +error: ERR_SET_ENV +args: [ "bootimage", "2" ] +-- End -- diff --git a/applications/luci-app-advanced-reboot/tests/03_boot_partition/03_zyxel_wsm20_switch b/applications/luci-app-advanced-reboot/tests/03_boot_partition/03_zyxel_wsm20_switch new file mode 100644 index 0000000000..1e96c2303b --- /dev/null +++ b/applications/luci-app-advanced-reboot/tests/03_boot_partition/03_zyxel_wsm20_switch @@ -0,0 +1,25 @@ +Test boot_partition for ZyXEL WSM20: switch to partition 2 (success). +Writes the boot-number byte "02" at offset 4 of the "persist" partition. + +-- File fs/open~_tmp_sysinfo_board_name.txt -- +zyxel,wsm20 +-- End -- + +-- File fs/popen~_lib_functions_sh_find_mtd_part_persist_.txt -- +/dev/mtdblock7 +-- End -- + +-- File fs/popen~printf_b_x02_dd_of_dev_mtdblock7_bs_1_seek_4_count_1_conv_notrunc_2_dev_null_echo_.txt -- +0 +-- End -- + +-- Testcase -- +let ar = require('advanced_reboot'); +let api = ar["luci.advanced-reboot"]; +let result = api.boot_partition.call({ args: { number: "2" } }); +printf("%J\n", result); +-- End -- + +-- Expect stdout -- +{ } +-- End -- diff --git a/applications/luci-app-advanced-reboot/tests/lib/mocklib.uc b/applications/luci-app-advanced-reboot/tests/lib/mocklib.uc new file mode 100644 index 0000000000..152160bd8f --- /dev/null +++ b/applications/luci-app-advanced-reboot/tests/lib/mocklib.uc @@ -0,0 +1,248 @@ +/* strict mode compliance: ensure that global variables are defined */ +if (!exists(global, 'REQUIRE_SEARCH_PATH')) + global.REQUIRE_SEARCH_PATH = []; + +if (!exists(global, 'MOCK_SEARCH_PATH')) + global.MOCK_SEARCH_PATH = []; + +if (!exists(global, 'TRACE_CALLS')) + global.TRACE_CALLS = null; + +let _fs = require("fs"); + +/* Force reloading fs module on next require */ +delete global.modules.fs; + +let _log = (level, fmt, ...args) => { + let color, prefix; + + switch (level) { + case 'info': + color = 34; + prefix = '!'; + break; + + case 'warn': + color = 33; + prefix = 'W'; + break; + + case 'error': + color = 31; + prefix = 'E'; + break; + + default: + color = 0; + prefix = 'I'; + } + + let f = sprintf("\u001b[%d;1m[%s] %s\u001b[0m", color, prefix, fmt); + warn(replace(sprintf(f, ...args), "\n", "\n "), "\n"); +}; + +let read_data_file = (path) => { + for (let dir in MOCK_SEARCH_PATH) { + let fd = _fs.open(dir + '/' + path, "r"); + + if (fd) { + let data = fd.read("all"); + fd.close(); + + return data; + } + } + + return null; +}; + +let read_json_file = (path) => { + let data = read_data_file(path); + + if (data != null) { + try { + return json(data); + } + catch (e) { + _log('error', "Unable to parse JSON data in %s: %s", path, e); + + return NaN; + } + } + + return null; +}; + +let format_json = (data) => { + let rv; + + let format_value = (value) => { + switch (type(value)) { + case "object": + return sprintf("{ /* %d keys */ }", length(value)); + + case "array": + return sprintf("[ /* %d items */ ]", length(value)); + + case "string": + if (length(value) > 64) + value = substr(value, 0, 64) + "..."; + + /* fall through */ + return sprintf("%J", value); + + default: + return sprintf("%J", value); + } + }; + + switch (type(data)) { + case "object": + rv = "{"; + + let k = sort(keys(data)); + + for (let i, n in k) + rv += sprintf("%s %J: %s", i ? "," : "", n, format_value(data[n])); + + rv += " }"; + break; + + case "array": + rv = "["; + + for (let i, v in data) + rv += (i ? "," : "") + " " + format_value(v); + + rv += " ]"; + break; + + default: + rv = format_value(data); + } + + return rv; +}; + +let trace_call = (ns, func, args) => { + let msg = "[call] " + + (ns ? ns + "." : "") + + func; + + for (let k, v in args) { + msg += ' ' + k + ' <'; + + switch (type(v)) { + case "array": + case "object": + msg += format_json(v); + break; + + default: + msg += v; + } + + msg += '>'; + } + + switch (TRACE_CALLS) { + case '1': + case 'stdout': + _fs.stdout.write(msg + "\n"); + break; + + case 'stderr': + _fs.stderr.write(msg + "\n"); + break; + } +}; + +/* Captured file contents from mock writefile */ +let _captured = {}; + +/* Prepend mocklib to REQUIRE_SEARCH_PATH */ +for (let pattern in REQUIRE_SEARCH_PATH) { + if (!match(pattern, /\*\.uc$/)) + continue; + + let path = replace(pattern, /\*/, 'mocklib'), + stat = _fs.stat(path); + + if (!stat || stat.type != 'file') + continue; + + if (!length(global.MOCK_SEARCH_PATH)) + global.MOCK_SEARCH_PATH = [ replace(path, /mocklib\.uc$/, '../mocks') ]; + + unshift(REQUIRE_SEARCH_PATH, replace(path, /mocklib\.uc$/, 'mocklib/*.uc')); + break; +} + +if (!length(global.MOCK_SEARCH_PATH)) + global.MOCK_SEARCH_PATH = [ './mocks' ]; + +/* Register global mocklib namespace */ +global.mocklib = { + require: function(module) { + let path, res, ex; + + if (type(REQUIRE_SEARCH_PATH) == "array" && index(REQUIRE_SEARCH_PATH[0], 'mocklib/*.uc') != -1) + path = shift(REQUIRE_SEARCH_PATH); + + try { + res = require(module); + } + catch (e) { + ex = e; + } + + if (path) + unshift(REQUIRE_SEARCH_PATH, path); + + if (ex) + die(ex); + + return res; + }, + + I: (...args) => _log('info', ...args), + N: (...args) => _log('notice', ...args), + W: (...args) => _log('warn', ...args), + E: (...args) => _log('error', ...args), + + format_json, + read_data_file, + read_json_file, + trace_call, + + capture: (path, data) => { _captured[path] = data; }, + read_captured: (path) => _captured[path], + has_captured: (path) => exists(_captured, path), + delete_captured: (path) => { delete _captured[path]; }, +}; + +/* Override stdlib functions */ +global.system = function(argv, timeout) { + trace_call(null, "system", { command: argv, timeout }); + + return 0; +}; + +global.time = function() { + trace_call(null, "time"); + + return 1615382640; +}; + +global.print = ((_orig) => function(...args) { + if (length(args) == 1 && type(args[0]) in ["array", "object"]) + printf("%s\n", format_json(args[0])); + else + _orig(...args); +})(global.print); + +global.getenv = function(key) { + return null; +}; + +return global.mocklib; diff --git a/applications/luci-app-advanced-reboot/tests/lib/mocklib/fs.uc b/applications/luci-app-advanced-reboot/tests/lib/mocklib/fs.uc new file mode 100644 index 0000000000..3c531b9ba5 --- /dev/null +++ b/applications/luci-app-advanced-reboot/tests/lib/mocklib/fs.uc @@ -0,0 +1,124 @@ +let mocklib = global.mocklib; // ucode-lsp disable + +return { + readfile: function(path, limit) { + /* Check captured content first (from mock writefile) */ + if (mocklib.has_captured(path)) { + mocklib.trace_call("fs", "readfile", { path, limit, source: "captured" }); + let data = mocklib.read_captured(path); + return limit ? substr(data, 0, limit) : data; + } + + let file = sprintf("fs/open~%s.txt", replace(path, /[^A-Za-z0-9_-]+/g, '_')), + mock = mocklib.read_data_file(file); + + if (mock == null) { + /* Silently return null for missing fixtures */ + return null; + } + + mocklib.trace_call("fs", "readfile", { path, limit }); + + return limit ? substr(mock, 0, limit) : mock; + }, + + writefile: function(path, data) { + mocklib.capture(path, data); + mocklib.trace_call("fs", "writefile", { path, length: length(data) }); + + return length(data); + }, + + popen: (cmdline, mode) => { + let read = (!mode || index(mode, "r") != -1), + path = sprintf("fs/popen~%s.txt", replace(cmdline, /[^A-Za-z0-9_-]+/g, '_')), + mock = mocklib.read_data_file(path); + + if (read && mock == null) { + /* Silently return empty-read handle for missing fixtures */ + return { + read: function(amount) { return ''; }, + write: function() {}, + close: function() {}, + error: function() { return null; } + }; + } + + mocklib.trace_call("fs", "popen", { cmdline, mode }); + + return { + read: function(amount) { + let rv; + + switch (amount) { + case "all": + rv = mock; + mock = ""; + break; + + case "line": + let i = index(mock, "\n"); + i = (i > -1) ? i + 1 : length(mock); + rv = substr(mock, 0, i); + mock = substr(mock, i); + break; + + default: + let n = +amount; + n = (n > 0) ? n : 0; + rv = substr(mock, 0, n); + mock = substr(mock, n); + break; + } + + return rv; + }, + + write: function() {}, + close: function() {}, + + error: function() { + return null; + } + }; + }, + + stat: function(path) { + /* Check captured content first */ + if (mocklib.has_captured(path)) { + mocklib.trace_call("fs", "stat", { path, source: "captured" }); + return { type: "file" }; + } + + let file = sprintf("fs/stat~%s.json", replace(path, /[^A-Za-z0-9_-]+/g, '_')), + mock = mocklib.read_json_file(file); + + if (!mock || mock != mock) { + /* No fixture: fall back to reasonable defaults */ + if (match(path, /\/$/)) + mock = { type: "directory" }; + else + mock = { type: "file" }; + } + + mocklib.trace_call("fs", "stat", { path }); + + return mock; + }, + + glob: function(pattern) { + mocklib.trace_call("fs", "glob", { pattern }); + + /* Return empty array — tests use devices.json fixture directly */ + return []; + }, + + unlink: function(path) { + mocklib.delete_captured(path); + mocklib.trace_call("fs", "unlink", { path }); + + return true; + }, + + error: () => "Unspecified error" +}; diff --git a/applications/luci-app-advanced-reboot/tests/mocks/fs/open~_usr_share_advanced-reboot_devices_json.txt b/applications/luci-app-advanced-reboot/tests/mocks/fs/open~_usr_share_advanced-reboot_devices_json.txt new file mode 100644 index 0000000000..f2d4d8f835 --- /dev/null +++ b/applications/luci-app-advanced-reboot/tests/mocks/fs/open~_usr_share_advanced-reboot_devices_json.txt @@ -0,0 +1,102 @@ +[ + { + "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], + "firmware": { + "kernel": "mtd3", + "kernel_label_offset": 192, + "rootfs": "mtd4" + } + }, + { + "number": 2, + "param_values": [2], + "firmware": { + "kernel": "mtd6", + "kernel_label_offset": 192, + "rootfs": "mtd7" + } + } + ] + }, + { + "device": { + "vendor": "ZyXEL", + "model": "NBG6817", + "board": ["zyxel,nbg6817"] + }, + "commands": { + "params": [], + "get": null, + "set": null, + "save": null + }, + "partitions": [ + { + "number": 1, + "param_values": ["ff"], + "firmware": { + "kernel": "mmcblk0p4", + "kernel_label_offset": 32 + } + }, + { + "number": 2, + "param_values": ["01"], + "firmware": { + "kernel": "mmcblk0p7", + "kernel_label_offset": 32 + } + } + ] + }, + { + "device": { + "vendor": "ZyXEL", + "model": "WSM20", + "board": ["zyxel,wsm20"] + }, + "commands": { + "params": [], + "get": null, + "set": null, + "save": null, + "dual_flag": { + "mtd": "persist", + "offset": 4 + } + }, + "partitions": [ + { + "number": 1, + "param_values": ["01"], + "firmware": { + "kernel": "mtd4", + "kernel_label_offset": 32, + "rootfs": "mtd5" + } + }, + { + "number": 2, + "param_values": ["02"], + "firmware": { + "kernel": "mtd6", + "kernel_label_offset": 32 + } + } + ] + } +] diff --git a/applications/luci-app-advanced-reboot/tests/run_tests.sh b/applications/luci-app-advanced-reboot/tests/run_tests.sh new file mode 100644 index 0000000000..b13ae8a9f2 --- /dev/null +++ b/applications/luci-app-advanced-reboot/tests/run_tests.sh @@ -0,0 +1,344 @@ +#!/usr/bin/env bash +# Functional test runner for luci-app-advanced-reboot. +# +# Tests: +# 00: Device JSON validation (structure, required fields) +# 01: Error handling (missing board, unknown device, bad args) +# 02: obtain_device_info (fw_printenv, dual-flag) +# 03: boot_partition (switch, failure) +# +# Usage: cd source.mossdef.org/luci-app-advanced-reboot && bash tests/run_tests.sh + +set -o pipefail + +line='........................................' + +# ── Patch phase ───────────────────────────────────────────────────── +# Convert ES namespace import to require() so the mock framework can +# intercept the fs module through the module cache. + +patch_dir="/tmp/ar_test_modules.$$" +mkdir -p "$patch_dir" + +sed \ + -e 's|import \* as fs from "fs";|let fs = require("fs");|' \ + ./root/usr/share/rpcd/ucode/luci.advanced-reboot > "$patch_dir/advanced_reboot.uc" + +trap "rm -rf '$patch_dir'" EXIT + +# Search paths: patched module first, then tests/lib (for mocklib) +ucode="ucode -S -L$patch_dir -L./tests/lib" + +# ── Device JSON validation ────────────────────────────────────────── + +DEVICES_DIR="./root/usr/share/advanced-reboot/devices" + +n_tests=0 +n_fails=0 + +pass() { + printf " PASS: %s\n" "$1" +} +fail() { + printf " FAIL: %s\n" "$1" + [ -n "$2" ] && printf " %s\n" "$2" + n_fails=$((n_fails + 1)) +} + +if [ -d "$DEVICES_DIR" ]; then + printf "\n##\n## 00: Device JSON validation\n##\n\n" + + device_count=0 + for f in "$DEVICES_DIR"/*.json; do + [ -f "$f" ] || continue + device_count=$((device_count + 1)) + base="$(basename "$f")" + + # Valid JSON + n_tests=$((n_tests + 1)) + if ! jq empty "$f" 2>/dev/null; then + fail "$base: invalid JSON" + continue + fi + pass "$base: valid JSON" + + # Required: device.vendor + n_tests=$((n_tests + 1)) + vendor="$(jq -r '.device.vendor // empty' "$f")" + if [ -n "$vendor" ]; then + pass "$base: has device.vendor '$vendor'" + else + fail "$base: missing device.vendor" + fi + + # Required: device.model + n_tests=$((n_tests + 1)) + model="$(jq -r '.device.model // empty' "$f")" + if [ -n "$model" ]; then + pass "$base: has device.model '$model'" + else + fail "$base: missing device.model" + fi + + # Required: device.board (must be array) + n_tests=$((n_tests + 1)) + board_type="$(jq -r '.device.board | type' "$f")" + if [ "$board_type" = "array" ]; then + board_len="$(jq '.device.board | length' "$f")" + if [ "$board_len" -gt 0 ]; then + pass "$base: device.board is array with $board_len entries" + else + fail "$base: device.board is empty array" + fi + else + fail "$base: device.board is not an array (got $board_type)" + fi + + # Required: partitions (must be array with >= 2 entries) + n_tests=$((n_tests + 1)) + part_type="$(jq -r '.partitions | type' "$f")" + if [ "$part_type" = "array" ]; then + part_len="$(jq '.partitions | length' "$f")" + if [ "$part_len" -ge 2 ]; then + pass "$base: has $part_len partitions" + else + fail "$base: need >= 2 partitions (got $part_len)" + fi + else + fail "$base: partitions is not an array" + fi + + # Each partition must have number and param_values + for i in $(seq 0 $((part_len - 1))); do + n_tests=$((n_tests + 1)) + has_num="$(jq ".partitions[$i] | has(\"number\")" "$f")" + has_pv="$(jq ".partitions[$i] | has(\"param_values\")" "$f")" + if [ "$has_num" = "true" ] && [ "$has_pv" = "true" ]; then + pass "$base: partition $i has number and param_values" + else + fail "$base: partition $i missing number ($has_num) or param_values ($has_pv)" + fi + done + done + + printf "\n Validated %d device files\n" "$device_count" +fi + +# ── Mock-based functional tests ──────────────────────────────────── + +extract_sections() { + local file=$1 + local dir=$2 + local count=0 + local tag line outfile + + while IFS= read -r line; do + case "$line" in + "-- Testcase --") + tag="test" + count=$((count + 1)) + outfile=$(printf "%s/%03d.in" "$dir" $count) + printf "" > "$outfile" + ;; + "-- Environment --") + tag="env" + count=$((count + 1)) + outfile=$(printf "%s/%03d.env" "$dir" $count) + printf "" > "$outfile" + ;; + "-- Expect stdout --"|"-- Expect stderr --"|"-- Expect exitcode --") + tag="${line#-- Expect }" + tag="${tag% --}" + count=$((count + 1)) + outfile=$(printf "%s/%03d.%s" "$dir" $count "$tag") + printf "" > "$outfile" + ;; + "-- File "*" --") + tag="file" + outfile="${line#-- File }" + outfile="$(echo "${outfile% --}" | xargs)" + outfile="$dir/files$(readlink -m "/${outfile:-file}")" + mkdir -p "$(dirname "$outfile")" + printf "" > "$outfile" + ;; + "-- End --") + tag="" + outfile="" + ;; + *) + if [ -n "$tag" ]; then + printf "%s\\n" "$line" >> "$outfile" + fi + ;; + esac + done < "$file" + + return $(ls -l "$dir/"*.in 2>/dev/null | wc -l) +} + +run_testcase() { + local num=$1 + local dir=$2 + local in=$3 + local env=$4 + local out=$5 + local err=$6 + local code=$7 + local fail=0 + + $ucode \ + -D MOCK_SEARCH_PATH='["'"$dir"'/files", "./tests/mocks"]' \ + ${env:+-F "$env"} \ + -l mocklib \ + - <"$in" >"$dir/res.out" 2>"$dir/res.err" + + printf "%d\n" $? > "$dir/res.code" + + touch "$dir/empty" + + if ! cmp -s "$dir/res.err" "${err:-$dir/empty}"; then + [ $fail = 0 ] && printf "!\n" + printf "Testcase #%d: Expected stderr did not match:\n" $num + diff -u --color=always --label="Expected stderr" --label="Resulting stderr" "${err:-$dir/empty}" "$dir/res.err" + printf -- "---\n" + fail=1 + fi + + if ! cmp -s "$dir/res.out" "${out:-$dir/empty}"; then + [ $fail = 0 ] && printf "!\n" + printf "Testcase #%d: Expected stdout did not match:\n" $num + diff -u --color=always --label="Expected stdout" --label="Resulting stdout" "${out:-$dir/empty}" "$dir/res.out" + printf -- "---\n" + fail=1 + fi + + if [ -n "$code" ] && ! cmp -s "$dir/res.code" "$code"; then + [ $fail = 0 ] && printf "!\n" + printf "Testcase #%d: Expected exit code did not match:\n" $num + diff -u --color=always --label="Expected code" --label="Resulting code" "$code" "$dir/res.code" + printf -- "---\n" + fail=1 + fi + + return $fail +} + +run_test() { + local file=$1 + local name=${file##*/} + local res ecode eout eerr ein eenv tests + local testcase_first=0 failed=0 count=0 + + printf "%s %s " "$name" "${line:${#name}}" + + mkdir "/tmp/test.$$" + + extract_sections "$file" "/tmp/test.$$" + tests=$? + + [ -f "/tmp/test.$$/001.in" ] && testcase_first=1 + + for res in "/tmp/test.$$/"[0-9]*; do + case "$res" in + *.in) + count=$((count + 1)) + + if [ $testcase_first = 1 ]; then + # Flush previous test + if [ -n "$ein" ]; then + run_testcase $count "/tmp/test.$$" "$ein" "$eenv" "$eout" "$eerr" "$ecode" || failed=$((failed + 1)) + + eout="" + eerr="" + ecode="" + eenv="" + fi + + ein=$res + else + run_testcase $count "/tmp/test.$$" "$res" "$eenv" "$eout" "$eerr" "$ecode" || failed=$((failed + 1)) + + eout="" + eerr="" + ecode="" + eenv="" + fi + + ;; + *.env) eenv=$res ;; + *.stdout) eout=$res ;; + *.stderr) eerr=$res ;; + *.exitcode) ecode=$res ;; + esac + done + + # Flush last test + if [ $testcase_first = 1 ] && [ -n "$ein" ]; then + run_testcase $count "/tmp/test.$$" "$ein" "$eenv" "$eout" "$eerr" "$ecode" || failed=$((failed + 1)) + fi + + rm -r "/tmp/test.$$" + + if [ $failed = 0 ]; then + printf "OK\n" + else + printf "%s %s FAILED (%d/%d)\n" "$name" "${line:${#name}}" $failed $tests + fi + + return $failed +} + + +select_tests="$@" + +use_test() { + local input="$(readlink -f "$1")" + local test + + [ -f "$input" ] || return 1 + [ -n "$select_tests" ] || return 0 + + for test in $select_tests; do + test="$(readlink -f "$test")" + + [ "$test" != "$input" ] || return 0 + done + + return 1 +} + +for catdir in tests/[0-9][0-9]_*; do + [ -d "$catdir" ] || continue + + printf "\n##\n## Running %s tests\n##\n\n" "${catdir##*/[0-9][0-9]_}" + + for testfile in "$catdir/"[0-9][0-9]_*; do + use_test "$testfile" || continue + + n_tests=$((n_tests + 1)) + run_test "$testfile" || n_fails=$((n_fails + 1)) + done +done + +# ── Shell script syntax checks ────────────────────────────────────── + +printf "\n##\n## Checking shell script syntax\n##\n\n" +for shellscript in \ + root/etc/uci-defaults/* \ + root/usr/share/advanced-reboot/helpers/*.sh; do + [ -f "$shellscript" ] || continue + head -1 "$shellscript" | grep -q '^#!/bin/sh' || continue + name="${shellscript#root/}" + n_tests=$((n_tests + 1)) + printf "%s %s " "$name" "${line:${#name}}" + if sh -n "$shellscript" 2>/dev/null; then + printf "OK\n" + else + printf "FAIL\n" + sh -n "$shellscript" + n_fails=$((n_fails + 1)) + fi +done + +printf "\nRan %d tests, %d okay, %d failures\n" $n_tests $((n_tests - n_fails)) $n_fails +exit $n_fails