luci-app-advanced-reboot: rewrite rpcd in shell script + bugfixes 4715/head
authorStan Grishin <stangri@melmac.net>
Wed, 6 Jan 2021 16:56:10 +0000 (16:56 +0000)
committerStan Grishin <stangri@melmac.net>
Thu, 7 Jan 2021 19:18:58 +0000 (19:18 +0000)
Signed-off-by: Stan Grishin <stangri@melmac.net>
applications/luci-app-advanced-reboot/Makefile
applications/luci-app-advanced-reboot/README.md
applications/luci-app-advanced-reboot/htdocs/luci-static/resources/view/system/advanced_reboot.js
applications/luci-app-advanced-reboot/root/usr/libexec/rpcd/luci.advanced_reboot
applications/luci-app-advanced-reboot/root/usr/share/advanced-reboot/devices/zyxel-nbg6817.json
applications/luci-app-advanced-reboot/root/usr/share/rpcd/acl.d/luci-app-advanced-reboot.json

index dff9be5ec939784b9b791fbd2786ee684ef82f8c..46ebedae9d04b3dff33dce64eea86d865721ffef 100644 (file)
@@ -9,10 +9,9 @@ PKG_MAINTAINER:=Stan Grishin <stangri@melmac.net>
 LUCI_TITLE:=Advanced Linksys Reboot Web UI
 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-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:=55
 
 include ../../luci.mk
 
index 48ff558c1a3cc189adf9f3c65e02324ead4593c3..a0fd20c9ef23b29c8f8a86ff89fcfc3345869935 100644 (file)
@@ -1,83 +1,3 @@
 # Advanced Reboot Web UI (luci-app-advanced-reboot)
 
-[![HitCount](http://hits.dwyl.com/stangri/openwrt/luci-app-advanced-reboot.svg)](http://hits.dwyl.com/stangri/openwrt/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 EA7300v2
-- Linksys EA8300
-- Linksys MR8300
-- 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/>).
index e2c12e6a468f3891c539a0983d65ee4af0d9110a..794ac8565e5e8d701d274702847f3c6ab1a2b395 100644 (file)
@@ -157,7 +157,7 @@ return view.extend({
                        }
 
                        res.push([
-                               (partition.number).toString(16).toUpperCase(),
+                               (partition.number+0x100).toString(16).substr(-2).toUpperCase(),
                                _(partition.state),
                                partition.os.replace("Unknown", _("Unknown")).replace("Compressed", _("Compressed")),
                                E('button', {
index a6c7c0e5403dc7707f8fb570b37759a5d8ad6bc4..c78a61d611007a97db1ad3b4e1f498dde8dc8b67 100755 (executable)
-#!/usr/bin/env lua
+#!/bin/sh
+# Copyright 2017-2020 Stan Grishin (stangri@melmac.net)
+# shellcheck disable=SC2039,SC1091
 
-local json = require "luci.jsonc"
-local nixio = require "nixio"
-local fs   = require "nixio.fs"
-local sys  = require "luci.sys"
-local util = require "luci.util"
+readonly devices_dir="/usr/share/advanced-reboot/devices/"
 
-local devices_dir = "/usr/share/advanced-reboot/devices/"
+. /lib/functions.sh
+. /usr/share/libubox/jshn.sh
 
-local function logger(t)
-       util.exec("logger -t advanced-reboot '" .. tostring(t) .. "'")
-end
+logger() { /usr/bin/logger -t advanced-reboot "$1"; }
 
-local function is_alt_mountable(p1_mtd, p2_mtd)
-       if p1_mtd:sub(1,3) == "mtd" and
-                                p2_mtd:sub(1,3) == "mtd" and
-                                fs.access("/usr/sbin/ubiattach") and
-                                fs.access("/usr/sbin/ubiblock") and
-                                fs.access("/bin/mount") then
-               return true
+is_alt_mountable() {
+       local p1_mtd="$1" p2_mtd="$2"
+       if [ "${p1_mtd:0:3}" = "mtd" ] && [ "${p2_mtd:0:3}" = "mtd" ] && \
+               [ -x "/usr/sbin/ubiattach" ] && \
+               [ -x "/usr/sbin/ubiblock" ] && \
+               [ -x "/bin/mount" ]; then
+               return 0
        else
-               return false
-       end
-end
-
-local function alt_partition_mount(op_ubi)
-       local ubi_dev
-       util.exec('for i in alt_rom alt_overlay firmware; do [ ! -d "$i" ] && mkdir -p "/alt/${i}"; done')
-       ubi_dev = tostring(util.exec("ubiattach -m " .. tostring(op_ubi)))
-       _, _, ubi_dev = ubi_dev:find("UBI device number (%d+)")
-       if not ubi_dev then
-               util.exec("ubidetach -m " .. tostring(op_ubi))
-               return
-       end
-       util.exec("ubiblock --create /dev/ubi" .. ubi_dev .. "_0")
-       util.exec("mount -t squashfs -o ro /dev/ubiblock" .. ubi_dev .. "_0 /alt/alt_rom")
-       util.exec("mount -t ubifs /dev/ubi" .. ubi_dev .. "_1 /alt/alt_overlay")
---     util.exec("mount -t overlay overlay -o noatime,lowerdir=/alt/rom,upperdir=/alt/overlay/upper,workdir=/alt/overlay/work /alt/firmware")
-end
-
-local function alt_partition_unmount(op_ubi)
-       local i
-       local mtdCount = tonumber(util.exec("ubinfo | grep 'Present UBI devices' | grep -c ','"))
-       mtdCount = mtdCount and mtdCount + 1 or 10
---     util.exec("[ -d /alt/firmware ] && umount /alt/firmware")
-       util.exec("[ -d /alt/alt_overlay ] && umount /alt/alt_overlay")
-       util.exec("[ -d /alt/alt_rom ] && umount /alt/alt_rom")
-       for i = 0, mtdCount do
-               if not fs.access("/sys/devices/virtual/ubi/ubi" .. tostring(i) .. "/mtd_num") then break end
-               ubi_mtd =  tonumber(util.trim(util.exec("cat /sys/devices/virtual/ubi/ubi" .. i .. "/mtd_num")))
-               if ubi_mtd and ubi_mtd == op_ubi then
-                       util.exec("ubiblock --remove /dev/ubi" .. tostring(i) .. "_0")
-                       util.exec("ubidetach -m " .. tostring(op_ubi))
-                       util.exec('rm -rf /alt')
-               end
-       end
-end
-
-local function get_partition_os_info(op_ubi)
-       local cp_info, op_info
-       if fs.access("/etc/os-release") then
-               cp_info = util.trim(util.exec('. /etc/os-release && echo "$PRETTY_NAME"'))
-               if cp_info:find("SNAPSHOT") then
-                       cp_info = util.trim(util.exec('. /etc/os-release && echo "$OPENWRT_RELEASE"'))
-               end
-       end
-       logger(string.format("attempting to mount alternative partition (mtd%s)", tostring(op_ubi)))
-       alt_partition_unmount(op_ubi)
-       alt_partition_mount(op_ubi)
-       if fs.access("/alt/alt_rom/etc/os-release") then
-               op_info = util.trim(util.exec('. /alt/alt_rom/etc/os-release && echo "$PRETTY_NAME"'))
-               if op_info:find("SNAPSHOT") then
-                       op_info = util.trim(util.exec('. /alt/alt_rom/etc/os-release && echo "$OPENWRT_RELEASE"'))
-               end
-       end
-       logger(string.format("attempting to unmount alternative partition (mtd%s)", tostring(op_ubi)))
-       alt_partition_unmount(op_ubi)
-       return cp_info, op_info
-end
-
-local function find_device_data(romBoardName)
-       local filename
-
-       for filename in fs.dir(devices_dir) do
-               local filedata = fs.readfile(devices_dir .. filename)
-
-               local p = json.parse(filedata or {})
-
-               if p then
-                       local boardName
-
-                       if p.boardName then
-                               boardName = p.boardName:gsub('%p','')
-                               if romBoardName:match(boardName) then return p end
-                       end
-                       if p.boardNames then
-                               for i, v in pairs(p.boardNames) do
-                                       boardName = v:gsub('%p','')
-                                       if romBoardName:match(boardName) then return p end
-                               end
-                       end
-               end
-       end
-
-       return nil
-end
-
-local methods = {
-       obtain_device_info = {
-               call = function()
-
-                       local ret = {}
-                       local romBoardName = fs.readfile('/tmp/sysinfo/board_name')
-
-                       if not romBoardName then
-                               ret.error = 'NO_BOARD_NAME'
-                               return ret
-                       end
-
-                       romBoardName = romBoardName:gsub('\n','')
+               return 1
+       fi
+}
 
-                       ret.rom_board_name = romBoardName
+alt_partition_mount() {
+       local ubi_dev op_ubi="$1"
+       for i in alt_rom alt_overlay firmware; do [ ! -d "$i" ] && mkdir -p "/alt/${i}"; done
+       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 -o ro "/dev/ubiblock${ubi_dev}_0" /alt/alt_rom
+       mount -t ubifs "/dev/ubi${ubi_dev}_0" /alt/alt_overlay
+       # mount -t overlay overlay -o noatime,lowerdir=/alt/rom,upperdir=/alt/overlay/upper,workdir=/alt/overlay/work /alt/firmware
+}
 
-                       romBoardName = romBoardName:gsub('%p','')
+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 /alt/firmware ] && umount /alt/firmware
+       [ -d /alt/alt_overlay ] && umount /alt/alt_overlay
+       [ -d /alt/alt_rom ] && umount /alt/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 /alt
+               fi
+               i=$((i + 1))
+       done
+}
 
-                       local p, boardName, n, p1_label, p1_version, p2_label, p2_version, p1_os, p2_os
-                       local current_partition
-                       local op_ubi, cp_info, op_info, zyxelFlagPartition
+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"
+}
 
-                       p = find_device_data(romBoardName)
+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 "/alt/alt_rom/etc/os-release" ]; then
+               op_info="$(. /alt/alt_rom/etc/os-release && echo "$PRETTY_NAME")"
+               if [ "${op_info//SNAPSHOT}" != "$op_info" ]; then
+                       op_info="$(. /alt/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"
+}
 
-                       if p then
-                               if p.labelOffset then
-                                       if p.partition1MTD then
-                                               p1_label = util.trim(util.exec("dd if=/dev/" .. p.partition1MTD .. " bs=1 skip=" .. p.labelOffset .. " count=128" .. " 2>/dev/null"))
-                                               n, p1_version = p1_label:match('(Linux)-([%d|.]+)')
-                                       end
+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
+}
 
-                                       if p1_label then
-                                               if p1_label:find("LEDE") then p1_os = "LEDE" end
-                                               if p1_label:find("OpenWrt") then p1_os = "OpenWrt" end
-                                               if p.vendorName and p1_label:find(p.vendorName) then p1_os = p.vendorName end
-                                       end
+print_json() { json_init; json_add_string "$1" "$2"; json_dump; json_cleanup; }
 
-                                       if not p1_os then
-                                               p1_os = (p.vendorName and p.vendorName or 'Unknown') .. "/" .. "Unknown"
-                                       end
-                                       if p1_os and p1_version then p1_os = p1_os .. " (Linux " .. p1_version .. ")" end
+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
 
-                                       if p.partition2MTD then
-                                               p2_label = util.trim(util.exec("dd if=/dev/" .. p.partition2MTD .. " bs=1 skip=" .. p.labelOffset .. " count=128" .. " 2>/dev/null"))
-                                               n, p2_version = p2_label:match('(Linux)-([%d|.]+)')
-                                       end
+       romBoardName="$(cat /tmp/sysinfo/board_name)"
+       if [ -z "$romBoardName" ]; then
+               print_json 'error' 'NO_BOARD_NAME'
+               return
+       fi
 
-                                       if p2_label then
-                                               if p2_label:find("LEDE") then p2_os = "LEDE" end
-                                               if p2_label:find("OpenWrt") then p2_os = "OpenWrt" end
-                                               if p.vendorName and p2_label:find(p.vendorName) then p2_os = p.vendorName end
-                                       end
+       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;
+}
 
-                                       if not p2_os then
-                                               p2_os = (p.vendorName and p.vendorName or 'Unknown') .. "/" .. "Unknown"
-                                       end
-                                       if p2_os and p2_version then p2_os = p2_os .. " (Linux " .. p2_version .. ")" end
-                               else
-                                       p1_os = p.vendorName .. "/" .. "Unknown" .. " (" .. "Compressed" .. ")"
-                                       p2_os = p.vendorName .. "/" .. "Unknown" .. " (" .. "Compressed" .. ")"
-                               end
+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
 
-                               if p.bootEnv1 then
-                                       if fs.access("/usr/sbin/fw_printenv") and fs.access("/usr/sbin/fw_setenv") then
-                                               current_partition = tonumber(util.trim(util.exec("fw_printenv -n " .. p.bootEnv1)))
-                                       end
+       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
-                                       if not zyxelFlagPartition then zyxelFlagPartition = util.trim(util.exec(". /lib/functions.sh; find_mtd_part 0:DUAL_FLAG")) end
-                                       if zyxelFlagPartition then
-                                               current_partition = tonumber(util.exec("dd if=" .. zyxelFlagPartition .. " bs=1 count=1 2>/dev/null | hexdump -n 1 -e '1/1 \"%d\"'"))
-                                       else
-                                               ret.error = 'NO_DUAL_FLAG'
-                                               logger("Unable to find Dual Boot Flag Partition.")
-                                               return ret
-                                       end
-                               end
-
-                               ret.current_partition = current_partition
-
-                               if is_alt_mountable(p.partition1MTD, p.partition2MTD) then
-                                       if current_partition == p.bootEnv1Partition1Value then
-                                               op_ubi = tonumber(p.partition2MTD:sub(4)) + 1
-                                       else
-                                               op_ubi = tonumber(p.partition1MTD:sub(4)) + 1
-                                       end
-                                       local cp_info, op_info = get_partition_os_info(op_ubi)
-                                       if current_partition == p.bootEnv1Partition1Value then
-                                               p1_os = cp_info or p1_os
-                                               p2_os = op_info or p2_os
-                                       else
-                                               p1_os = op_info or p1_os
-                                               p2_os = cp_info or p2_os
-                                       end
-                               end
-
-                               ret.device_name = (p.vendorName and p.vendorName or "") .. " " .. p.deviceName
-
-                               ret.partitions = {
-                                       {
-                                               os = p1_os,
-                                               state = p.bootEnv1Partition1Value == current_partition and 'Current' or 'Alternative',
-                                               number = p.bootEnv1Partition1Value
-                                       },
-                                       {
-                                               os = p2_os,
-                                               state = p.bootEnv1Partition2Value == current_partition and 'Current' or 'Alternative',
-                                               number = p.bootEnv1Partition2Value
-                                       }
-                               }
-                       end
-
-                       return ret
-               end
-       },
-       toggle_boot_partition = {
-               call = function()
-                       local ret = {}
-                       local zyxelFlagPartition, zyxelBootFlag, zyxelNewBootFlag, errorCode, curEnvSetting, newEnvSetting
-
-                       local romBoardName = fs.readfile('/tmp/sysinfo/board_name')
-
-                       if not romBoardName then
-                               ret.error = 'NO_BOARD_NAME'
-                               return ret
-                       end
-
-                       romBoardName = romBoardName:gsub('\n',''):gsub('%p','')
-                       p = find_device_data(romBoardName)
-                       local bev1, bev2 = p.bootEnv1, p.bootEnv2
-
-                       if bev1 or bev2 then -- Linksys devices
-                               if bev1 then
-                                       curEnvSetting = tonumber(util.trim(util.exec("fw_printenv -n " .. bev1)))
-                                       if not curEnvSetting then
-                                               logger(string.format("Unable to obtain firmware environment variable: %s.", bev1))
-                                               ret.error = 'NO_FIRM_ENV'
-                                               ret.args = { bev1 }
-                                               return ret
-                                       else
-                                               local bev1p1, bev1p2 = p.bootEnv1Partition1Value, p.bootEnv1Partition2Value
-                                               newEnvSetting = curEnvSetting == bev1p1 and bev1p2 or bev1p1
-                                               errorCode = sys.call("fw_setenv " .. bev1 .. " " .. newEnvSetting)
-                                               if errorCode ~= 0 then
-                                                       logger(string.format("Unable to set firmware environment variable: %s to %s.", bev1, newEnvSetting))
-                                                       ret.error = 'ERR_SET_ENV'
-                                                       ret.args = { bev1, newEnvSetting }
-                                                       return ret
-                                               end
-                                       end
-                               end
-                               if bev2 then
-                                       curEnvSetting = util.trim(util.exec("fw_printenv -n " .. bev2))
-                                       if not curEnvSetting then
-                                               logger(string.format("Unable to obtain firmware environment variable: %s.", bev2))
-                                               ret.error = 'NO_FIRM_ENV'
-                                               ret.args = { bev2 }
-                                               return ret
-                                       else
-                                               local bev2p1, bev2p2 = p.bootEnv2Partition1Value, p.bootEnv2Partition1Value
-                                               newEnvSetting = curEnvSetting == bev2p1 and bev2p2 or bev2p1
-                                               errorCode = sys.call("fw_setenv " .. bev2 .. " '" .. newEnvSetting .. "'")
-                                               if errorCode ~= 0 then
-                                                       logger(string.format("Unable to set firmware environment variable: %s to %s.", bev2, newEnvSetting))
-                                                       ret.error = 'ERR_SET_ENV'
-                                                       ret.args = { bev2, newEnvSetting }
-                                                       return ret
-                                               end
-                                       end
-                               end
-                       else -- NetGear device
-                               if not zyxelFlagPartition then zyxelFlagPartition = util.trim(util.exec(". /lib/functions.sh; find_mtd_part 0:DUAL_FLAG")) end
-                               if not zyxelFlagPartition then
-                                       logger("Unable to find Dual Boot Flag Partition.")
-                                       ret.error = 'NO_DUAL_FLAG'
+                                       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
-                                       zyxelBootFlag = tonumber(util.exec("dd if=" .. zyxelFlagPartition .. " bs=1 count=1 2>/dev/null | hexdump -n 1 -e '1/1 \"%d\"'"))
-                                       zyxelNewBootFlag = zyxelBootFlag and zyxelBootFlag == 1 and "\\xff" or "\\x01"
-                                       if zyxelNewBootFlag then
-                                               errorCode = sys.call("printf \"" .. zyxelNewBootFlag .. "\" >" .. zyxelFlagPartition )
-                                               if errorCode ~= 0 then
-                                                       logger(string.format("Unable to set Dual Boot Flag Partition entry for partition: %s.", zyxelFlagPartition))
-                                                       ret.error = 'ERR_SET_DUAL_FLAG'
-                                                       ret.args = { zyxelFlagPartition }
-                                                       return ret
-                                               end
-                                       end
-                               end
-                       end
-
-                       return ret
-               end
-       }
+                                       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
 }
 
-local function parseInput()
-       local parse = json.new()
-       local done, err
-
-       while true do
-               local chunk = io.read(4096)
-               if not chunk then
-                       break
-               elseif not done and not err then
-                       done, err = parse:parse(chunk)
-               end
-       end
-
-       if not done then
-               print(json.stringify({ error = err or "Incomplete input" }))
-               os.exit(1)
-       end
-
-       return parse:get()
-end
-
-local function validateArgs(func, uargs)
-       local method = methods[func]
-       if not method then
-               print(json.stringify({ error = "Method not found" }))
-               os.exit(1)
-       end
-
-       if type(uargs) ~= "table" then
-               print(json.stringify({ error = "Invalid arguments" }))
-               os.exit(1)
-       end
-
-       uargs.ubus_rpc_session = nil
-
-       local k, v
-       local margs = method.args or {}
-       for k, v in pairs(uargs) do
-               if margs[k] == nil or
-                  (v ~= nil and type(v) ~= type(margs[k]))
-               then
-                       print(json.stringify({ error = "Invalid arguments" }))
-                       os.exit(1)
-               end
-       end
-
-       return method
-end
-
-if arg[1] == "list" then
-       local _, method, rv = nil, nil, {}
-       for _, method in pairs(methods) do rv[_] = method.args or {} end
-       print((json.stringify(rv):gsub(":%[%]", ":{}")))
-elseif arg[1] == "call" then
-       local args = parseInput()
-       local method = validateArgs(arg[2], args)
-       local result, code = method.call(args)
-       print((json.stringify(result):gsub("^%[%]$", "{}")))
-       os.exit(code or 0)
-end
+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
index 719900b0663b8871ab8b3e69b5162ea8683bb05d..85e764879a54e3b14b5785b3143a9da1cd60e1a2 100644 (file)
@@ -1,7 +1,7 @@
 {
        "vendorName": "ZyXEL",
        "deviceName": "NBG6817",
-       "boardNames": [ "nbg6817" ],
+       "boardNames": [ "nbg6817", "zyxel,nbg6817" ],
        "partition1MTD": "mmcblk0p4",
        "partition2MTD": "mmcblk0p7",
        "labelOffset": 32,
index 4b22db1083f08bfbbf9ee5cdc92b85016225fe80..48f43a2756fb6e1e032385eb683f67addf62f3da 100644 (file)
@@ -3,7 +3,8 @@
                "description": "Grant UCI and file access for luci-app-advanced-reboot",
                "read": {
                        "ubus": {
-                               "luci.advanced_reboot": [ "obtain_device_info", "toggle_boot_partition" ]
+                               "luci.advanced_reboot": [ "obtain_device_info", "toggle_boot_partition" ],
+                               "system": [ "reboot" ]
                        },
                        "file": {
                                "/usr/sbin/fw_printenv": [ "list" ],