PKG_LICENSE:=GPL-3.0-or-later
PKG_MAINTAINER:=Stan Grishin <stangri@melmac.net>
+PKG_VERSION:=1.0.0-1
LUCI_TITLE:=Advanced Linksys Reboot Web UI
+LUCI_URL:=https://docs.openwrt.melmac.net/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://github.com/openwrt/luci/blob/master/applications/luci-app-advanced-reboot/README.md
-LUCI_DEPENDS:=+luci-compat +luci-mod-admin-full
+ routers are listed at https://docs.openwrt.melmac.net/luci-app-advanced-reboot/
+LUCI_DEPENDS:=+luci-mod-admin-full +jshn
LUCI_PKGARCH:=all
-PKG_RELEASE:=54
include ../../luci.mk
# Advanced Reboot Web UI (luci-app-advanced-reboot)
-## Description
-
-This package allows you to reboot to an alternative partition on the supported (dual-partition) routers and to power off (power down) your OpenWrt device.
-
-## Supported Devices
-
-Currently supported dual-partition devices include:
-
-- Linksys EA3500
-- Linksys E4200v2
-- Linksys EA4500
-- Linksys EA6350v3
-- Linksys EA8300
-- Linksys EA8500
-- Linksys WRT1200AC
-- Linksys WRT1900AC
-- Linksys WRT1900ACv2
-- Linksys WRT1900ACS
-- Linksys WRT3200ACM
-- Linksys WRT32X
-- ZyXEL NBG6817
-
-If your device is not in the list above, however it is a [dual-firmware device](https://openwrt.org/tag/dual_firmware?do=showtag&tag=dual_firmware) and you're interested in having your device supported, please post in [OpenWrt Forum Support Thread](https://forum.openwrt.org/t/web-ui-to-reboot-to-another-partition-dual-partition-routers/3423).
-
-## Screenshot (luci-app-advanced-reboot)
-
-![screenshot](https://cdn.jsdelivr.net/gh/stangri/openwrt_packages@master/screenshots/luci-app-advanced-reboot/screenshot02.png "screenshot")
-
-## How to install
-
-Install ```luci-app-advanced-reboot``` from Web UI or connect to your router via ssh and run the following commands:
-
-```sh
-opkg update
-opkg install luci-app-advanced-reboot
-```
-
-If the ```luci-app-advanced-reboot``` package is not found in the official feed/repo for your version of OpenWrt/LEDE Project, you will need to add a custom repo to your router following instructions on [GitHub](https://github.com/stangri/openwrt_packages/blob/master/README.md#on-your-router)/[jsDelivr](https://cdn.jsdelivr.net/gh/stangri/openwrt_packages@master/README.md#on-your-router) first.
-
-## Notes/Known Issues
-
-- When you reboot to a different partition, your current settings (WiFi SSID/password, etc.) will not apply to a different partition. Different partitions might have completely different settings and even firmware.
-- If you reboot to a partition which doesn't allow you to switch boot partitions (like stock vendor firmware), you might not be able to boot back to OpenWrt unless you reflash it, losing all the settings.
-- Some devices allow you to trigger reboot to an alternative partition by interrupting boot 3 times in a row (by resetting/switching off the device or pulling power). As these methods might be different for different devices, do your own homework.
-- Newer versions of this package try to mount alternative partition on compatible NAND routers in order to retrieve detailed firmware information. When that happens, it is normal to have messages similar to the below in the system log:
-
- ```sh
- Tue Nov 19 15:45:03 2019 user.notice luci-app-advanced-reboot: attempting to mount alternative partition (mtd6)
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30392.673826] ubi2: attaching mtd6
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30392.876698] ubi2: scanning is finished
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30392.885267] ubi2: attached mtd6 (name "rootfs1", size 74 MiB)
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30392.891063] ubi2: PEB size: 131072 bytes (128 KiB), LEB size: 126976 bytes
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30392.898011] ubi2: min./max. I/O unit sizes: 2048/2048, sub-page size 2048
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30392.904878] ubi2: VID header offset: 2048 (aligned 2048), data offset: 4096
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30392.911928] ubi2: good PEBs: 592, bad PEBs: 0, corrupted PEBs: 0
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30392.917962] ubi2: user volume: 2, internal volumes: 1, max. volumes count: 128
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30392.925252] ubi2: max/mean erase counter: 48/32, WL threshold: 4096, image sequence number: 1659081076
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30392.934623] ubi2: available PEBs: 0, total reserved PEBs: 592, PEBs reserved for bad PEB handling: 40
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30392.944346] ubi2: background thread "ubi_bgt2d" started, PID 26780
- Tue Nov 19 15:45:03 2019 kern.info kernel: [30392.952596] block ubiblock2_0: created from ubi2:0 (rootfs)
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30392.964083] UBIFS (ubi2:1): background thread "ubifs_bgt2_1" started, PID 26787
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30393.009298] UBIFS (ubi2:1): UBIFS: mounted UBI device 2, volume 1, name "rootfs_data"
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30393.017185] UBIFS (ubi2:1): LEB size: 126976 bytes (124 KiB), min./max. I/O unit sizes: 2048 bytes/2048 bytes
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30393.027213] UBIFS (ubi2:1): FS size: 61075456 bytes (58 MiB, 481 LEBs), journal size 3047424 bytes (2 MiB, 24 LEBs)
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30393.037733] UBIFS (ubi2:1): reserved for root: 2884744 bytes (2817 KiB)
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30393.044389] UBIFS (ubi2:1): media format: w4/r0 (latest is w5/r0), UUID 76F0C52C-6197-4E00-B306-747262B06545, small LPT model
- Tue Nov 19 15:45:03 2019 user.notice luci-app-advanced-reboot: attempting to unmount alternative partition (mtd6)
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30393.132743] UBIFS (ubi2:1): un-mount UBI device 2
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30393.137481] UBIFS (ubi2:1): background thread "ubifs_bgt2_1" stops
- Tue Nov 19 15:45:03 2019 kern.info kernel: [30393.390961] block ubiblock2_0: released
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30393.396576] ubi2: detaching mtd6
- Tue Nov 19 15:45:03 2019 kern.notice kernel: [30393.400117] ubi2: mtd6 is detached
- ```
-
-## Thanks
-
-I'd like to thank everyone who helped create, test and troubleshoot this package. Without help from [@hnyman](https://github.com/hnyman), [@jpstyves](https://github.com/jpstyves), [@imi2003](https://github.com/imi2003), [@jeffsf](https://github.com/jeffsf) and many contributions from [@slh](https://github.com/pkgadd) it wouldn't have been possible.
+README has been moved to [https://docs.openwrt.melmac.net/luci-app-advanced-reboot/](<https://docs.openwrt.melmac.net/luci-app-advanced-reboot/>).
--- /dev/null
+'use strict';
+'require view';
+'require rpc';
+'require ui';
+'require uci';
+'require fs';
+
+return view.extend({
+ translateTable: {
+ NO_BOARD_NAME : function(args) { return _('Unable to find Device Board Name.')},
+ NO_DUAL_FLAG : function(args) {return _('Unable to find Dual Boot Flag Partition.')},
+ ERR_SET_DUAL_FLAG : function(args) { return _('Unable to set Dual Boot Flag Partition entry for partition: %s.').format(args[0])},
+ NO_FIRM_ENV : function(args) { return _('Unable to obtain firmware environment variable: %s.').format(args[0])},
+ ERR_SET_ENV : function(args) { return _('Unable to set firmware environment variable: %s to %s.').format(args[0],args[1])}
+ },
+
+ callReboot: rpc.declare({
+ object: 'system',
+ method: 'reboot',
+ expect: { result: 0 }
+ }),
+
+ callObtainDeviceInfo: rpc.declare({
+ object: 'luci.advanced_reboot',
+ method: 'obtain_device_info',
+ expect: { }
+ }),
+
+ callTogglePartition: rpc.declare({
+ object: 'luci.advanced_reboot',
+ method: 'toggle_boot_partition',
+ expect: { }
+ }),
+
+ callPowerOff: function() {
+ return fs.exec('/sbin/poweroff').then(function() {
+ ui.showModal(_('Shutting down...'), [
+ E('p', { 'class': 'spinning' }, _('The system is shutting down now.<br /> DO NOT POWER OFF THE DEVICE!<br /> It might be necessary to renew the address of your computer to reach the device again, depending on your settings.'))
+ ]);
+ })
+ },
+
+ handlePowerOff: function() {
+
+ ui.showModal(_('Power Off Device'), [
+ E('p', _("WARNING: Power off might result in a reboot on a device which doesn't support power off.<br /><br />\
+ Click \"Proceed\" below to power off your device.")),
+ E('div', { 'class': 'right' }, [
+ E('button', {
+ 'class': 'btn',
+ 'click': ui.hideModal
+ }, _('Cancel')), ' ',
+ E('button', {
+ 'class': 'btn cbi-button cbi-button-positive important',
+ 'click': L.bind(this.callPowerOff, this)
+ }, _('Proceed'))
+ ])
+ ]);
+
+ },
+
+ handleReboot: function(ev) {
+ return this.callReboot().then(function(res) {
+ if (res != 0) {
+ ui.addNotification(null, E('p', _('The reboot command failed with code %d').format(res)));
+ L.raise('Error', 'Reboot failed');
+ }
+
+ ui.showModal(_('Rebooting…'), [
+ E('p', { 'class': 'spinning' }, _('Waiting for device...'))
+ ]);
+
+ window.setTimeout(function() {
+ ui.showModal(_('Rebooting…'), [
+ E('p', { 'class': 'spinning alert-message warning' },
+ _('Device unreachable! Still waiting for device...'))
+ ]);
+ }, 150000);
+
+ ui.awaitReconnect();
+ })
+ .catch(function(e) { ui.addNotification(null, E('p', e.message)) });
+ },
+
+ handleTogglePartition: function(ev) {
+ return this.callTogglePartition().then(L.bind(function(res) {
+ if (res.error) {
+ ui.hideModal()
+ return ui.addNotification(null, E('p', this.translateTable[res.error](res.args)));
+ }
+
+ return this.callReboot().then(function(res) {
+ if (res != 0) {
+ ui.addNotification(null, E('p', _('The reboot command failed with code %d').format(res)));
+ L.raise('Error', 'Reboot failed');
+ }
+
+ ui.showModal(_('Rebooting…'), [
+ E('p', { 'class': 'spinning' }, _('The system is rebooting to an alternative partition now.<br /> DO NOT POWER OFF THE DEVICE!<br /> Wait a few minutes before you try to reconnect. It might be necessary to renew the address of your computer to reach the device again, depending on your settings.'))
+ ]);
+
+ window.setTimeout(function() {
+ ui.showModal(_('Rebooting…'), [
+ E('p', { 'class': 'spinning alert-message warning' },
+ _('Device unreachable! Still waiting for device...'))
+ ]);
+ }, 150000);
+
+ ui.awaitReconnect();
+ })
+ .catch(function(e) { ui.addNotification(null, E('p', e.message)) });
+ }, this));
+ },
+
+ handleAlternativeReboot: function(ev) {
+ return Promise.all([
+ L.resolveDefault(fs.stat('/usr/sbin/fw_printenv'), null),
+ L.resolveDefault(fs.stat('/usr/sbin/fw_setenv'), null),
+ ]).then(L.bind(function (data) {
+ if (!data[0] || !data[1]) {
+ return ui.addNotification(null, E('p', _('No access to fw_printenv or fw_printenv!')));
+ }
+
+ ui.showModal(_('Reboot Device to an Alternative Partition') + " - " + _("Confirm"), [
+ E('p', _("WARNING: An alternative partition might have its own settings and completely different firmware.<br /><br />\
+ As your network configuration and WiFi SSID/password on alternative partition might be different,\
+ you might have to adjust your computer settings to be able to access your device once it reboots.<br /><br />\
+ Please also be aware that alternative partition firmware might not provide an easy way to switch active partition\
+ and boot back to the currently active partition.<br /><br />\
+ Click \"Proceed\" below to reboot device to an alternative partition.")),
+ E('div', { 'class': 'right' }, [
+ E('button', {
+ 'class': 'btn',
+ 'click': ui.hideModal
+ }, _('Cancel')), ' ',
+ E('button', {
+ 'class': 'btn cbi-button cbi-button-positive important',
+ 'click': L.bind(this.handleTogglePartition, this)
+ }, _('Proceed'))
+ ])
+ ]);
+ }, this))
+ },
+
+ parsePartitions: function(partitions) {
+ var res = [];
+
+ partitions.forEach(L.bind(function(partition) {
+ var func, text;
+
+ if (partition.state == 'Current') {
+ func = 'handleReboot';
+ text = _('Reboot to current partition');
+ } else {
+ func = 'handleAlternativeReboot';
+ text = _('Reboot to alternative partition...');
+ }
+
+ res.push([
+ (partition.number+0x100).toString(16).substr(-2).toUpperCase(),
+ _(partition.state),
+ partition.os.replace("Unknown", _("Unknown")).replace("Compressed", _("Compressed")),
+ E('button', {
+ 'class': 'btn cbi-button cbi-button-apply important',
+ 'click': ui.createHandlerFn(this, func)
+ }, text)
+ ])
+ }, this));
+
+ return res;
+ },
+
+ load: function() {
+ return Promise.all([
+ uci.changes(),
+ L.resolveDefault(fs.stat('/sbin/poweroff'), null),
+ this.callObtainDeviceInfo()
+ ]);
+ },
+
+ render: function(data) {
+ var changes = data[0],
+ poweroff_supported = data[1] != null ? true : false,
+ device_info = data[2];
+
+ var body = E([
+ E('h2', _('Advanced Reboot'))
+ ]);
+
+ for (var config in (changes || {})) {
+ body.appendChild(E('p', { 'class': 'alert-message warning' },
+ _('Warning: There are unsaved changes that will get lost on reboot!')));
+ break;
+ }
+
+ if (device_info.error)
+ body.appendChild(E('p', { 'class' : 'alert-message warning'}, _("ERROR: ") + this.translateTable[device_info.error]()));
+
+ body.appendChild(E('h3', device_info.device_name + _(' Partitions')));
+ if (device_info.device_name) {
+ var partitions_table = E('table', { 'class': 'table' }, [
+ E('tr', { 'class': 'tr table-titles' }, [
+ E('th', { 'class': 'th' }, [ _('Partition') ]),
+ E('th', { 'class': 'th' }, [ _('Status') ]),
+ E('th', { 'class': 'th' }, [ _('Firmware') ]),
+ E('th', { 'class': 'th' }, [ _('Reboot') ])
+ ])
+ ]);
+
+ cbi_update_table(partitions_table, this.parsePartitions(device_info.partitions));
+
+ body.appendChild(partitions_table);
+ } else {
+ body.appendChild(E('p', { 'class' : 'alert-message warning'},
+ device_info.rom_board_name ? _("Warning: Device (%s) is unknown or isn't a dual-partition device!").format(device_info.rom_board_name)
+ : _('Warning: Unable to obtain device information!')
+ ));
+ }
+
+ body.appendChild(E('hr'));
+ body.appendChild(
+ poweroff_supported ? E('button', {
+ 'class': 'btn cbi-button cbi-button-apply important',
+ 'click': ui.createHandlerFn(this, 'handlePowerOff')
+ }, _('Perform power off...'))
+
+ : E('p', { 'class' : 'alert-message warning'},
+ _('Warning: This system does not support powering off!'))
+ );
+
+ return body;
+ },
+
+ handleSaveApply: null,
+ handleSave: null,
+ handleReset: null
+});
#!/bin/sh
+/etc/init.d/rpcd reload
rm -rf /var/luci-modulecache/; rm -f /var/luci-indexcache;
exit 0
-
--- /dev/null
+#!/bin/sh
+# Copyright 2017-2020 Stan Grishin (stangri@melmac.net)
+# shellcheck disable=SC2039,SC1091
+
+readonly devices_dir="/usr/share/advanced-reboot/devices/"
+
+. /lib/functions.sh
+. /usr/share/libubox/jshn.sh
+
+logger() { /usr/bin/logger -t advanced-reboot "$1"; }
+is_present() { command -v "$1" >/dev/null 2>&1; }
+
+is_alt_mountable() {
+ local p1_mtd="$1" p2_mtd="$2"
+ if [ "${p1_mtd:0:3}" = "mtd" ] && [ "${p2_mtd:0:3}" = "mtd" ] && \
+ is_present 'ubiattach' && \
+ is_present 'ubiblock' && \
+ is_present 'mount'; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+alt_partition_mount() {
+ local ubi_dev op_ubi="$1"
+ mkdir -p /var/alt_rom
+ ubi_dev="$(ubiattach -m "$op_ubi")"
+ ubi_dev="$(echo "$ubi_dev" | sed -n "s/^UBI device number\s*\(\d*\),.*$/\1/p")"
+ if [ -z "$ubi_dev" ]; then
+ ubidetach -m "$op_ubi"
+ return 1
+ fi
+ ubiblock --create "/dev/ubi${ubi_dev}_0" && \
+ mount -t squashfs -r "/dev/ubiblock${ubi_dev}_0" /var/alt_rom
+}
+
+alt_partition_unmount() {
+ local mtdCount i=0 op_ubi="$1"
+ mtdCount="$(ubinfo | grep 'Present UBI devices' | tr ',' '\n' | grep -c 'ubi')"
+ [ -z "$mtdCount" ] && mtdCount=10
+ [ -d /var/alt_rom ] && umount /var/alt_rom
+ while [ "$i" -le "$mtdCount" ]; do
+ if [ ! -e "/sys/devices/virtual/ubi/ubi${i}/mtd_num" ]; then
+ break
+ fi
+ ubi_mtd="$(cat /sys/devices/virtual/ubi/ubi${i}/mtd_num)"
+ if [ -n "$ubi_mtd" ] && [ "$ubi_mtd" = "$op_ubi" ]; then
+ ubiblock --remove /dev/ubi${i}_0
+ ubidetach -m "$op_ubi"
+ rm -rf /var/alt_rom
+ fi
+ i=$((i + 1))
+ done
+}
+
+get_main_partition_os_info(){
+ local cp_info
+ if [ -s "/etc/os-release" ]; then
+ cp_info="$(. /etc/os-release && echo "$PRETTY_NAME")"
+ if [ "${cp_info//SNAPSHOT}" != "$cp_info" ]; then
+ cp_info="$(. /etc/os-release && echo "${OPENWRT_RELEASE%%-*}")"
+ fi
+ fi
+ echo "$cp_info"
+}
+
+get_alt_partition_os_info(){
+ local op_info op_ubi="$1"
+ logger "attempting to mount alternative partition (mtd${op_ubi})"
+ alt_partition_unmount "$op_ubi"
+ alt_partition_mount "$op_ubi"
+ if [ -s "/var/alt_rom/etc/os-release" ]; then
+ op_info="$(. /var/alt_rom/etc/os-release && echo "$PRETTY_NAME")"
+ if [ "${op_info//SNAPSHOT}" != "$op_info" ]; then
+ op_info="$(. /var/alt_rom/etc/os-release && echo "${OPENWRT_RELEASE%%-*}")"
+ fi
+ fi
+ logger "attempting to unmount alternative partition (mtd${op_ubi})"
+ alt_partition_unmount "$op_ubi"
+ echo "$op_info"
+}
+
+find_device_data(){
+ local boardNames filename i romBoardName="$1"
+ for filename in "${devices_dir}"*.json; do
+ [ "$filename" = "${devices_dir}*.json" ] && return
+ json_load_file "$filename"
+ json_get_values boardNames 'boardNames'
+ json_cleanup
+ for i in $boardNames; do
+ if [ "$i" = "$romBoardName" ]; then
+ echo "$filename"
+ return
+ fi
+ done
+ done
+}
+
+print_json() { json_init; json_add_string "$1" "$2"; json_dump; json_cleanup; }
+
+obtain_device_info(){
+ local romBoardName p zyxelFlagPartition
+ local vendorName deviceName partition1MTD partition2MTD labelOffset
+ local bootEnv1 bootEnv1Partition1Value bootEnv1Partition2Value
+ local bootEnv2 bootEnv2Partition1Value bootEnv2Partition2Value
+ local p1_label p1_version p2_label p2_version p1_os p2_os
+ local current_partition op_ubi cp_info op_info
+
+ romBoardName="$(cat /tmp/sysinfo/board_name)"
+ if [ -z "$romBoardName" ]; then
+ print_json 'error' 'NO_BOARD_NAME'
+ return
+ fi
+
+ p="$(find_device_data "$romBoardName")"
+ if [ -z "$p" ] || [ ! -s "$p" ]; then
+ print_json 'rom_board_name' "$romBoardName"
+ return
+ fi
+
+ json_load_file "$p"
+ for i in vendorName deviceName partition1MTD partition2MTD labelOffset \
+ bootEnv1 bootEnv1Partition1Value bootEnv1Partition2Value \
+ bootEnv2 bootEnv2Partition1Value bootEnv2Partition2Value; do
+ json_get_var $i "$i"
+ done
+ json_cleanup
+
+ if [ -n "$labelOffset" ]; then
+ if [ -n "$partition1MTD" ]; then
+ p1_label="$(dd if="/dev/${partition1MTD}" bs=1 skip="${labelOffset}" count=64 2>/dev/null)"
+ if [ -n "$p1_label" ]; then
+ p1_version="$(echo "$p1_label" | sed -n "s/\(.*\)Linux-\([0-9.]\+\).*$/\2/p")"
+ if [ "${p1_label//LEDE}" != "$p1_label" ]; then p1_os="LEDE"; fi
+ if [ "${p1_label//OpenWrt}" != "$p1_label" ]; then p1_os="OpenWrt"; fi
+ if [ -n "$vendorName" ] && [ "${p1_label//$vendorName}" != "$p1_label" ]; then
+ p1_os="$vendorName"
+ fi
+ fi
+ if [ -z "$p1_os" ]; then
+ p1_os="${vendorName:-Unknown}/Unknown"
+ fi
+ fi
+
+ if [ -n "$partition2MTD" ]; then
+ p2_label="$(dd if="/dev/${partition2MTD}" bs=1 skip="${labelOffset}" count=64 2>/dev/null)"
+ if [ -n "$p2_label" ]; then
+ p2_version="$(echo "$p2_label" | sed -n "s/\(.*\)Linux-\([0-9.]\+\).*$/\2/p")"
+ if [ "${p2_label//LEDE}" != "$p2_label" ]; then p2_os="LEDE"; fi
+ if [ "${p2_label//OpenWrt}" != "$p2_label" ]; then p2_os="OpenWrt"; fi
+ if [ -n "$vendorName" ] && [ "${p2_label//$vendorName}" != "$p2_label" ]; then
+ p2_os="$vendorName"
+ fi
+ fi
+ if [ -z "$p2_os" ]; then
+ p2_os="${vendorName:-Unknown}/Unknown"
+ fi
+ fi
+ else
+ p1_os="${vendorName}/Unknown (Compressed)"
+ p2_os="${vendorName}/Unknown (Compressed)"
+ fi
+
+ if [ -n "$bootEnv1" ]; then
+ if [ -x "/usr/sbin/fw_printenv" ] && [ -x "/usr/sbin/fw_setenv" ]; then
+ current_partition="$(/usr/sbin/fw_printenv -n "${bootEnv1}")"
+ fi
+ else
+ if [ -z "$zyxelFlagPartition" ]; then
+ zyxelFlagPartition="$(find_mtd_part 0:DUAL_FLAG 2>/dev/null)"
+ fi
+ if [ -n "$zyxelFlagPartition" ]; then
+ current_partition="$(dd if="${zyxelFlagPartition}" bs=1 count=1 2>/dev/null | hexdump -n 1 -e '1/1 "%d"')"
+ else
+ print_json 'error' 'NO_DUAL_FLAG'
+ logger "Unable to find Dual Boot Environment or Dual Boot Flag Partition."
+ return
+ fi
+ fi
+
+ if is_alt_mountable "$partition1MTD" "$partition2MTD"; then
+ if [ "$current_partition" = "$bootEnv1Partition1Value" ]; then
+ op_ubi=$(( ${partition2MTD:3:3} + 1 ))
+ else
+ op_ubi=$(( ${partition1MTD:3:3} + 1 ))
+ fi
+ cp_info="$(get_main_partition_os_info $op_ubi)"
+ op_info="$(get_alt_partition_os_info $op_ubi)"
+ if [ "$current_partition" = "$bootEnv1Partition1Value" ]; then
+ p1_os="${cp_info:-$p1_os}"
+ p2_os="${op_info:-$p2_os}"
+ else
+ p1_os="${op_info:-$p1_os}"
+ p2_os="${cp_info:-$p2_os}"
+ fi
+ fi
+ if [ -n "$p1_os" ] && [ -n "$p1_version" ]; then
+ p1_os="$p1_os (Linux ${p1_version})"
+ fi
+ if [ -n "$p2_os" ] && [ -n "$p2_version" ]; then
+ p2_os="$p2_os (Linux ${p2_version})"
+ fi
+
+
+ json_init
+ json_add_int 'current_partition' "$current_partition"
+ json_add_string 'device_name' "$vendorName $deviceName"
+ json_add_array 'partitions'
+ json_add_object
+ if [ "$bootEnv1Partition1Value" = "$current_partition" ]; then
+ json_add_string 'state' "Current"
+ else
+ json_add_string 'state' "Alternative"
+ fi
+ json_add_string 'os' "$p1_os"
+ json_add_int 'number' "$bootEnv1Partition1Value"
+ json_close_object
+ json_add_object
+ if [ "$bootEnv1Partition2Value" = "$current_partition" ]; then
+ json_add_string 'state' "Current"
+ else
+ json_add_string 'state' "Alternative"
+ fi
+ json_add_string 'os' "$p2_os"
+ json_add_int 'number' "$bootEnv1Partition2Value"
+ json_close_object
+ json_close_array
+ json_add_string 'rom_board_name' "$romBoardName"
+ json_dump; json_cleanup;
+}
+
+toggle_boot_partition(){
+ local zyxelFlagPartition zyxelBootFlag zyxelNewBootFlag curEnvSetting newEnvSetting
+ local romBoardName p
+ local bev1 bev2 bev1p1 bev1p2 bev2p1 bev2p2
+ local vendorName deviceName partition1MTD partition2MTD labelOffset
+ local bootEnv1 bootEnv1Partition1Value bootEnv1Partition2Value
+ local bootEnv2 bootEnv2Partition1Value bootEnv2Partition2Value
+
+ romBoardName="$(cat /tmp/sysinfo/board_name)"
+ if [ -z "$romBoardName" ]; then
+ print_json 'error' 'NO_BOARD_NAME'
+ return
+ fi
+
+ p="$(find_device_data "$romBoardName")"
+ if [ -z "$p" ] || [ ! -s "$p" ]; then
+ print_json 'rom_board_name' "$romBoardName"
+ return
+ fi
+
+ json_load_file "$p"
+ for i in vendorName deviceName partition1MTD partition2MTD labelOffset \
+ bootEnv1 bootEnv1Partition1Value bootEnv1Partition2Value \
+ bootEnv2 bootEnv2Partition1Value bootEnv2Partition2Value; do
+ json_get_var $i "$i"
+ done
+ json_cleanup
+
+ bev1="$bootEnv1"
+ bev2="$bootEnv2"
+
+ if [ -n "${bev1}${bev2}" ]; then # Linksys devices
+ if [ -n "$bev1" ]; then
+ curEnvSetting="$(fw_printenv -n "${bev1}")"
+ if [ -z "$curEnvSetting" ]; then
+ logger "$(printf "Unable to obtain firmware environment variable: %s." "$bev1")"
+ json_init
+ json_add_string 'error' 'NO_FIRM_ENV'
+ json_add_array 'args'
+ json_add_string "$bev1"
+ json_close_array
+ json_add_string 'rom_board_name' "$romBoardName"
+ json_dump; json_cleanup;
+ return
+ else
+ bev1p1="$bootEnv1Partition1Value"
+ bev1p2="$bootEnv1Partition2Value"
+ if [ "$curEnvSetting" = "$bev1p1" ]; then
+ newEnvSetting="$bev1p2"
+ else
+ newEnvSetting="$bev1p1"
+ fi
+ if ! fw_setenv "$bev1" "$newEnvSetting"; then
+ logger "$(printf "Unable to set firmware environment variable: %s to %s." "$bev1" "$newEnvSetting")"
+ json_init
+ json_add_string 'error' 'ERR_SET_ENV'
+ json_add_array 'args'
+ json_add_string "$bev1"
+ json_add_string "$newEnvSetting"
+ json_close_array
+ json_add_string 'rom_board_name' "$romBoardName"
+ json_dump; json_cleanup;
+ return
+ fi
+ fi
+ fi
+ if [ -n "$bev2" ]; then
+ curEnvSetting="$(fw_printenv -n "${bev2}")"
+ if [ -z "$curEnvSetting" ]; then
+ logger "$(printf "Unable to obtain firmware environment variable: %s." "$bev2")"
+ json_init
+ json_add_string 'error' 'NO_FIRM_ENV'
+ json_add_array 'args'
+ json_add_string "$bev2"
+ json_close_array
+ json_add_string 'rom_board_name' "$romBoardName"
+ json_dump; json_cleanup;
+ return
+ else
+ bev2p1="$bootEnv2Partition1Value"
+ bev2p2="$bootEnv2Partition2Value"
+ if [ "$curEnvSetting" = "$bev2p1" ]; then
+ newEnvSetting="$bev2p2"
+ else
+ newEnvSetting="$bev2p1"
+ fi
+ if ! fw_setenv "$bev2" "$newEnvSetting"; then
+ logger "$(printf "Unable to set firmware environment variable: %s to %s." "$bev2" "$newEnvSetting")"
+ json_init
+ json_add_string 'error' 'ERR_SET_ENV'
+ json_add_array 'args'
+ json_add_string "$bev2"
+ json_add_string "$newEnvSetting"
+ json_close_array
+ json_add_string 'rom_board_name' "$romBoardName"
+ json_dump; json_cleanup;
+ return
+ fi
+ fi
+ fi
+ json_init
+ json_dump; json_cleanup;
+ else # NetGear device
+ if [ -z "$zyxelFlagPartition" ]; then
+ zyxelFlagPartition="$(find_mtd_part 0:DUAL_FLAG 2>/dev/null)"
+ fi
+ if [ -z "$zyxelFlagPartition" ]; then
+ logger "Unable to find Dual Boot Flag Partition."
+ print_json 'error' 'NO_DUAL_FLAG'
+ return
+ else
+ zyxelBootFlag="$(dd if="${zyxelFlagPartition}" bs=1 count=1 2>/dev/null | hexdump -n 1 -e '1/1 "%d"')"
+ if [ "$zyxelBootFlag" = "1" ]; then
+ zyxelNewBootFlag="\\xff"
+ else
+ zyxelNewBootFlag="\\x01"
+ fi
+ if [ -n "$zyxelNewBootFlag" ]; then
+ if ! printf "%b" "$zyxelNewBootFlag" > "$zyxelFlagPartition"; then
+ logger "$(printf "Unable to set Dual Boot Flag Partition entry for partition: %s." "$zyxelFlagPartition")"
+ json_init
+ json_add_string 'error' 'ERR_SET_DUAL_FLAG'
+ json_add_array 'args'
+ json_add_string "$zyxelFlagPartition"
+ json_close_array
+ json_add_string 'rom_board_name' "$romBoardName"
+ json_dump; json_cleanup;
+ return
+ fi
+ fi
+ fi
+ json_init
+ json_dump; json_cleanup;
+ fi
+}
+
+case "$1" in
+ list)
+ json_init
+ json_add_object "obtain_device_info"
+ json_close_object
+ json_add_object "toggle_boot_partition"
+ json_close_object
+ json_dump
+ json_cleanup
+ ;;
+ call)
+ case "$2" in
+ obtain_device_info)
+ obtain_device_info;;
+ toggle_boot_partition)
+ toggle_boot_partition;;
+ esac
+ ;;
+esac
--- /dev/null
+{
+ "vendorName": "Linksys",
+ "deviceName": "EA9500",
+ "boardName": "linksys-panamera",
+ "partition1MTD": "mtd3",
+ "partition2MTD": "mtd6",
+ "labelOffset": 28,
+ "bootEnv1": "boot_part",
+ "bootEnv1Partition1Value": 1,
+ "bootEnv1Partition2Value": 2,
+ "bootEnv2": null,
+ "bootEnv2Partition1Value": null,
+ "bootEnv2Partition2Value": null
+}
--- /dev/null
+{
+ "vendorName": "Netgear",
+ "deviceName": "WAC510",
+ "boardNames": [ "netgear,wac510" ],
+ "partition1MTD": "mtd9",
+ "partition2MTD": "mtd10",
+ "labelOffset": null,
+ "bootEnv1": "primary",
+ "bootEnv1Partition1Value": 0,
+ "bootEnv1Partition2Value": 3800000,
+ "bootEnv2": "secondary",
+ "bootEnv2Partition1Value": 3800000,
+ "bootEnv2Partition2Value": 0
+}
--- /dev/null
+{
+ "vendorName": "Linksys",
+ "deviceName": "E4200v2/EA4500",
+ "boardNames": [ "linksys-viper", "linksys,viper" ],
+ "partition1MTD": "mtd3",
+ "partition2MTD": "mtd5",
+ "labelOffset": 32,
+ "bootEnv1": "boot_part",
+ "bootEnv1Partition1Value": 1,
+ "bootEnv1Partition2Value": 2,
+ "bootEnv2": "bootcmd",
+ "bootEnv2Partition1Value": "run nandboot",
+ "bootEnv2Partition2Value": "run altnandboot"
+}
--- /dev/null
+{
+ "vendorName": "Linksys",
+ "deviceName": "E4200v2",
+ "boardNames": [ "linksys-e4200v2", "linksys,e4200v2" ],
+ "partition1MTD": "mtd3",
+ "partition2MTD": "mtd5",
+ "labelOffset": 32,
+ "bootEnv1": "boot_part",
+ "bootEnv1Partition1Value": 1,
+ "bootEnv1Partition2Value": 2,
+ "bootEnv2": "bootcmd",
+ "bootEnv2Partition1Value": "run nandboot",
+ "bootEnv2Partition2Value": "run altnandboot"
+}
--- /dev/null
+{
+ "vendorName": "Linksys",
+ "deviceName": "EA3500",
+ "boardNames": [ "linksys-audi", "linksys,audi", "linksys-ea3500", "linksys,ea3500" ],
+ "partition1MTD": "mtd3",
+ "partition2MTD": "mtd5",
+ "labelOffset": 32,
+ "bootEnv1": "boot_part",
+ "bootEnv1Partition1Value": 1,
+ "bootEnv1Partition2Value": 2,
+ "bootEnv2": "bootcmd",
+ "bootEnv2Partition1Value": "run nandboot",
+ "bootEnv2Partition2Value": "run altnandboot"
+}
+
--- /dev/null
+{
+ "vendorName": "Linksys",
+ "deviceName": "EA4500",
+ "boardNames": [ "linksys-e4500", "linksys,e4500" ],
+ "partition1MTD": "mtd3",
+ "partition2MTD": "mtd5",
+ "labelOffset": 32,
+ "bootEnv1": "boot_part",
+ "bootEnv1Partition1Value": 1,
+ "bootEnv1Partition2Value": 2,
+ "bootEnv2": "bootcmd",
+ "bootEnv2Partition1Value": "run nandboot",
+ "bootEnv2Partition2Value": "run altnandboot"
+}
--- /dev/null
+{
+ "vendorName": "Linksys",
+ "deviceName": "EA6350v3",
+ "boardNames": [ "linksys-ea6350v3", "linksys,ea6350v3" ],
+ "partition1MTD": "mtd10",
+ "partition2MTD": "mtd12",
+ "labelOffset": 192,
+ "bootEnv1": "boot_part",
+ "bootEnv1Partition1Value": 1,
+ "bootEnv1Partition2Value": 2,
+ "bootEnv2": null,
+ "bootEnv2Partition1Value": null,
+ "bootEnv2Partition2Value": null
+}
--- /dev/null
+{
+ "vendorName": "Linksys",
+ "deviceName": "EA7300v1",
+ "boardNames": [ "linksys,ea7300-v1" ],
+ "partition1MTD": "mtd5",
+ "partition2MTD": "mtd7",
+ "labelOffset": 32,
+ "bootEnv1": "boot_part",
+ "bootEnv1Partition1Value": 1,
+ "bootEnv1Partition2Value": 2,
+ "bootEnv2": "bootcmd",
+ "bootEnv2Partition1Value": "run nandboot",
+ "bootEnv2Partition2Value": "run altnandboot"
+}
+
--- /dev/null
+{
+ "vendorName": "Linksys",
+ "deviceName": "EA7300v2",
+ "boardNames": [ "linksys,ea7300-v2" ],
+ "partition1MTD": "mtd5",
+ "partition2MTD": "mtd7",
+ "labelOffset": 32,
+ "bootEnv1": "boot_part",
+ "bootEnv1Partition1Value": 1,
+ "bootEnv1Partition2Value": 2,
+ "bootEnv2": "bootcmd",
+ "bootEnv2Partition1Value": "run nandboot",
+ "bootEnv2Partition2Value": "run altnandboot"
+}
+
--- /dev/null
+{
+ "vendorName": "Linksys",
+ "deviceName": "EA8300",
+ "boardNames": [ "linksys-ea8300", "linksys,ea8300" ],
+ "partition1MTD": "mtd10",
+ "partition2MTD": "mtd12",
+ "labelOffset": 192,
+ "bootEnv1": "boot_part",
+ "bootEnv1Partition1Value": 1,
+ "bootEnv1Partition2Value": 2,
+ "bootEnv2": null,
+ "bootEnv2Partition1Value": null,
+ "bootEnv2Partition2Value": null
+}
--- /dev/null
+{
+ "vendorName": "Linksys",
+ "deviceName": "EA8500",
+ "boardNames": [ "linksys-ea8500", "linksys,ea8500" ],
+ "partition1MTD": "mtd13",
+ "partition2MTD": "mtd15",
+ "labelOffset": 32,
+ "bootEnv1": "boot_part",
+ "bootEnv1Partition1Value": 1,
+ "bootEnv1Partition2Value": 2,
+ "bootEnv2": null,
+ "bootEnv2Partition1Value": null,
+ "bootEnv2Partition2Value": null
+}
--- /dev/null
+{
+ "vendorName": "Linksys",
+ "deviceName": "MR8300",
+ "boardNames": [ "linksys-mr8300", "linksys,mr8300" ],
+ "partition1MTD": "mtd10",
+ "partition2MTD": "mtd12",
+ "labelOffset": 192,
+ "bootEnv1": "boot_part",
+ "bootEnv1Partition1Value": 1,
+ "bootEnv1Partition2Value": 2,
+ "bootEnv2": null,
+ "bootEnv2Partition1Value": null,
+ "bootEnv2Partition2Value": null
+}
--- /dev/null
+{
+ "vendorName": "Linksys",
+ "deviceName": "WRT1200AC",
+ "boardNames": [ "linksys-caiman", "linksys,caiman", "linksys,wrt1200ac" ],
+ "partition1MTD": "mtd4",
+ "partition2MTD": "mtd6",
+ "labelOffset": 32,
+ "bootEnv1": "boot_part",
+ "bootEnv1Partition1Value": 1,
+ "bootEnv1Partition2Value": 2,
+ "bootEnv2": "bootcmd",
+ "bootEnv2Partition1Value": "run nandboot",
+ "bootEnv2Partition2Value": "run altnandboot"
+}
--- /dev/null
+{
+ "vendorName": "Linksys",
+ "deviceName": "WRT1900ACv1",
+ "boardNames": [ "linksys-mamba", "linksys,mamba", "linksys,wrt1900ac-v1" ],
+ "partition1MTD": "mtd4",
+ "partition2MTD": "mtd6",
+ "labelOffset": 32,
+ "bootEnv1": "boot_part",
+ "bootEnv1Partition1Value": 1,
+ "bootEnv1Partition2Value": 2,
+ "bootEnv2": "bootcmd",
+ "bootEnv2Partition1Value": "run nandboot",
+ "bootEnv2Partition2Value": "run altnandboot"
+}
--- /dev/null
+{
+ "vendorName": "Linksys",
+ "deviceName": "WRT1900ACS",
+ "boardNames": [ "linksys-shelby", "linksys,shelby", "linksys,wrt1900acs" ],
+ "partition1MTD": "mtd4",
+ "partition2MTD": "mtd6",
+ "labelOffset": 32,
+ "bootEnv1": "boot_part",
+ "bootEnv1Partition1Value": 1,
+ "bootEnv1Partition2Value": 2,
+ "bootEnv2": "bootcmd",
+ "bootEnv2Partition1Value": "run nandboot",
+ "bootEnv2Partition2Value": "run altnandboot"
+}
--- /dev/null
+{
+ "vendorName": "Linksys",
+ "deviceName": "WRT1900ACv2",
+ "boardNames": [ "linksys-cobra", "linksys,cobra", "linksys,wrt1900ac-v2" ],
+ "partition1MTD": "mtd4",
+ "partition2MTD": "mtd6",
+ "labelOffset": 32,
+ "bootEnv1": "boot_part",
+ "bootEnv1Partition1Value": 1,
+ "bootEnv1Partition2Value": 2,
+ "bootEnv2": "bootcmd",
+ "bootEnv2Partition1Value": "run nandboot",
+ "bootEnv2Partition2Value": "run altnandboot"
+}
--- /dev/null
+{
+ "vendorName": "Linksys",
+ "deviceName": "WRT3200ACM",
+ "boardNames": [ "linksys-rango", "linksys,rango", "linksys,wrt3200acm" ],
+ "partition1MTD": "mtd5",
+ "partition2MTD": "mtd7",
+ "labelOffset": 32,
+ "bootEnv1": "boot_part",
+ "bootEnv1Partition1Value": 1,
+ "bootEnv1Partition2Value": 2,
+ "bootEnv2": "bootcmd",
+ "bootEnv2Partition1Value": "run nandboot",
+ "bootEnv2Partition2Value": "run altnandboot"
+}
--- /dev/null
+{
+ "vendorName": "Linksys",
+ "deviceName": "WRT32X",
+ "boardNames": [ "linksys-venom", "linksys,venom", "linksys,wrt32x" ],
+ "partition1MTD": "mtd5",
+ "partition2MTD": "mtd7",
+ "labelOffset": null,
+ "bootEnv1": "boot_part",
+ "bootEnv1Partition1Value": 1,
+ "bootEnv1Partition2Value": 2,
+ "bootEnv2": "bootcmd",
+ "bootEnv2Partition1Value": "run nandboot",
+ "bootEnv2Partition2Value": "run altnandboot"
+}
--- /dev/null
+{
+ "vendorName": "ZyXEL",
+ "deviceName": "NBG6817",
+ "boardNames": [ "nbg6817", "zyxel,nbg6817" ],
+ "partition1MTD": "mmcblk0p4",
+ "partition2MTD": "mmcblk0p7",
+ "labelOffset": 32,
+ "bootEnv1": null,
+ "bootEnv1Partition1Value": 255,
+ "bootEnv1Partition2Value": 1,
+ "bootEnv2": null,
+ "bootEnv2Partition1Value": null,
+ "bootEnv2Partition2Value": null
+}
--- /dev/null
+{
+ "admin/system/advanced_reboot": {
+ "title": "Advanced Reboot",
+ "order": 90,
+ "action": {
+ "type": "view",
+ "path": "system/advanced_reboot"
+ },
+ "depends": {
+ "acl": [ "luci-app-advanced-reboot" ]
+ }
+ }
+}
"luci-app-advanced-reboot": {
"description": "Grant UCI and file access for luci-app-advanced-reboot",
"read": {
- "cgi-io": [
- "exec"
- ],
- "file": {
- "/usr/lib/lua/luci/advanced-reboot/devices/*": [
- "read"
- ],
- "/sys/devices/virtual/ubi/ubi*/mtd_num": [
- "read"
- ],
- "/etc/os-release": [
- "read"
- ],
- "/alt/rom/etc/os-release": [
- "read"
- ],
- "/usr/sbin/fw_printenv *": [
- "exec"
- ],
- "/usr/sbin/fw_setenv *": [
- "exec"
- ],
- "/usr/sbin/ubiattach *": [
- "exec"
- ],
- "/usr/sbin/ubiblock *": [
- "exec"
- ],
- "/usr/sbin/ubidetach *": [
- "exec"
- ],
- "/usr/sbin/ubinfo *": [
- "exec"
- ],
- "/bin/cat *": [
- "exec"
- ],
- "/usr/bin/cat *": [
- "exec"
- ],
- "/bin/dd *": [
- "exec"
- ],
- "/usr/bin/dd *": [
- "exec"
- ],
- "/bin/hexdump *": [
- "exec"
- ],
- "/usr/bin/hexdump *": [
- "exec"
- ],
- "/bin/logger -t advanced-reboot *": [
- "exec"
- ],
- "/usr/bin/logger -t advanced-reboot *": [
- "exec"
- ],
- "/bin/mkdir *": [
- "exec"
- ],
- "/usr/bin/mkdir *": [
- "exec"
- ],
- "/bin/mount *": [
- "exec"
- ],
- "/usr/bin/mount *": [
- "exec"
- ],
- "/bin/printf *": [
- "exec"
- ],
- "/usr/bin/printf *": [
- "exec"
- ],
- "/bin/rm *": [
- "exec"
- ],
- "/usr/bin/rm *": [
- "exec"
- ],
- "/lib/functions.sh": [
- "exec"
- ]
+ "ubus": {
+ "luci.advanced_reboot": [ "obtain_device_info", "toggle_boot_partition" ],
+ "system": [ "reboot" ]
},
- "uci": [
- "network"
- ]
+ "file": {
+ "/usr/sbin/fw_printenv": [ "list" ],
+ "/usr/sbin/fw_setenv": [ "list" ],
+ "/sbin/poweroff": [ "list", "exec" ]
+ }
}
}
}