🌴 Sync 2026-03-05 23:51:42

This commit is contained in:
github-actions[bot] committed 2026-03-05 23:51:42 +08:00
1 parent 97c049ed0a
commit 0acff03804
14253 files changed
+3893239

No files matched your search

+37
View File
@@ -0,0 +1,37 @@
#=====================================================================================================
# This file is licensed under the terms of the GNU General Public
# License version 2. This program is licensed "as is" without any
# warranty of any kind, whether express or implied.
#
# This file is a part of the luci-app-amlogic plugin
# https://github.com/ophub/luci-app-amlogic
#
# Description: Supports install/update/backup/restore/snapshot operations using OpenWrt on many boxes
# Copyright (C) 2021- https://github.com/unifreq/openwrt_packit
# Copyright (C) 2021- https://github.com/ophub/luci-app-amlogic
#
# Command: curl -fsSL git.io/luci-app-amlogic | bash
#=====================================================================================================
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-amlogic
PKG_VERSION:=3.1.286
PKG_RELEASE:=1
PKG_LICENSE:=GPL-2.0 License
PKG_MAINTAINER:=ophub <https://github.com/ophub/luci-app-amlogic>
LUCI_TITLE:=LuCI support for Amlogic, Allwinner and Rockchip related boxs
LUCI_PKGARCH:=all
LUCI_DEPENDS:= \
@(aarch64||arm) +bash +blkid +block-mount +curl +dosfstools +e2fsprogs \
+fdisk +jq +losetup +lsblk +parted +perl +pv +uuidgen
define Package/$(PKG_NAME)/conffiles
/etc/config/amlogic
endef
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="175" height="20" role="img" aria-label="OpenWrt: Compiler author"><title>OpenWrt: Compiler author</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="175" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="76" height="20" fill="#555"/><rect x="76" width="99" height="20" fill="#4c1"/><rect width="175" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSJ3aGl0ZXNtb2tlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+R2l0SHViPC90aXRsZT48cGF0aCBkPSJNMTIgLjI5N2MtNi42MyAwLTEyIDUuMzczLTEyIDEyIDAgNS4zMDMgMy40MzggOS44IDguMjA1IDExLjM4NS42LjExMy44Mi0uMjU4LjgyLS41NzcgMC0uMjg1LS4wMS0xLjA0LS4wMTUtMi4wNC0zLjMzOC43MjQtNC4wNDItMS42MS00LjA0Mi0xLjYxQzQuNDIyIDE4LjA3IDMuNjMzIDE3LjcgMy42MzMgMTcuN2MtMS4wODctLjc0NC4wODQtLjcyOS4wODQtLjcyOSAxLjIwNS4wODQgMS44MzggMS4yMzYgMS44MzggMS4yMzYgMS4wNyAxLjgzNSAyLjgwOSAxLjMwNSAzLjQ5NS45OTguMTA4LS43NzYuNDE3LTEuMzA1Ljc2LTEuNjA1LTIuNjY1LS4zLTUuNDY2LTEuMzMyLTUuNDY2LTUuOTMgMC0xLjMxLjQ2NS0yLjM4IDEuMjM1LTMuMjItLjEzNS0uMzAzLS41NC0xLjUyMy4xMDUtMy4xNzYgMCAwIDEuMDA1LS4zMjIgMy4zIDEuMjMuOTYtLjI2NyAxLjk4LS4zOTkgMy0uNDA1IDEuMDIuMDA2IDIuMDQuMTM4IDMgLjQwNSAyLjI4LTEuNTUyIDMuMjg1LTEuMjMgMy4yODUtMS4yMy42NDUgMS42NTMuMjQgMi44NzMuMTIgMy4xNzYuNzY1Ljg0IDEuMjMgMS45MSAxLjIzIDMuMjIgMCA0LjYxLTIuODA1IDUuNjI1LTUuNDc1IDUuOTIuNDIuMzYuODEgMS4wOTYuODEgMi4yMiAwIDEuNjA2LS4wMTUgMi44OTYtLjAxNSAzLjI4NiAwIC4zMTUuMjEuNjkuODI1LjU3QzIwLjU2NSAyMi4wOTIgMjQgMTcuNTkyIDI0IDEyLjI5N2MwLTYuNjI3LTUuMzczLTEyLTEyLTEyIi8+PC9zdmc+"/><text aria-hidden="true" x="475" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="490">OpenWrt</text><text x="475" y="140" transform="scale(.1)" fill="#fff" textLength="490">OpenWrt</text><text aria-hidden="true" x="1245" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="890">Compiler author</text><text x="1245" y="140" transform="scale(.1)" fill="#fff" textLength="890">Compiler author</text></g></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="187" height="20" role="img" aria-label="OpenWrt: flippy&apos;s homepage"><title>OpenWrt: flippy&apos;s homepage</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="187" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="76" height="20" fill="#555"/><rect x="76" width="111" height="20" fill="blueviolet"/><rect width="187" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSJ3aGl0ZXNtb2tlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+R2l0SHViPC90aXRsZT48cGF0aCBkPSJNMTIgLjI5N2MtNi42MyAwLTEyIDUuMzczLTEyIDEyIDAgNS4zMDMgMy40MzggOS44IDguMjA1IDExLjM4NS42LjExMy44Mi0uMjU4LjgyLS41NzcgMC0uMjg1LS4wMS0xLjA0LS4wMTUtMi4wNC0zLjMzOC43MjQtNC4wNDItMS42MS00LjA0Mi0xLjYxQzQuNDIyIDE4LjA3IDMuNjMzIDE3LjcgMy42MzMgMTcuN2MtMS4wODctLjc0NC4wODQtLjcyOS4wODQtLjcyOSAxLjIwNS4wODQgMS44MzggMS4yMzYgMS44MzggMS4yMzYgMS4wNyAxLjgzNSAyLjgwOSAxLjMwNSAzLjQ5NS45OTguMTA4LS43NzYuNDE3LTEuMzA1Ljc2LTEuNjA1LTIuNjY1LS4zLTUuNDY2LTEuMzMyLTUuNDY2LTUuOTMgMC0xLjMxLjQ2NS0yLjM4IDEuMjM1LTMuMjItLjEzNS0uMzAzLS41NC0xLjUyMy4xMDUtMy4xNzYgMCAwIDEuMDA1LS4zMjIgMy4zIDEuMjMuOTYtLjI2NyAxLjk4LS4zOTkgMy0uNDA1IDEuMDIuMDA2IDIuMDQuMTM4IDMgLjQwNSAyLjI4LTEuNTUyIDMuMjg1LTEuMjMgMy4yODUtMS4yMy42NDUgMS42NTMuMjQgMi44NzMuMTIgMy4xNzYuNzY1Ljg0IDEuMjMgMS45MSAxLjIzIDMuMjIgMCA0LjYxLTIuODA1IDUuNjI1LTUuNDc1IDUuOTIuNDIuMzYuODEgMS4wOTYuODEgMi4yMiAwIDEuNjA2LS4wMTUgMi44OTYtLjAxNSAzLjI4NiAwIC4zMTUuMjEuNjkuODI1LjU3QzIwLjU2NSAyMi4wOTIgMjQgMTcuNTkyIDI0IDEyLjI5N2MwLTYuNjI3LTUuMzczLTEyLTEyLTEyIi8+PC9zdmc+"/><text aria-hidden="true" x="475" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="490">OpenWrt</text><text x="475" y="140" transform="scale(.1)" fill="#fff" textLength="490">OpenWrt</text><text aria-hidden="true" x="1305" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="1010">flippy&apos;s homepage</text><text x="1305" y="140" transform="scale(.1)" fill="#fff" textLength="1010">flippy&apos;s homepage</text></g></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="161" height="20" role="img" aria-label="Plugin: luci-app-amlogic"><title>Plugin: luci-app-amlogic</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="161" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="60" height="20" fill="#555"/><rect x="60" width="101" height="20" fill="#007ec6"/><rect width="161" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSJ3aGl0ZXNtb2tlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+R2l0SHViPC90aXRsZT48cGF0aCBkPSJNMTIgLjI5N2MtNi42MyAwLTEyIDUuMzczLTEyIDEyIDAgNS4zMDMgMy40MzggOS44IDguMjA1IDExLjM4NS42LjExMy44Mi0uMjU4LjgyLS41NzcgMC0uMjg1LS4wMS0xLjA0LS4wMTUtMi4wNC0zLjMzOC43MjQtNC4wNDItMS42MS00LjA0Mi0xLjYxQzQuNDIyIDE4LjA3IDMuNjMzIDE3LjcgMy42MzMgMTcuN2MtMS4wODctLjc0NC4wODQtLjcyOS4wODQtLjcyOSAxLjIwNS4wODQgMS44MzggMS4yMzYgMS44MzggMS4yMzYgMS4wNyAxLjgzNSAyLjgwOSAxLjMwNSAzLjQ5NS45OTguMTA4LS43NzYuNDE3LTEuMzA1Ljc2LTEuNjA1LTIuNjY1LS4zLTUuNDY2LTEuMzMyLTUuNDY2LTUuOTMgMC0xLjMxLjQ2NS0yLjM4IDEuMjM1LTMuMjItLjEzNS0uMzAzLS41NC0xLjUyMy4xMDUtMy4xNzYgMCAwIDEuMDA1LS4zMjIgMy4zIDEuMjMuOTYtLjI2NyAxLjk4LS4zOTkgMy0uNDA1IDEuMDIuMDA2IDIuMDQuMTM4IDMgLjQwNSAyLjI4LTEuNTUyIDMuMjg1LTEuMjMgMy4yODUtMS4yMy42NDUgMS42NTMuMjQgMi44NzMuMTIgMy4xNzYuNzY1Ljg0IDEuMjMgMS45MSAxLjIzIDMuMjIgMCA0LjYxLTIuODA1IDUuNjI1LTUuNDc1IDUuOTIuNDIuMzYuODEgMS4wOTYuODEgMi4yMiAwIDEuNjA2LS4wMTUgMi44OTYtLjAxNSAzLjI4NiAwIC4zMTUuMjEuNjkuODI1LjU3QzIwLjU2NSAyMi4wOTIgMjQgMTcuNTkyIDI0IDEyLjI5N2MwLTYuNjI3LTUuMzczLTEyLTEyLTEyIi8+PC9zdmc+"/><text aria-hidden="true" x="395" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="330">Plugin</text><text x="395" y="140" transform="scale(.1)" fill="#fff" textLength="330">Plugin</text><text aria-hidden="true" x="1095" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="910">luci-app-amlogic</text><text x="1095" y="140" transform="scale(.1)" fill="#fff" textLength="910">luci-app-amlogic</text></g></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

@@ -0,0 +1,557 @@
module("luci.controller.amlogic", package.seeall)
local sys = require "luci.sys"
local PKG_NAME = "luci-app-amlogic"
function index()
if not nixio.fs.access("/etc/config/amlogic") then
return
end
local page = entry({ "admin", "system", "amlogic" }, alias("admin", "system", "amlogic", "info"), _("Amlogic Service"), 88)
page.dependent = true
page.acl_depends = { PKG_NAME }
local platfrom = luci.sys.exec("cat /etc/flippy-openwrt-release 2>/dev/null | grep PLATFORM | awk -F'=' '{print $2}' | grep -oE '(amlogic|rockchip|allwinner|qemu)' | xargs") or "Unknown"
local install_menu = luci.sys.exec("cat /etc/flippy-openwrt-release 2>/dev/null | grep SHOW_INSTALL_MENU | awk -F'=' '{print $2}' | grep -oE '(yes|no)' | xargs") or "Unknown"
entry({ "admin", "system", "amlogic", "info" }, form("amlogic/amlogic_info"), _("Amlogic Service"), 1).leaf = true
if (string.find(platfrom, "amlogic")) ~= nil or (string.find(install_menu, "yes")) ~= nil then
entry({ "admin", "system", "amlogic", "install" }, form("amlogic/amlogic_install"), _("Install OpenWrt"), 2).leaf = true
end
entry({ "admin", "system", "amlogic", "upload" }, form("amlogic/amlogic_upload"), _("Manually Upload Update"), 3).leaf = true
entry({ "admin", "system", "amlogic", "check" }, form("amlogic/amlogic_check"), _("Online Download Update"), 4).leaf = true
entry({ "admin", "system", "amlogic", "backup" }, form("amlogic/amlogic_backup"), _("Backup Firmware Config"), 5).leaf = true
entry({ "admin", "system", "amlogic", "backuplist" }, form("amlogic/amlogic_backuplist")).leaf = true
if (string.find(platfrom, "qemu")) == nil then
entry({ "admin", "system", "amlogic", "armcpu" }, cbi("amlogic/amlogic_armcpu"), _("CPU Settings"), 6).leaf = true
end
entry({ "admin", "system", "amlogic", "config" }, cbi("amlogic/amlogic_config"), _("Plugin Settings"), 7).leaf = true
entry({ "admin", "system", "amlogic", "log" }, form("amlogic/amlogic_log"), _("Server Logs"), 8).leaf = true
entry({ "admin", "system", "amlogic", "poweroff" }, form("amlogic/amlogic_poweroff"), _("PowerOff"), 9).leaf = true
entry({ "admin", "system", "amlogic", "check_firmware" }, call("action_check_firmware"))
entry({ "admin", "system", "amlogic", "check_plugin" }, call("action_check_plugin"))
entry({ "admin", "system", "amlogic", "check_kernel" }, call("action_check_kernel"))
entry({ "admin", "system", "amlogic", "refresh_log" }, call("action_refresh_log"))
entry({ "admin", "system", "amlogic", "del_log" }, call("action_del_log"))
entry({ "admin", "system", "amlogic", "start_model_database" }, call("action_check_model_database")).leaf = true
entry({ "admin", "system", "amlogic", "start_check_install" }, call("action_start_check_install")).leaf = true
entry({ "admin", "system", "amlogic", "start_check_firmware" }, call("action_start_check_firmware")).leaf = true
entry({ "admin", "system", "amlogic", "start_check_plugin" }, call("action_start_check_plugin")).leaf = true
entry({ "admin", "system", "amlogic", "start_check_kernel" }, call("action_start_check_kernel")).leaf = true
entry({ "admin", "system", "amlogic", "start_check_rescue" }, call("action_start_check_rescue")).leaf = true
entry({ "admin", "system", "amlogic", "start_check_upfiles" }, call("action_start_check_upfiles")).leaf = true
entry({ "admin", "system", "amlogic", "start_amlogic_install" }, call("action_start_amlogic_install")).leaf = true
entry({ "admin", "system", "amlogic", "start_amlogic_update" }, call("action_start_amlogic_update")).leaf = true
entry({ "admin", "system", "amlogic", "start_amlogic_kernel" }, call("action_start_amlogic_kernel")).leaf = true
entry({ "admin", "system", "amlogic", "start_amlogic_plugin" }, call("action_start_amlogic_plugin")).leaf = true
entry({ "admin", "system", "amlogic", "start_amlogic_rescue" }, call("action_start_amlogic_rescue")).leaf = true
entry({ "admin", "system", "amlogic", "start_snapshot_delete" }, call("action_start_snapshot_delete")).leaf = true
entry({ "admin", "system", "amlogic", "start_snapshot_restore" }, call("action_start_snapshot_restore")).leaf = true
entry({ "admin", "system", "amlogic", "start_snapshot_list" }, call("action_check_snapshot")).leaf = true
entry({ "admin", "system", "amlogic", "start_openwrt_author" }, call("action_openwrt_author")).leaf = true
entry({ "admin", "system", "amlogic", "state" }, call("action_state")).leaf = true
entry({ "admin", "system", "amlogic", "start_poweroff" }, call("action_poweroff")).leaf = true
entry({ "admin", "system", "amlogic", "start_switch" }, call("action_switch")).leaf = true
end
--Remove the spaces in the string
function trim(str)
--return (string.gsub(str, "^%s*(.-)%s*$", "%1"))
return (string.gsub(str, "%s+", ""))
end
--Create a temporary folder
local tmp_upload_dir = luci.sys.exec("[ -d /tmp/upload ] || mkdir -p /tmp/upload >/dev/null")
local tmp_amlogic_dir = luci.sys.exec("[ -d /tmp/amlogic ] || mkdir -p /tmp/amlogic >/dev/null")
--Whether to automatically restore the firmware config
local amlogic_firmware_config = luci.sys.exec("uci get amlogic.config.amlogic_firmware_config 2>/dev/null") or "1"
if tonumber(amlogic_firmware_config) == 0 then
update_restore_config = "no-restore"
else
update_restore_config = "restore"
end
--Whether to automatically write to the bootLoader
local amlogic_write_bootloader = luci.sys.exec("uci get amlogic.config.amlogic_write_bootloader 2>/dev/null") or "1"
if tonumber(amlogic_write_bootloader) == 0 then
auto_write_bootloader = "no"
else
auto_write_bootloader = "yes"
end
--Set the file system type of the shared partition
local amlogic_shared_fstype = luci.sys.exec("uci get amlogic.config.amlogic_shared_fstype 2>/dev/null") or ""
if trim(amlogic_shared_fstype) == "" then
auto_shared_fstype = "ext4"
else
auto_shared_fstype = trim(amlogic_shared_fstype)
end
--Device identification
device_platfrom = luci.sys.exec("cat /etc/flippy-openwrt-release 2>/dev/null | grep PLATFORM | awk -F'=' '{print $2}' | grep -oE '(amlogic|rockchip|allwinner|qemu)' | xargs") or "Unknown"
if (string.find(device_platfrom, "rockchip")) ~= nil then
device_install_script = ""
device_update_script = "openwrt-update-rockchip"
device_kernel_script = "openwrt-kernel"
elseif (string.find(device_platfrom, "allwinner")) ~= nil then
device_install_script = "openwrt-install-allwinner"
device_update_script = "openwrt-update-allwinner"
device_kernel_script = "openwrt-kernel"
elseif (string.find(device_platfrom, "qemu")) ~= nil then
device_install_script = ""
device_update_script = "openwrt-update-kvm"
device_kernel_script = "openwrt-kernel"
else
device_install_script = "openwrt-install-amlogic"
device_update_script = "openwrt-update-amlogic"
device_kernel_script = "openwrt-kernel"
end
--General array functions
function string.split(input, delimiter)
input = tostring(input)
delimiter = tostring(delimiter)
if (delimiter == '') then return false end
local pos, arr = 0, {}
-- for each divider found
for st, sp in function() return string.find(input, delimiter, pos, true) end do
table.insert(arr, string.sub(input, pos, st - 1))
pos = sp + 1
end
table.insert(arr, string.sub(input, pos))
return arr
end
--Refresh the log
function action_refresh_log()
local logfile = "/tmp/amlogic/amlogic.log"
if not nixio.fs.access(logfile) then
luci.sys.exec("uname -a > /tmp/amlogic/amlogic.log && sync")
luci.sys.exec("echo '' > /tmp/amlogic/amlogic_check_install.log && sync >/dev/null 2>&1")
luci.sys.exec("echo '' > /tmp/amlogic/amlogic_check_upfiles.log && sync >/dev/null 2>&1")
luci.sys.exec("echo '' > /tmp/amlogic/amlogic_check_plugin.log && sync >/dev/null 2>&1")
luci.sys.exec("echo '' > /tmp/amlogic/amlogic_check_kernel.log && sync >/dev/null 2>&1")
luci.sys.exec("echo '' > /tmp/amlogic/amlogic_check_firmware.log && sync >/dev/null 2>&1")
luci.sys.exec("echo '' > /tmp/amlogic/amlogic_check_rescue.log && sync >/dev/null 2>&1")
luci.sys.exec("echo '' > /tmp/amlogic/amlogic_running_script.log && sync >/dev/null 2>&1")
end
luci.http.prepare_content("text/plain; charset=utf-8")
local f = io.open(logfile, "r+")
f:seek("set")
local a = f:read(2048000) or ""
f:close()
luci.http.write(a)
end
--Delete the logs
function action_del_log()
luci.sys.exec(": > /tmp/amlogic/amlogic.log")
luci.sys.exec(": > /tmp/amlogic/amlogic_check_install.log")
luci.sys.exec(": > /tmp/amlogic/amlogic_check_upfiles.log")
luci.sys.exec(": > /tmp/amlogic/amlogic_check_plugin.log")
luci.sys.exec(": > /tmp/amlogic/amlogic_check_kernel.log")
luci.sys.exec(": > /tmp/amlogic/amlogic_check_firmware.log")
luci.sys.exec(": > /tmp/amlogic/amlogic_check_rescue.log")
luci.sys.exec(": > /tmp/amlogic/amlogic_running_script.log")
end
--Upgrade luci-app-amlogic plugin
function start_amlogic_plugin()
local log_file = "/tmp/amlogic/amlogic_check_plugin.log"
local running_lock = "/tmp/amlogic/amlogic_running_script.log"
local config_file = "/etc/config/amlogic"
local config_bak = "/etc/config/amlogic_bak"
-- 1. Create a running lock and clear previous log
luci.sys.call("echo '1@Plugin update in progress, try again later!' > " .. running_lock .. " && > " .. log_file)
-- 2. Backup config file
luci.sys.call(string.format("[ -f %s ] && cp -vf %s %s >> %s 2>&1", config_file, config_file, config_bak, log_file))
-- 3. Detect and install
local install_status = 1
if luci.sys.call("command -v opkg >/dev/null") == 0 then
luci.sys.call("echo 'System uses opkg. Attempting to install .ipk package...' >> " .. log_file)
local install_cmd = string.format("opkg --force-reinstall install /tmp/amlogic/*.ipk >> %s 2>&1", log_file)
install_status = luci.sys.call(install_cmd)
elseif luci.sys.call("command -v apk >/dev/null") == 0 then
luci.sys.call("echo 'System uses apk. Attempting to install .apk package...' >> " .. log_file)
local install_cmd = string.format("apk add --force-overwrite --allow-untrusted /tmp/amlogic/*.apk >> %s 2>&1", log_file)
install_status = luci.sys.call(install_cmd)
else
luci.sys.call("echo 'Error: Neither opkg nor apk found. Aborting.' >> " .. log_file)
end
-- 4. Check result and finalize
if install_status == 0 then
-- SUCCESS
luci.sys.call("echo 'Installation successful. Finalizing...' >> " .. log_file)
luci.sys.call(string.format("[ -f %s ] && cp -vf %s %s >> %s 2>&1", config_bak, config_bak, config_file, log_file))
luci.sys.call("rm -rf /tmp/luci-indexcache /tmp/luci-modulecache/* " .. config_bak)
luci.sys.call("echo '' > " .. running_lock)
luci.sys.call("echo 'Successful Update' > " .. log_file)
return 0
else
-- FAILURE
luci.sys.call("echo '--- INSTALLATION FAILED! ---' >> " .. log_file)
luci.sys.call("echo 'Restoring configuration and aborting.' >> " .. log_file)
luci.sys.call(string.format("[ -f %s ] && cp -vf %s %s >> %s 2>&1", config_bak, config_bak, config_file, log_file))
luci.sys.call("rm -f " .. config_bak)
luci.sys.call("echo '' > " .. running_lock)
return install_status
end
end
--Upgrade the kernel
function start_amlogic_kernel()
luci.sys.call("echo '2@Kernel update in progress, try again later!' > /tmp/amlogic/amlogic_running_script.log && sync >/dev/null 2>&1")
luci.sys.call("chmod +x /usr/sbin/" .. device_kernel_script .. " >/dev/null 2>&1")
local state = luci.sys.call("/usr/sbin/" .. device_kernel_script .. " " .. auto_write_bootloader .. " > /tmp/amlogic/amlogic_check_kernel.log && sync >/dev/null 2>&1")
return state
end
--Upgrade amlogic openwrt firmware
function start_amlogic_update()
luci.sys.call("echo '3@OpenWrt update in progress, try again later!' > /tmp/amlogic/amlogic_running_script.log && sync >/dev/null 2>&1")
luci.sys.call("chmod +x /usr/sbin/" .. device_update_script .. " >/dev/null 2>&1")
local amlogic_update_sel = luci.http.formvalue("amlogic_update_sel")
local res = string.split(amlogic_update_sel, "@")
local update_firmware_name = res[1] or "auto"
local update_firmware_updated = res[2] or "updated"
local update_write_path = res[3] or "/tmp"
luci.sys.call("echo " .. update_firmware_updated .. " > " .. update_write_path .. "/.luci-app-amlogic/op_release_code 2>/dev/null && sync")
local state = luci.sys.call("/usr/sbin/" .. device_update_script .. " " .. update_firmware_name .. " " .. auto_write_bootloader .. " " .. update_restore_config .. " > /tmp/amlogic/amlogic_check_firmware.log && sync 2>/dev/null")
return state
end
--Read rescue kernel log
local function start_amlogic_rescue()
luci.sys.call("echo '4@Kernel rescue in progress, try again later!' > /tmp/amlogic/amlogic_running_script.log && sync >/dev/null 2>&1")
luci.sys.call("chmod +x /usr/sbin/" .. device_kernel_script .. " >/dev/null 2>&1")
local state = luci.sys.call("/usr/sbin/" .. device_kernel_script .. " -s > /tmp/amlogic/amlogic_check_rescue.log && sync >/dev/null 2>&1")
luci.sys.call("echo '' > /tmp/amlogic/amlogic_running_script.log && sync >/dev/null 2>&1")
return state
end
--Install amlogic openwrt firmware
function start_amlogic_install()
luci.sys.exec("chmod +x /usr/sbin/" .. device_install_script .. " >/dev/null 2>&1")
local amlogic_install_sel = luci.http.formvalue("amlogic_install_sel")
local res = string.split(amlogic_install_sel, "@")
soc_id = res[1] or "99"
if tonumber(res[1]) == 99 then
dtb_filename = res[2] or "auto_dtb"
else
dtb_filename = "auto_dtb"
end
local state = luci.sys.call("/usr/sbin/" .. device_install_script .. " " .. auto_write_bootloader .. " " .. soc_id .. " " .. dtb_filename .. " " .. auto_shared_fstype .. " > /tmp/amlogic/amlogic_check_install.log && sync 2>/dev/null")
return state
end
--Delets the snapshot
function start_snapshot_delete()
local snapshot_delete_sel = luci.http.formvalue("snapshot_delete_sel")
local state = luci.sys.exec("btrfs subvolume delete -c /.snapshots/" .. snapshot_delete_sel .. " 2>/dev/null && sync")
return state
end
--Restore to this snapshot
function start_snapshot_restore()
local snapshot_restore_sel = luci.http.formvalue("snapshot_restore_sel")
local state = luci.sys.exec("btrfs subvolume snapshot /.snapshots/etc-" .. snapshot_restore_sel .. " /etc 2>/dev/null && sync")
local state_nowreboot = luci.sys.exec("echo 'b' > /proc/sysrq-trigger 2>/dev/null")
return state
end
--Check the plugin
function action_check_plugin()
luci.sys.exec("chmod +x /usr/share/amlogic/amlogic_check_plugin.sh >/dev/null 2>&1")
return luci.sys.call("/usr/share/amlogic/amlogic_check_plugin.sh >/dev/null 2>&1")
end
--Check and download the kernel
function check_kernel()
luci.sys.exec("chmod +x /usr/share/amlogic/amlogic_check_kernel.sh >/dev/null 2>&1")
local kernel_options = luci.http.formvalue("kernel_options")
if kernel_options == "check" then
local state = luci.sys.call("/usr/share/amlogic/amlogic_check_kernel.sh -check >/dev/null 2>&1")
else
local state = luci.sys.call("/usr/share/amlogic/amlogic_check_kernel.sh -download " .. kernel_options .. " >/dev/null 2>&1")
end
return state
end
--Check the kernel
function action_check_kernel()
luci.http.prepare_content("application/json")
luci.http.write_json({
check_kernel_status = check_kernel();
})
end
--Check the firmware
function check_firmware()
luci.sys.exec("chmod +x /usr/share/amlogic/amlogic_check_firmware.sh >/dev/null 2>&1")
local firmware_options = luci.http.formvalue("firmware_options")
if firmware_options == "check" then
local state = luci.sys.call("/usr/share/amlogic/amlogic_check_firmware.sh -check >/dev/null 2>&1")
else
local state = luci.sys.call("/usr/share/amlogic/amlogic_check_firmware.sh -download " .. firmware_options .. " >/dev/null 2>&1")
end
return state
end
--Check the openwrt firmware version online
function action_check_firmware()
luci.http.prepare_content("application/json")
luci.http.write_json({
check_firmware_status = check_firmware();
})
end
--Read upload files log
local function start_check_upfiles()
return luci.sys.exec("sed -n '$p' /tmp/amlogic/amlogic_check_upfiles.log 2>/dev/null")
end
--Read plug-in check log
local function start_check_plugin()
return luci.sys.exec("sed -n '$p' /tmp/amlogic/amlogic_check_plugin.log 2>/dev/null")
end
--Read kernel check log
local function start_check_kernel()
return luci.sys.exec("sed -n '$p' /tmp/amlogic/amlogic_check_kernel.log 2>/dev/null")
end
--Read openwrt firmware check log
local function start_check_firmware()
return luci.sys.exec("sed -n '$p' /tmp/amlogic/amlogic_check_firmware.log 2>/dev/null")
end
--Read rescue kernel log
local function start_check_rescue()
return luci.sys.exec("sed -n '$p' /tmp/amlogic/amlogic_check_rescue.log 2>/dev/null")
end
--Read openwrt install log
local function start_check_install()
return luci.sys.exec("sed -n '$p' /tmp/amlogic/amlogic_check_install.log 2>/dev/null")
end
--Return online check plugin result
function action_start_check_plugin()
luci.http.prepare_content("application/json")
luci.http.write_json({
start_check_plugin = start_check_plugin();
})
end
--Return online check kernel result
function action_start_check_kernel()
luci.http.prepare_content("application/json")
luci.http.write_json({
start_check_kernel = start_check_kernel();
})
end
--Return online check openwrt firmware result
function action_start_check_firmware()
luci.http.prepare_content("application/json")
luci.http.write_json({
start_check_firmware = start_check_firmware();
})
end
--Return online check rescue kernel result
function action_start_check_rescue()
luci.http.prepare_content("application/json")
luci.http.write_json({
start_check_rescue = start_check_rescue();
})
end
--Return online install openwrt result
function action_start_check_install()
luci.http.prepare_content("application/json")
luci.http.write_json({
start_check_install = start_check_install();
})
end
--Return online install openwrt result for amlogic
function action_start_amlogic_install()
luci.http.prepare_content("application/json")
luci.http.write_json({
rule_install_status = start_amlogic_install();
})
end
--Return snapshot delete result
function action_start_snapshot_delete()
luci.http.prepare_content("application/json")
luci.http.write_json({
rule_delete_status = start_snapshot_delete();
})
end
--Return snapshot restore result
function action_start_snapshot_restore()
luci.http.prepare_content("application/json")
luci.http.write_json({
rule_restore_status = start_snapshot_restore();
})
end
--Return openwrt update result for amlogic
function action_start_amlogic_update()
luci.http.prepare_content("application/json")
luci.http.write_json({
rule_update_status = start_amlogic_update();
})
end
--Return kernel update result
function action_start_amlogic_kernel()
luci.http.prepare_content("application/json")
luci.http.write_json({
rule_kernel_status = start_amlogic_kernel();
})
end
--Return plugin update result
function action_start_amlogic_plugin()
luci.http.prepare_content("application/json")
luci.http.write_json({
rule_plugin_status = start_amlogic_plugin();
})
end
--Return rescue kernel result
function action_start_amlogic_rescue()
luci.http.prepare_content("application/json")
luci.http.write_json({
start_amlogic_rescue = start_amlogic_rescue();
})
end
--Return files upload result
function action_start_check_upfiles()
luci.http.prepare_content("application/json")
luci.http.write_json({
start_check_upfiles = start_check_upfiles();
})
end
--Return the current openwrt firmware version
local function current_firmware_version()
return luci.sys.exec("uname -r 2>/dev/null | grep -oE '^[1-9].[0-9]{1,3}.[0-9]+'") or "Invalid value."
end
--Return the current plugin version
local function current_plugin_version()
local version_str = ""
-- Check if opkg command exists
if sys.call("command -v opkg >/dev/null") == 0 then
local opkg_cmd = string.format("opkg list-installed | grep '^%s' | awk '{print $3}' | cut -d'-' -f1", PKG_NAME)
version_str = trim(sys.exec(opkg_cmd))
end
-- If opkg failed or not found, check if apk command exists
if version_str == "" and sys.call("command -v apk >/dev/null") == 0 then
local apk_cmd = string.format("apk list --installed 2>/dev/null | grep '^%s' | awk '{print $1}' | cut -d'-' -f4", PKG_NAME)
version_str = trim(sys.exec(apk_cmd))
end
if version_str ~= "" then
return version_str
else
return "Invalid value."
end
end
--Return the current kernel version
local function current_kernel_version()
return luci.sys.exec("uname -r 2>/dev/null | grep -oE '^[1-9].[0-9]{1,3}.[0-9]+'") or "Invalid value."
end
--Return the current kernel branch
local function current_kernel_branch()
local default_kernel_branch = luci.sys.exec("uname -r 2>/dev/null | grep -oE '^[1-9].[0-9]{1,3}'")
local amlogic_kernel_branch = luci.sys.exec("uci get amlogic.config.amlogic_kernel_branch 2>/dev/null | grep -oE '^[1-9].[0-9]{1,3}'") or ""
if trim(amlogic_kernel_branch) == "" then
return default_kernel_branch
else
return amlogic_kernel_branch
end
end
--Return current version information
function action_state()
luci.http.prepare_content("application/json")
luci.http.write_json({
current_firmware_version = current_firmware_version(),
current_plugin_version = current_plugin_version(),
current_kernel_version = current_kernel_version(),
current_kernel_branch = current_kernel_branch();
})
end
--Read external model database
local function my_model_database()
if (string.find(device_platfrom, "allwinner")) ~= nil then
return luci.sys.exec("cat /etc/model_database.txt 2>/dev/null | grep -E '^w[0-9]{1,9}.*:' | awk -F ':' '{print $1,$2}' OFS='###' ORS='@@@' | tr ' ' '~' 2>&1")
else
return luci.sys.exec("cat /etc/model_database.txt 2>/dev/null | grep -E '^[0-9]{1,9}.*:' | awk -F ':' '{print $1,$2}' OFS='###' ORS='@@@' | tr ' ' '~' 2>&1")
end
end
--Return external model database
function action_check_model_database()
luci.http.prepare_content("application/json")
luci.http.write_json({
my_model_database = my_model_database();
})
end
--Return the current snapshot list
local function current_snapshot()
return luci.sys.exec("btrfs subvolume list -rt / | awk '{print $4}' | grep .snapshots") or "Invalid value."
end
--Return current snapshot information
function action_check_snapshot()
luci.http.prepare_content("application/json")
luci.http.write_json({
current_snapshot = current_snapshot();
})
end
--Return the openwrt compile author
local function openwrt_author()
return luci.sys.exec("uci get amlogic.config.amlogic_firmware_repo 2>/dev/null") or "Invalid value."
end
--Return current snapshot information
function action_openwrt_author()
luci.http.prepare_content("application/json")
luci.http.write_json({
openwrt_author = openwrt_author();
})
end
--Shut down the router
function action_poweroff()
luci.sys.exec("/sbin/poweroff")
end
--Switching dual partition
function action_switch()
luci.sys.exec("[ -f /boot/efi/EFI/BOOT/grub.cfg.prev ] && (cd /boot/efi/EFI/BOOT/ && mv -f grub.cfg grub.cfg.bak && mv -f grub.cfg.prev grub.cfg && mv -f grub.cfg.bak grub.cfg.prev)")
luci.sys.exec("sync && reboot")
end
@@ -0,0 +1,98 @@
--Copyright: https://github.com/coolsnowwolf/luci/tree/master/applications/luci-app-cpufreq
--Planner: https://github.com/unifreq/openwrt_packit
--Extended support: https://github.com/ophub/luci-app-amlogic
--Function: Support multi-core
local mp
--Remove the spaces in the string
function trim(str)
--return (string.gsub(str, "^%s*(.-)%s*$", "%1"))
return (string.gsub(str, "%s+", ""))
end
--split
function string.split(e, t)
e = tostring(e)
t = tostring(t)
if (t == '') then return false end
local a, o = 0, {}
for i, t in function() return string.find(e, t, a, true) end do
table.insert(o, string.sub(e, a, i - 1))
a = t + 1
end
table.insert(o, string.sub(e, a))
return o
end
--Auto-complete node
local check_config_settings = luci.sys.exec("uci get amlogic.@settings[0].governor0 2>/dev/null") or ""
if (trim(check_config_settings) == "") then
luci.sys.exec("uci delete amlogic.@settings[0] 2>/dev/null")
luci.sys.exec("uci set amlogic.armcpu='settings' 2>/dev/null")
luci.sys.exec("uci commit amlogic 2>/dev/null")
end
mp = Map("amlogic")
mp.title = translate("CPU Freq Settings")
mp.description = translate("Set CPU Scaling Governor to Max Performance or Balance Mode")
s = mp:section(NamedSection, "armcpu", "settings")
s.anonymouse = true
local cpu_policys = luci.sys.exec("ls /sys/devices/system/cpu/cpufreq | grep -E 'policy[0-9]{1,3}' | xargs") or "policy0"
policy_array = string.split(cpu_policys, " ")
for tt, policy_name in ipairs(policy_array) do
--Dynamic tab, automatically changes according to the number of cores, begin ------
policy_name = tostring(trim(policy_name))
policy_id = tostring(trim(string.gsub(policy_name, "policy", "")))
tab_name = policy_name
tab_id = tostring(trim("tab" .. policy_id))
cpu_freqs = nixio.fs.readfile(trim("/sys/devices/system/cpu/cpufreq/" .. policy_name .. "/scaling_available_frequencies")) or "100000"
cpu_freqs = string.sub(cpu_freqs, 1, -3)
cpu_governors = nixio.fs.readfile(trim("/sys/devices/system/cpu/cpufreq/" .. policy_name .. "/scaling_available_governors")) or "performance"
cpu_governors = string.sub(cpu_governors, 1, -3)
freq_array = string.split(cpu_freqs, " ")
governor_array = string.split(cpu_governors, " ")
s:tab(tab_id, tab_name)
tab_core_type = s:taboption(tab_id, DummyValue, trim("core_type" .. policy_id), translate("Microarchitectures:"))
tab_core_type.default = luci.sys.exec("cat /sys/devices/system/cpu/cpu" .. policy_id .. "/uevent | grep -E '^OF_COMPATIBLE_0.*' | tr -d 'OF_COMPATIBLE_0=' | xargs") or "Unknown"
tab_core_type.rmempty = false
governor = s:taboption(tab_id, ListValue, trim("governor" .. policy_id), translate("CPU Scaling Governor:"))
for t, e in ipairs(governor_array) do
if e ~= "" then governor:value(e, translate(e, string.upper(e))) end
end
governor.default = "schedutil"
governor.rmempty = false
minfreq = s:taboption(tab_id, ListValue, trim("minfreq" .. policy_id), translate("Min Freq:"))
for t, e in ipairs(freq_array) do
if e ~= "" then minfreq:value(e) end
end
minfreq.default = "500000"
minfreq.rmempty = false
maxfreq = s:taboption(tab_id, ListValue, trim("maxfreq" .. policy_id), translate("Max Freq:"))
for t, e in ipairs(freq_array) do
if e ~= "" then maxfreq:value(e) end
end
maxfreq.default = "1512000"
maxfreq.rmempty = false
--Dynamic tab, automatically changes according to the number of cores, end ------
end
-- Apply the settings to the system
function mp.on_after_commit(self)
luci.sys.exec("(sleep 2 && /etc/init.d/amlogic start) >/dev/null 2>&1 &")
end
return mp
@@ -0,0 +1,151 @@
--Copyright: https://github.com/coolsnowwolf/luci/tree/master/applications/luci-app-filetransfer
--Extended support: https://github.com/ophub/luci-app-amlogic
--Function: Download files
local io = require "io"
local os = require "os"
local fs = require "nixio.fs"
local b, c, x
-- Checks wheather the given path exists and points to a directory.
function isdirectory(dirname)
return fs.stat(dirname, "type") == "dir"
end
-- Check if a file or directory exists
function file_exists(path)
local file = io.open(path, "rb")
if file then file:close() end
return file ~= nil
end
--SimpleForm for Backup Config
b = SimpleForm("backup", nil)
b.title = translate("Backup Firmware Config")
b.description = translate("Backup OpenWrt config (openwrt_config.tar.gz). Use this file to restore the config in [Manually Upload Update].")
b.reset = false
b.submit = false
s = b:section(SimpleSection, "", "")
-- Button for customize backup list
my = s:option(Button, "customize", translate("Edit List:"))
my.template = "amlogic/other_button"
my.render = function(self, section, scope)
self.section = true
scope.display = ""
self.inputtitle = translate("Open List")
self.inputstyle = "save"
Button.render(self, section, scope)
end
my.write = function(self, section, scope)
local handle = io.popen("[[ -s /etc/amlogic_backup_list.conf ]] || sed -n \"/BACKUP_LIST='/,/.*'$/p\" /usr/sbin/openwrt-backup | sed -e \"s/BACKUP_LIST=\\(.*\\)/\\1/; s/'//g; s/\\\\\\\\//g; s/ //g\" > /etc/amlogic_backup_list.conf 2>/dev/null")
handle:close()
luci.http.redirect(luci.dispatcher.build_url("admin", "system", "amlogic", "backuplist"))
end
-- Button for download backup config
o = s:option(Button, "download", translate("Backup Config:"))
o.template = "amlogic/other_button"
um = s:option(DummyValue, "", nil)
um.template = "amlogic/other_dvalue"
o.render = function(self, section, scope)
self.section = true
scope.display = ""
self.inputtitle = translate("Download Backup")
self.inputstyle = "save"
Button.render(self, section, scope)
end
o.write = function(self, section, scope)
local x = luci.sys.exec("chmod +x /usr/sbin/openwrt-backup 2>/dev/null")
local r = luci.sys.exec("/usr/sbin/openwrt-backup -b > /tmp/amlogic/amlogic.log && sync 2>/dev/null")
local sPath, sFile, fd, block
sPath = "/.reserved/openwrt_config.tar.gz"
sFile = fs.basename(sPath)
if isdirectory(sPath) then
fd = io.popen('tar -C "%s" -cz .' % { sPath }, "r")
sFile = sFile .. ".tar.gz"
else
fd = nixio.open(sPath, "r")
end
if not fd then
um.value = translate("Couldn't open file:") .. sPath
return
else
um.value = translate("The file Will download automatically.") .. sPath
end
luci.http.header('Content-Disposition', 'attachment; filename="%s"' % { sFile })
luci.http.prepare_content("application/octet-stream")
while true do
block = fd:read(nixio.const.buffersize)
if (not block) or (#block == 0) then
break
else
luci.http.write(block)
end
end
fd:close()
luci.http.close()
end
-- Button for restore backup list
r = s:option(Button, "restore", translate("Restore Backup:"))
r.template = "amlogic/other_button"
r.render = function(self, section, scope)
self.section = true
scope.display = ""
self.inputtitle = translate("Upload Backup")
self.inputstyle = "save"
Button.render(self, section, scope)
end
r.write = function(self, section, scope)
luci.http.redirect(luci.dispatcher.build_url("admin", "system", "amlogic", "upload"))
end
-- SimpleForm for Create Snapshot
c = SimpleForm("snapshot", nil)
c.title = translate("Snapshot Management")
c.description = translate("Create a snapshot of the current system configuration, or restore to a snapshot.")
c.reset = false
c.submit = false
d = c:section(SimpleSection, "", nil)
w = d:option(Button, "create_snapshot", "")
w.template = "amlogic/other_button"
w.render = function(self, section, scope)
self.section = true
scope.display = ""
self.inputtitle = translate("Create Snapshot")
self.inputstyle = "save"
Button.render(self, section, scope)
end
w.write = function(self, section, scope)
local x = luci.sys.exec("btrfs subvolume snapshot -r /etc /.snapshots/etc-" .. os.date("%m.%d.%H%M%S") .. " 2>/dev/null && sync")
luci.http.redirect(luci.dispatcher.build_url("admin", "system", "amlogic", "backup"))
end
w = d:option(TextValue, "snapshot_list", nil)
w.template = "amlogic/other_snapshot"
--KVM virtual machine switching dual partition
if file_exists("/boot/efi/EFI/BOOT/grub.cfg.prev") then
x = SimpleForm("kvm", nil)
x.title = translate("KVM dual system switching")
x.description = translate("You can freely switch between KVM dual partitions, using OpenWrt systems in different partitions.")
x.reset = false
x.submit = false
x:section(SimpleSection).template = "amlogic/other_kvm"
end
return b, c, x
@@ -0,0 +1,51 @@
local fs = require "nixio.fs"
local backup_list_conf = "/etc/amlogic_backup_list.conf"
-- Delete all spaces and tabs at the beginning of the line, and the unified line break is \n
function remove_spaces(value)
local lines = {}
for line in value:gmatch("[^\r\n]+") do
line = line:gsub("^%s*", "")
if line ~= "" then
table.insert(lines, line)
end
end
value = table.concat(lines, "\n")
value = value:gsub("[\r\n]+", "\n")
return value
end
-- Remove backslash at the end of each line
function remove_backslash_at_end(value)
local lines = {}
for line in value:gmatch("[^\r\n]+") do
line = line:gsub("%s*\\%s*$", "")
table.insert(lines, line)
end
return table.concat(lines, "\n")
end
local f = SimpleForm("customize",
translate("Backup Configuration - Custom List"),
translate("Write one configuration item per line, and directories should end with a /."))
local o = f:field(Value, "_custom")
o.template = "cbi/tvalue"
o.rows = 30
function o.cfgvalue(self, section)
local readconf = fs.readfile(backup_list_conf)
local value = remove_spaces(readconf)
local value = remove_backslash_at_end(value)
return value
end
function o.write(self, section, value)
local value = remove_spaces(value)
local value = remove_backslash_at_end(value)
fs.writefile(backup_list_conf, value)
luci.http.redirect(luci.dispatcher.build_url("admin", "system", "amlogic", "backup"))
end
return f
@@ -0,0 +1,22 @@
local b, c
--SimpleForm for Check
b = SimpleForm("amlogic", nil)
b.title = translate("Check Update")
b.description = translate("Provide OpenWrt Firmware, Kernel and Plugin online check, download and update service.")
b.reset = false
b.submit = false
b:section(SimpleSection).template = "amlogic/other_check"
--SimpleForm for Rescue Kernel
c = SimpleForm("rescue", nil)
c.title = translate("Rescue Kernel")
c.description = translate("When a kernel update fails and causes the OpenWrt system to be unbootable, the kernel can be restored by mutual recovery from eMMC/NVMe/sdX.")
c.reset = false
c.submit = false
c:section(SimpleSection).template = "amlogic/other_rescue"
return b, c
@@ -0,0 +1,156 @@
--Remove the spaces in the string
function trim(str)
--return (string.gsub(str, "^%s*(.-)%s*$", "%1"))
return (string.gsub(str, "%s+", ""))
end
--Auto-complete node
local check_config_amlogic = luci.sys.exec("uci get amlogic.@amlogic[0].amlogic_firmware_repo 2>/dev/null") or ""
if (trim(check_config_amlogic) == "") then
luci.sys.exec("uci delete amlogic.@amlogic[0] 2>/dev/null")
luci.sys.exec("uci set amlogic.config='amlogic' 2>/dev/null")
luci.sys.exec("uci commit amlogic 2>/dev/null")
end
b = Map("amlogic")
b.title = translate("Plugin Settings")
local des_content = translate("You can customize the github.com download repository of OpenWrt files and kernels in [Online Download Update].")
local des_content = des_content .. "<br />" .. translate("Tip: The same files as the current OpenWrt system's BOARD (such as rock5b) and kernel (such as 5.10) will be downloaded.")
b.description = des_content
o = b:section(NamedSection, "config", "amlogic")
o.anonymouse = true
--1.Set OpenWrt Firmware Repository
mydevice = o:option(DummyValue, "mydevice", translate("Current Device:"))
mydevice.description = translate("Display the PLATFORM classification of the device.")
mydevice_platfrom = trim(luci.sys.exec("cat /etc/flippy-openwrt-release 2>/dev/null | grep PLATFORM | awk -F'=' '{print $2}' | grep -oE '(amlogic|rockchip|allwinner|qemu)'")) or "Unknown"
mydevice.default = "PLATFORM: " .. mydevice_platfrom
mydevice.rmempty = false
--2.Set OpenWrt Firmware Repository
firmware_repo = o:option(Value, "amlogic_firmware_repo", translate("OpenWrt download repository:"))
firmware_repo.description = translate("Set the OpenWrt files download repository on github.com in [Online Download Update].")
firmware_repo.default = "https://github.com/breakingbadboy/OpenWrt"
firmware_repo.rmempty = false
--3.Set OpenWrt Releases's Tag Keywords
firmware_tag = o:option(Value, "amlogic_firmware_tag", translate("OpenWrt download tags keyword:"))
firmware_tag.description = translate("Set the OpenWrt files download tags keyword for github.com in [Online Download Update].")
firmware_tag.default = "ARMv8"
firmware_tag.rmempty = false
--4.Set OpenWrt Firmware Suffix
firmware_suffix = o:option(Value, "amlogic_firmware_suffix", translate("OpenWrt files suffix:"))
firmware_suffix.description = translate("Set the OpenWrt files download suffix for github.com in [Online Download Update].")
firmware_suffix:value(".7z", translate(".7z"))
firmware_suffix:value(".zip", translate(".zip"))
firmware_suffix:value(".img.gz", translate(".img.gz"))
firmware_suffix:value(".img.xz", translate(".img.xz"))
firmware_suffix.default = ".img.gz"
firmware_suffix.rmempty = false
--5.Set OpenWrt Kernel DownLoad Path
kernel_path = o:option(Value, "amlogic_kernel_path", translate("Kernel download repository:"))
kernel_path.description = translate("Set the kernel files download repository on github.com in [Online Download Update].")
kernel_path:value("https://github.com/breakingbadboy/OpenWrt")
kernel_path:value("https://github.com/ophub/kernel")
kernel_path.default = "https://github.com/breakingbadboy/OpenWrt"
kernel_path.rmempty = false
--6. Set OpenWrt Kernel Tags
-- Read the currently SAVED value of the kernel path.
local current_kernel_path = trim(luci.sys.exec("uci get amlogic.@amlogic[0].amlogic_kernel_path 2>/dev/null") or "")
-- If it's not set yet, use its default value for the logic below.
if current_kernel_path == "" then
current_kernel_path = kernel_path.default
end
-- Define the tag lists.
-- The base list, available for all repositories.
local known_tags = {
kernel_rk3588 = "kernel_rk3588 [Rockchip RK3588 Kernel]",
kernel_rk35xx = "kernel_rk35xx [Rockchip RK35xx Kernel]",
kernel_stable = "kernel_stable [Mainline Stable Kernel]",
}
-- Additional tags only available for the 'ophub/kernel' repository.
local ophub_extra_tags = {
kernel_flippy = "kernel_flippy [Mainline Stable Kernel by Flippy]",
kernel_h6 = "kernel_h6 [Allwinner H6 Kernel]",
kernel_beta = "kernel_beta [Beta Kernel]",
}
-- Conditionally add the extra tags to the list.
if (string.find(current_kernel_path, "ophub/kernel")) then
for value, display_name in pairs(ophub_extra_tags) do
known_tags[value] = display_name
end
end
-- Determine the default kernel tag based on existing config or system info.
local kernel_tagsname
local existing_tag = trim(luci.sys.exec("uci get amlogic.@amlogic[0].amlogic_kernel_tags 2>/dev/null") or "")
if existing_tag ~= "" then
kernel_tagsname = existing_tag
else
local kernel_release_info = trim(luci.sys.exec("uname -r 2>/dev/null")) or ""
if (string.find(kernel_release_info, "-rk3588")) then
kernel_tagsname = "kernel_rk3588"
elseif (string.find(kernel_release_info, "-rk35xx")) then
kernel_tagsname = "kernel_rk35xx"
elseif (string.find(kernel_release_info, "-h6") or string.find(kernel_release_info, "-zicai")) then
kernel_tagsname = "kernel_h6"
else
kernel_tagsname = "kernel_stable"
end
end
-- Create the kernel tags option.
kernel_tags = o:option(Value, "amlogic_kernel_tags", translate("Kernel download tags:"))
kernel_tags.description = translate("Set the kernel files download tags on github.com in [Online Download Update].")
-- Populate the dropdown with the known tags.
for value, display_name in pairs(known_tags) do
kernel_tags:value(value, translate(display_name))
end
-- Ensure the default tag is included in the options.
if not known_tags[kernel_tagsname] then
kernel_tags:value(kernel_tagsname, kernel_tagsname)
end
-- Set the default and other properties.
kernel_tags.default = kernel_tagsname
kernel_tags.rmempty = false
--7.Set kernel version branch
kernel_branch = o:option(Value, "amlogic_kernel_branch", translate("Set version branch:"))
kernel_branch.description = translate("Set the version branch of the OpenWrt files and kernel selected in [Online Download Update].")
kernel_branch:value("5.4", translate("5.4"))
kernel_branch:value("5.10", translate("5.10"))
kernel_branch:value("5.15", translate("5.15"))
kernel_branch:value("6.1", translate("6.1"))
kernel_branch:value("6.6", translate("6.6"))
kernel_branch:value("6.12", translate("6.12"))
kernel_branch:value("6.18", translate("6.18"))
local default_kernel_branch = luci.sys.exec("uname -r | grep -oE '^[1-9].[0-9]{1,3}'")
kernel_branch.default = trim(default_kernel_branch)
kernel_branch.rmempty = false
--8.Restore configuration
firmware_config = o:option(Flag, "amlogic_firmware_config", translate("Keep config update:"))
firmware_config.description = translate("Set whether to keep the current config during [Online Download Update] and [Manually Upload Update].")
firmware_config.default = "1"
firmware_config.rmempty = false
--9.Write bootloader
write_bootloader = o:option(Flag, "amlogic_write_bootloader", translate("Auto write bootloader:"))
write_bootloader.description = translate("[Recommended choice] Set whether to auto write bootloader during install and update OpenWrt.")
write_bootloader.default = "0"
write_bootloader.rmempty = false
--10.Set the file system type of the shared partition
shared_fstype = o:option(ListValue, "amlogic_shared_fstype", translate("Set the file system type:"))
shared_fstype.description = translate("[Default ext4] Set the file system type of the shared partition (/mnt/mmcblk*p4) when install OpenWrt.")
shared_fstype:value("ext4", translate("ext4"))
shared_fstype:value("f2fs", translate("f2fs"))
shared_fstype:value("btrfs", translate("btrfs"))
shared_fstype:value("xfs", translate("xfs"))
shared_fstype.default = "ext4"
shared_fstype.rmempty = false
return b
@@ -0,0 +1,12 @@
local b
--SimpleForm for Info
b = SimpleForm("amlogic", nil)
b.title = translate("Amlogic Service")
b.description = translate("Supports management of Amlogic s9xxx, Allwinner (V-Plus Cloud), and Rockchip (BeikeYun, Chainedbox L1 Pro) boxes.")
b.reset = false
b.submit = false
b:section(SimpleSection).template = "amlogic/other_info"
return b
@@ -0,0 +1,12 @@
local b
--SimpleForm for Install OpenWrt to Amlogic EMMC
b = SimpleForm("amlogic_install", nil)
b.title = translate("Install OpenWrt")
b.description = translate("Install OpenWrt to EMMC, Please select the device model, Or enter the dtb file name.")
b.reset = false
b.submit = false
b:section(SimpleSection).template = "amlogic/other_install"
return b
@@ -0,0 +1,15 @@
local b
--SimpleForm for Server Logs
b = SimpleForm("amlogic_log", nil)
b.title = translate("Server Logs")
b.description = translate("Display the execution log of the current operation.")
b.reset = false
b.submit = false
s = b:section(SimpleSection, "", nil)
o = s:option(TextValue, "")
o.template = "amlogic/other_log"
return b
@@ -0,0 +1,12 @@
local b
--SimpleForm for PowerOff
b = SimpleForm("poweroff", nil)
b.title = translate("PowerOff")
b.description = translate("Shut down your router device.")
b.reset = false
b.submit = false
b:section(SimpleSection).template = "amlogic/other_poweroff"
return b
@@ -0,0 +1,300 @@
--Copyright: https://github.com/coolsnowwolf/luci/tree/master/applications/luci-app-filetransfer
--Extended support: https://github.com/ophub/luci-app-amlogic
--Function: Upload files
local os = require "os"
local fs = require "nixio.fs"
local nutil = require "nixio.util"
local type = type
local b, form
--Remove the spaces in the string
function trim(str)
--return (string.gsub(str, "^%s*(.-)%s*$", "%1"))
return (string.gsub(str, "%s+", ""))
end
-- Evaluate given shell glob pattern and return a table containing all matching
function glob(...)
local iter, code, msg = fs.glob(...)
if iter then
return nutil.consume(iter)
else
return nil, code, msg
end
end
-- Checks wheather the given path exists and points to a regular file.
function isfile(filename)
return fs.stat(filename, "type") == "reg"
end
-- Get the last modification time of given file path in Unix epoch format.
function mtime(path)
return fs.stat(path, "mtime")
end
local stat_tr = {
reg = "regular",
dir = "directory",
lnk = "link",
chr = "character device",
blk = "block device",
fifo = "fifo",
sock = "socket"
}
-- Get information about given file or directory.
function stat(path, key)
local data, code, msg = fs.stat(path)
if data then
data.mode = data.modestr
data.type = stat_tr[data.type] or "?"
end
return key and data and data[key] or data, code, msg
end
--Set default upload path
local ROOT_PTNAME = trim(luci.sys.exec("df / | tail -n1 | awk '{print $1}' | awk -F '/' '{print $3}'"))
if ROOT_PTNAME then
if (string.find(ROOT_PTNAME, "mmcblk[0-4]p[1-4]")) then
local EMMC_NAME = trim(luci.sys.exec("echo " .. ROOT_PTNAME .. " | awk '{print substr($1, 1, length($1)-2)}'"))
upload_path = trim("/mnt/" .. EMMC_NAME .. "p4/")
elseif (string.find(ROOT_PTNAME, "[hsv]d[a-z]")) then
local EMMC_NAME = trim(luci.sys.exec("echo " .. ROOT_PTNAME .. " | awk '{print substr($1, 1, length($1)-1)}'"))
upload_path = trim("/mnt/" .. EMMC_NAME .. "4/")
else
upload_path = "/tmp/upload/"
end
else
upload_path = "/tmp/upload/"
end
--Clear the version check log
luci.sys.exec("echo '' > /tmp/amlogic/amlogic_check_plugin.log && sync >/dev/null 2>&1")
luci.sys.exec("echo '' > /tmp/amlogic/amlogic_check_kernel.log && sync >/dev/null 2>&1")
--SimpleForm for Update OpenWrt firmware/kernel
b = SimpleForm("upload", nil)
b.title = translate("Upload")
local des_content = translate("Update plugins first, then update the kernel or firmware.")
local des_content = des_content .. "<br />" .. translate("After uploading [Firmware], [Kernel], [IPK] or [Backup Config], the operation buttons will be displayed.")
b.description = des_content
b.reset = false
b.submit = false
s = b:section(SimpleSection, "", "")
o = s:option(FileUpload, "")
o.template = "amlogic/other_upload"
um = s:option(DummyValue, "", nil)
um.template = "amlogic/other_dvalue"
local dir, fd
dir = upload_path
fs.mkdir(dir)
luci.http.setfilehandler(
function(meta, chunk, eof)
if not fd then
if not meta then return end
if meta and chunk then fd = nixio.open(dir .. meta.file, "w") end
if not fd then
um.value = translate("Create upload file error.") .. " Error Info: " .. trim(upload_path .. meta.file)
return
end
end
if chunk and fd then
fd:write(chunk)
end
if eof and fd then
fd:close()
fd = nil
um.value = translate("File saved to") .. trim(upload_path .. meta.file)
end
end
)
if luci.http.formvalue("upload") then
local f = luci.http.formvalue("ulfile")
if #f <= 0 then
um.value = translate("No specify upload file.")
end
end
local function getSizeStr(size)
local i = 0
local byteUnits = { ' kB', ' MB', ' GB', ' TB' }
repeat
size = size / 1024
i = i + 1
until (size <= 1024)
return string.format("%.1f", size) .. byteUnits[i]
end
local inits, attr = {}
for i, f in ipairs(glob(trim(upload_path .. "*"))) do
attr = stat(f)
itisfile = isfile(f)
if attr and itisfile then
inits[i] = {}
inits[i].name = fs.basename(f)
inits[i].mtime = os.date("%Y-%m-%d %H:%M:%S", attr.mtime)
inits[i].modestr = attr.modestr
inits[i].size = getSizeStr(attr.size)
inits[i].remove = 0
inits[i].ipk = false
--Check whether the openwrt firmware file
-- openwrt_s905d_v5.10.16_2021.05.31.1958.img.gz
if (string.lower(string.sub(fs.basename(f), -7, -1)) == ".img.gz") then
openwrt_firmware_file = true
end
-- openwrt_s905d_n1_R21.7.15_k5.4.134-flippy-62+o.img.xz
if (string.lower(string.sub(fs.basename(f), -7, -1)) == ".img.xz") then
openwrt_firmware_file = true
end
-- openwrt_s905d_n1_R21.7.15_k5.13.2-flippy-62+.7z
if (string.lower(string.sub(fs.basename(f), -3, -1)) == ".7z") then
openwrt_firmware_file = true
end
-- openwrt_s905d_n1_R21.7.15_k5.13.2-flippy-62+.img
if (string.lower(string.sub(fs.basename(f), -4, -1)) == ".img") then
openwrt_firmware_file = true
end
--Check whether the three kernel files
-- boot-5.10.16-flippy-53+.tar.gz
if (string.lower(string.sub(fs.basename(f), 1, 5)) == "boot-") then
boot_file = true
end
-- dtb-amlogic-5.10.16-flippy-53+.tar.gz
if (string.lower(string.sub(fs.basename(f), 1, 4)) == "dtb-") then
dtb_file = true
end
-- modules-5.10.16-flippy-53+.tar.gz
if (string.lower(string.sub(fs.basename(f), 1, 8)) == "modules-") then
modules_file = true
end
--Check whether the backup file
-- openwrt_config.tar.gz
if (string.lower(string.sub(fs.basename(f), 1, -1)) == "openwrt_config.tar.gz") then
backup_config_file = true
end
end
end
--SimpleForm for Upload file list
form = SimpleForm("filelist", translate("Upload file list"), nil)
form.reset = false
form.submit = false
description_info = ""
luci.sys.exec("echo '' > /tmp/amlogic/amlogic_check_upfiles.log && sync >/dev/null 2>&1")
if backup_config_file then
description_info = description_info .. translate("There are config file in the upload directory, and you can restore the config. ")
end
if boot_file and dtb_file and modules_file then
description_info = description_info .. translate("There are kernel files in the upload directory, and you can replace the kernel.")
luci.sys.exec("echo 'kernel' > /tmp/amlogic/amlogic_check_upfiles.log && sync >/dev/null 2>&1")
end
if openwrt_firmware_file then
description_info = description_info .. translate("There are openwrt firmware file in the upload directory, and you can update the openwrt.")
luci.sys.exec("echo 'firmware' > /tmp/amlogic/amlogic_check_upfiles.log && sync >/dev/null 2>&1")
end
if description_info ~= "" then
form.description = ' <span style="color: green"><b> Tip: ' .. description_info .. ' </b></span> '
end
tb = form:section(Table, inits)
nm = tb:option(DummyValue, "name", translate("File name"))
mt = tb:option(DummyValue, "mtime", translate("Modify time"))
ms = tb:option(DummyValue, "modestr", translate("Attributes"))
sz = tb:option(DummyValue, "size", translate("Size"))
btnrm = tb:option(Button, "remove", translate("Remove"))
btnrm.render = function(self, section, scope)
self.inputstyle = "remove"
Button.render(self, section, scope)
end
btnrm.write = function(self, section)
local v = fs.unlink(trim(upload_path .. fs.basename(inits[section].name)))
if v then table.remove(inits, section) end
return v
end
function IsConfigFile(name)
name = name or ""
local config_file = string.lower(string.sub(name, 1, -1))
return config_file == "openwrt_config.tar.gz"
end
-- Check if the file is a known package type (.ipk or .apk)
function IsPackageFile(name)
name = name or ""
local lname = string.lower(name)
return string.sub(lname, -4) == ".ipk" or string.sub(lname, -4) == ".apk"
end
--Add Button for *.ipk
btnis = tb:option(Button, "ipk", translate("Install"))
btnis.template = "amlogic/other_button"
btnis.render = function(self, section, scope)
if not inits[section] then return false end
if IsPackageFile(inits[section].name) then
scope.display = ""
self.inputtitle = translate("Install")
elseif IsConfigFile(inits[section].name) then
scope.display = ""
self.inputtitle = translate("Restore")
else
scope.display = "none"
end
self.inputstyle = "apply"
Button.render(self, section, scope)
end
btnis.write = function(self, section)
local file_to_install = inits[section].name
local full_path = upload_path .. file_to_install
if IsPackageFile(file_to_install) then
local r = ""
local install_cmd = ""
-- Check for opkg first
if luci.sys.call("command -v opkg >/dev/null") == 0 then
install_cmd = string.format('opkg --force-reinstall install %s', full_path)
r = luci.sys.exec(install_cmd)
-- If opkg is not found, check for apk
elseif luci.sys.call("command -v apk >/dev/null") == 0 then
-- NOTE: --allow-untrusted is required for local packages
install_cmd = string.format('apk add --force-overwrite --allow-untrusted %s', full_path)
r = luci.sys.exec(install_cmd)
-- If neither is found
else
r = "Error: Neither 'opkg' nor 'apk' package manager found on the system."
end
-- Clean LuCI cache after installation
luci.sys.exec("rm -rf /tmp/luci-indexcache /tmp/luci-modulecache/* >/dev/null 2>&1")
-- Display the result message
-- We add a message to prompt the user to refresh the page to see changes.
local result_msg = r .. "<br/><b>" .. translate("Please refresh the page to see the changes.") .. "</b>"
form.description = string.format('<span style="color: red">%s</span>', result_msg)
elseif IsConfigFile(inits[section].name) then
form.description = ' <span style="color: green"><b> ' .. translate("Tip: The config is being restored, and it will automatically restart after completion.") .. ' </b></span> '
luci.sys.exec("chmod +x /usr/sbin/openwrt-backup 2>/dev/null")
luci.sys.exec("/usr/sbin/openwrt-backup -r > /tmp/amlogic/amlogic.log && sync 2>/dev/null")
end
end
--SimpleForm for Check upload files
form:section(SimpleSection).template = "amlogic/other_upfiles"
return b, form
@@ -0,0 +1,7 @@
<%+cbi/valueheader%>
<% if self:cfgvalue(section) ~= false then %>
<input class="cbi-button cbi-button-<%=self.inputstyle or "button" %>" style="display: <%= display %>" type="submit" <%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.inputtitle or self.title)%> />
<% else %>
-
<% end %>
<%+cbi/valuefooter%>
@@ -0,0 +1,222 @@
<style>
.NewsTdHeight{ line-height: 20px; }
</style>
<fieldset class="cbi-section">
<table width="100%" class="NewsTdHeight">
<tr><td width="100%" colspan="2">
<p align="center">
<%:Update plugins first, then update the kernel or firmware. More options can be configured in [Plugin Settings].%> <span id="_openwrt_mainline_version"></span>
</p>
</td></tr>
<tr><td width="35%" align="right"><input type="button" class="cbi-button cbi-button-reload" value="<%:Only update Amlogic Service%>" onclick="return b_check_plugin(this)"/></td><td width="65%" align="left"><span id="_current_plugin_version"><%:Collecting data...%></span> <span id="_check_plugin"></span></td></tr>
<tr><td width="35%" align="right"><input type="button" class="cbi-button cbi-button-reload" value="<%:Update system kernel only%>" onclick="return b_check_kernel(this, 'check')"/></td><td width="65%" align="left"><span id="_current_kernel_version"><%:Collecting data...%></span> <span id="_check_kernel"></span></td></tr>
<tr><td width="35%" align="right"><input type="button" class="cbi-button cbi-button-reload" value="<%:Complete system update%>" onclick="return b_check_firmware(this, 'check')"/></td><td width="65%" align="left"><span id="_current_firmware_version"><%:Collecting data...%></span> <span id="_check_firmware"></span></td></tr>
</table>
</fieldset>
<script type="text/javascript">//<![CDATA[
function amlogic_update(btn,amlogic_update_sel)
{
btn.disabled = true;
btn.value = '<%:Updating...%> ';
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_amlogic_update")%>',
{
amlogic_update_sel: amlogic_update_sel
},
function(x,status)
{
if ( x && x.status == 200 ) {
if(status.rule_update_status!="0")
{
btn.value = '<%:Update Failed%>';
}
else
{
btn.value = '<%:Successful Update%>';
}
}
else {
btn.value = '<%:Update%>';
}
}
);
btn.disabled = false;
return false;
}
function amlogic_kernel(btn)
{
btn.disabled = true;
btn.value = '<%:Updating...%> ';
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_amlogic_kernel")%>', null, function(x, status) {
if ( x && x.status == 200 ) {
if(status.rule_kernel_status!="0")
{
btn.value = '<%:Update Failed%>';
}
else
{
btn.value = '<%:Successful Update%>';
}
}
else {
btn.value = '<%:Update%>';
}
}
);
btn.disabled = false;
return false;
}
function amlogic_plugin(btn)
{
btn.disabled = true;
btn.value = '<%:Updating...%> ';
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_amlogic_plugin")%>', null, function(x, status) {
if ( x && x.status == 200 ) {
if(status.rule_plugin_status!="0")
{
btn.value = '<%:Update Failed%>';
}
else
{
btn.value = '<%:Successful Update%>';
}
}
else {
btn.value = '<%:Update%>';
}
}
);
btn.disabled = false;
return false;
}
function b_check_firmware(btn,firmware_options)
{
btn.disabled = true;
btn.value = '<%:Checking...%>';
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "check_firmware")%>',
{
firmware_options: firmware_options
},
function(x,status)
{
if ( x && x.status == 200 ) {
if(status.check_firmware_status!="0")
{
btn.value = '<%:Complete system update%>';
}
else
{
btn.value = '<%:Complete system update%>';
}
}
else {
btn.value = '<%:Complete system update%>';
}
}
);
btn.disabled = false;
return false;
}
function b_check_plugin(btn)
{
btn.disabled = true;
btn.value = '<%:Checking...%>';
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "check_plugin")%>', null, function(x, status) {
if ( x && x.status == 200 ) {
btn.disabled = false;
btn.value = '<%:Only update Amlogic Service%>';
}
else {
btn.disabled = false;
btn.value = '<%:Only update Amlogic Service%>';
}
return false;
});
}
function b_check_kernel(btn,kernel_options)
{
btn.disabled = true;
btn.value = '<%:Checking...%>';
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "check_kernel")%>',
{
kernel_options: kernel_options
},
function(x,status)
{
if ( x && x.status == 200 ) {
if(status.check_kernel_status!="0")
{
btn.value = '<%:Update system kernel only%>';
}
else
{
btn.value = '<%:Update system kernel only%>';
}
}
else {
btn.value = '<%:Update system kernel only%>';
}
}
);
btn.disabled = false;
return false;
}
var _check_firmware = document.getElementById('_check_firmware');
XHR.poll(1, '<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_check_firmware")%>', status.start_check_firmware, function(x, status) {
if ( x && x.status == 200 ) {
if ( status.start_check_firmware != "\n" && status.start_check_firmware != "" ) {
_check_firmware.innerHTML = '<font color="blue"> '+status.start_check_firmware+'</font>';
}
if ( status.start_check_firmware == "\n" || status.start_check_firmware == "" ) {
_check_firmware.innerHTML = '';
}
}
});
var _check_plugin = document.getElementById('_check_plugin');
XHR.poll(1, '<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_check_plugin")%>', status.start_check_plugin, function(x, status) {
if ( x && x.status == 200 ) {
if ( status.start_check_plugin != "\n" && status.start_check_plugin != "" ) {
_check_plugin.innerHTML = '<font color="blue"> '+status.start_check_plugin+'</font>';
}
if ( status.start_check_plugin == "\n" || status.start_check_plugin == "" ) {
_check_plugin.innerHTML = '';
}
}
});
var _check_kernel = document.getElementById('_check_kernel');
XHR.poll(1, '<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_check_kernel")%>', status.start_check_kernel, function(x, status) {
if ( x && x.status == 200 ) {
if ( status.start_check_kernel != "\n" && status.start_check_kernel != "" ) {
_check_kernel.innerHTML = '<font color="blue"> '+status.start_check_kernel+'</font>';
}
if ( status.start_check_kernel == "\n" || status.start_check_kernel == "" ) {
_check_kernel.innerHTML = '';
}
}
});
var _current_firmware_version = document.getElementById('_current_firmware_version');
var _current_plugin_version = document.getElementById('_current_plugin_version');
var _current_kernel_version = document.getElementById('_current_kernel_version');
var _openwrt_mainline_version = document.getElementById('_openwrt_mainline_version');
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "state")%>', null, function(x, status) {
if ( x && x.status == 200 ) {
_current_firmware_version.innerHTML = status.current_firmware_version ? "<font color=green><%:Current Version%> [ "+status.current_firmware_version+" ] </font>" : "<font color=red>"+"<%:Invalid value.%>"+"</font>";
_current_plugin_version.innerHTML = status.current_plugin_version ? "<font color=green><%:Current Version%> [ "+status.current_plugin_version+" ] </font>" : "<font color=red>"+"<%:Invalid value.%>"+"</font>";
_current_kernel_version.innerHTML = status.current_kernel_version ? "<font color=green><%:Current Version%> [ "+status.current_kernel_version+" ] </font>" : "<font color=red>"+"<%:Invalid value.%>"+"</font>";
_openwrt_mainline_version.innerHTML = status.current_kernel_branch ? " [ "+status.current_kernel_branch+".y ] " : "[ "+"<%:Invalid value.%>"+" ]";
}
});
//]]></script>
@@ -0,0 +1,8 @@
<%+cbi/valueheader%>
<span style="color: red">
<%
local val = self:cfgvalue(section) or self.default or ""
write(pcdata(val))
%>
</span>
<%+cbi/valuefooter%>
@@ -0,0 +1,70 @@
<style>
.NewsTdHeight{ line-height:20px; }
</style>
<fieldset class="cbi-section">
<table width="100%" class="NewsTdHeight">
<tr><td colspan="2" width="100%" align="center">
<img id="logo_amlogic" src="<%=resource%>/amlogic/logo.png" alt="Logo" width="135" />
</td></tr>
<tr><td colspan="2" width="100%" align="center">
<img id="Packit" src="<%=resource%>/amlogic/packit.svg" alt="Packit" width="168px" height="20px" onclick="return homepage('packit')" />
&nbsp;&nbsp;
<img id="Author" src="<%=resource%>/amlogic/author.svg" alt="Author" width="168px" height="20px" onclick="return author_homepage('author')" />
&nbsp;&nbsp;
<img id="Plugin" src="<%=resource%>/amlogic/plugin.svg" alt="luci-app-amlogic" width="160px" height="20px" onclick="return homepage('plugin')" />
</td></tr>
<tr><td width="20%" align="right"><%:Supported functions:%></td><td width="80%" align="left" id="_clash">
<%:Provide services such as install to EMMC, Update Firmware and Kernel, Backup and Recovery Config, Snapshot management, etc.%>
</td></tr>
<tr><td width="20%" align="right"><%:Supported Boxes:%></td><td width="80%" align="left" id="_clash">
<%:Amlogic s922x --- [ Beelink, Beelink-Pro, Ugoos-AM6-Plus, ODROID-N2, Khadas-VIM3, Ali-CT2000 ]%><br>
<%:Amlogic s905x3 -- [ X96-Max+, HK1-Box, H96-Max-X3, Ugoos-X3, TX3, X96-Air, A95XF3-Air ]%><br>
<%:Amlogic s905x2 -- [ X96Max-4G, X96Max-2G, MECOOL-KM3-4G, Tanix-Tx5-Max, A95X-F2 ]%><br>
<%:Amlogic s912 ---- [ H96-Pro-Plus, Octopus-Planet, A1, A2, Z6-Plus, TX92, X92, TX8-MAX, TX9-Pro ]%><br>
<%:Amlogic s905x --- [ HG680P, B860H, TBee, T95, TX9, XiaoMI-3S, X96 ]%><br>
<%:Amlogic s905w --- [ X96-Mini, TX3-Mini, W95, X96W/FunTV, MXQ-Pro-4K ]%><br>
<%:Amlogic s905d --- [ Phicomm-N1, MECOOL-KI-Pro, SML-5442TW ]%><br>
<%:Amlogic s905l --- [ UNT402A, M201-S ]%><br>
<%:Amlogic s905l2 -- [ MGV2000, MGV3000, Wojia-TV-IPBS9505, M301A, E900v21E ]%><br>
<%:Amlogic s905l3 -- [ CM211-1, CM311-1, HG680-LC, M401A, UNT400G1, UNT402A, ZXV10-BV310 ]%><br>
<%:Amlogic s905l3a - [ E900V22C/D, CM311-1a-YST, M401A, M411A, UNT403A, UNT413A, IP112H ]%><br>
<%:Amlogic s905l3b - [ CM211-1, CM311-1, E900V22D, E900V21E, E900V22E, M302A/M304A ]%><br>
<%:Amlogic s905 ---- [ Beelink-Mini-MX-2G, Sunvell-T95M, MXQ-Pro+4K, SumaVision-Q5 ]%><br>
<%:Allwinner H6 ---- [ V-Plus Cloud ]%><br>
<%:Rockchip -------- [ BeikeYun, L1-Pro, FastRhino R66S/R68S, Radxa 5B/E25 ]%><br>
<%:Used in KVM ----- [ Can be used in KVM virtual machine of Armbian system. ]%>
</td></tr>
</table>
</fieldset>
<script type="text/javascript">//<![CDATA[
function winOpen(url)
{
var winOpen = window.open(url);
if( winOpen == null || typeof(winOpen) == 'undefined' ){ window.location.href=url; }
}
function homepage(website)
{
var url = "";
if( website == 'packit' ) { url = 'https://github.com/unifreq/openwrt_packit'; }
if( website == 'plugin' ) { url = 'https://github.com/ophub/luci-app-amlogic'; }
if ( url != "" ) { winOpen(url); }
}
function author_homepage(website)
{
var openwrt_author_repo = "";
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_openwrt_author")%>', null, function(x, status) {
if ( x && x.status == 200 ) {
let openwrt_author_repo = status.openwrt_author;
let trimstr_au = openwrt_author_repo.replace(/(^\s*)|(\s*$)/g, "");
if (trimstr_au.indexOf("https") == -1) {
trimstr_au = 'https://github.com/' + trimstr_au;
}
if ( trimstr_au != "" ) { winOpen(trimstr_au); }
}
});
}
//]]></script>
@@ -0,0 +1,128 @@
<style>
.NewsTdHeight{ line-height:20px; }
</style>
<fieldset class="cbi-section">
<table width="100%" class="NewsTdHeight">
<tr><td width="35%" align="right"><%:Select the device model:%></td>
<td width="65%" align="left">
<select name="amlogic_soc" id="amlogic_soc" style="width:auto" onchange="sel_dtb_input(this.options[this.selectedIndex].value)">
<option value="0"><%:Select List%></option>
<option value="99"><%:Enter the dtb file name%></option>
</select>
</td>
</tr>
<tr id="tr_sel_dtb" style="display:none;"><td width="30%" align="right"><%:Enter the dtb file name:%></td><td width="70%" align="left"><input class="cbi-input-file" style="width: 235px" type="text" id="amlogic_dtb" name="amlogic_dtb" /></td></tr>
<tr id="tr_sel_soc" style="display:none;"><td width="30%" align="right"><%:Enter the soc name:%></td><td width="70%" align="left"><input class="cbi-input-file" style="width: 235px" type="text" id="amlogic_socname" name="amlogic_socname" /></td></tr>
<tr id="tr_sel_uboot" style="display:none;"><td width="30%" align="right"><%:Enter the uboot_overload name:%></td><td width="70%" align="left"><input class="cbi-input-file" style="width: 235px" type="text" id="amlogic_uboot" name="amlogic_uboot" /></td></tr>
<tr>
<td width="30%" align="right"><%:Install OpenWrt:%></td>
<td width="70%" align="left">
<input type="button" class="cbi-button cbi-button-reload" value="<%:Install%>" onclick="return amlogic_install(this, '<%=self:cfgvalue(section)%>')"/> <span id="_check_install"></span>
</td>
</tr>
</table>
</fieldset>
<script type="text/javascript">//<![CDATA[
// Show custom dtb input box
function sel_dtb_input(soc_value){
if ( soc_value == "99" )
{
document.getElementById('tr_sel_dtb').style = '';
document.getElementById('tr_sel_soc').style = '';
document.getElementById('tr_sel_uboot').style = '';
}
else
{
document.getElementById('tr_sel_dtb').style = 'display:none;';
document.getElementById('tr_sel_soc').style = 'display:none;';
document.getElementById('tr_sel_uboot').style = 'display:none;';
}
}
// Show the status of the install button
function amlogic_install(btn,amlogic_install_sel)
{
var amlogic_soc_id = document.getElementById('amlogic_soc');
var amlogic_soc_index = amlogic_soc_id.selectedIndex;
var amlogic_soc_value = amlogic_soc_id.options[amlogic_soc_index].value;
var amlogic_soc_text = amlogic_soc_id.options[amlogic_soc_index].text;
var amlogic_dtb_id = document.getElementById('amlogic_dtb');
var amlogic_dtb_value = amlogic_dtb_id.value;
var amlogic_soc_name = document.getElementById('amlogic_socname');
var amlogic_socname_value = amlogic_socname.value;
var amlogic_ubootname = document.getElementById('amlogic_uboot');
var amlogic_ubootname_value = amlogic_ubootname.value;
var amlogic_confirm_info = amlogic_soc_text;
if (confirm('<%:You have chosen:%>' + amlogic_confirm_info + ', <%:Start install?%>') != true) { return false; }
btn.disabled = true;
btn.value = '<%:Installing...%> ';
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_amlogic_install")%>',
{
amlogic_install_sel: amlogic_soc_value + '@' + amlogic_dtb_value + ':' + amlogic_socname_value + ':' + amlogic_ubootname_value
},
function(x,status)
{
if ( x && x.status == 200 ) {
if(status.rule_install_status!="0")
{
btn.value = '<%:Install Failed%>';
}
else
{
btn.value = '<%:Successful Install%>';
}
}
else {
btn.value = '<%:Install%>';
}
}
);
btn.disabled = false;
return false;
}
// Read openwrt install log
var start_check_install = document.getElementById('_check_install');
XHR.poll(1, '<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_check_install")%>', status.start_check_install, function(x, status) {
if ( x && x.status == 200 ) {
if ( status.start_check_install != "\n" && status.start_check_install != "" ) {
start_check_install.innerHTML = '<font color="blue"> '+status.start_check_install+'</font>';
}
if ( status.start_check_install == "\n" || status.start_check_install == "" ) {
start_check_install.innerHTML = '';
}
}
});
// Show external modal database: /etc/model_database.txt
var mymodel_arrlen = 0;
var _option_codes = '<option value="0"><%:Select List%></option>';
var _check_my_amlogic_soc = document.getElementById('amlogic_soc');
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_model_database")%>', null, function(x, status) {
if ( x && x.status == 200 ) {
if ( status.my_model_database != "" ) {
let userModelList = status.my_model_database;
var user_arry = userModelList.split('@@@');
var mymodel_arrlen = user_arry.length - 1;
for ( j = 0; j < mymodel_arrlen; j++ ) {
my_box_mode = user_arry[j].split('###');
my_box_mode_id = my_box_mode[0];
my_box_mode_name = my_box_mode[1];
if ( my_box_mode_id != "" && my_box_mode_name != "" ) {
_option_codes = _option_codes + '<option value="' + my_box_mode_id + '">[ ' + my_box_mode_id + ' ] ' + my_box_mode_name.replace(/~/g, " ") + '</option>';
}
}
}
}
_option_codes = _option_codes + '<option value="99"><%:Enter the dtb file name%></option>';
_check_my_amlogic_soc.innerHTML = _option_codes;
});
//]]></script>
@@ -0,0 +1,48 @@
<style>
.NewsTdHeight{ line-height:32px; }
.imgLeft{ float:left; margin-right:10px; vertical-align:middle; }
.contentRight{ align-items: center; }
</style>
<fieldset class="cbi-section">
<table width="100%" class="NewsTdHeight">
<tr><td width="100%" align="left">
<input class="cbi-button cbi-button-save" type="button" value="<%:Switch System%>" onclick="switchopenwrt(this)" />
<p style="display:none">
<img id="img_loading" style="display:block" src="<%=resource%>/amlogic/loading.gif" alt="<%:Loading%>" class="imgLeft" />
<img id="img_switch" style="display:none" src="<%=resource%>/amlogic/switch.png" alt="<%:PowerOff%>" class="imgLeft" />
<span id="msg_switch" class="contentRight"><%:System is switching...%></span>
</p>
</td></tr>
</table>
</fieldset>
<script type="text/javascript">//<![CDATA[
function status_check() {
var time = 5;
var img_loading = document.getElementById("img_loading");
var img_switch = document.getElementById("img_switch");
var msg = document.getElementById("msg_switch");
var set = setInterval(function() {
time--;
msg.innerHTML = "<%:Waiting for system switching...%>";
if(time === 0) {
img_loading.style.display = 'none';
img_switch.style.display = 'block';
msg.innerHTML = "<%:System switchover succeeded, restarting...%>";
clearInterval(set);
}
}, 1000);
}
function switchopenwrt(btn) {
if (confirm('<%:Are you sure you want to switch systems?%>') != true) { return false; }
btn.style.display = 'none';
document.getElementById('msg_switch').parentNode.style.display = 'block';
(new XHR()).post('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_switch")%>', { token: '<%=token%>' }, status_check);
}
//]]></script>
@@ -0,0 +1,117 @@
<%+cbi/valueheader%>
<textarea id="amlogic.ophub.clog" class="cbi-input-textarea" style="width: 100%;display:inline" data-update="change" rows="8" cols="60" readonly="readonly" > </textarea>
<fieldset class="cbi-section">
<table width="100%">
<tr>
<td width="25%" align="center"><input type="button" class="cbi-button cbi-button-apply" id="stop_refresh_button" value="<%:Stop Refresh Log%>" onclick=" return stop_refresh() "/></td>
<td width="25%" align="center"><input type="button" class="cbi-button cbi-button-apply" id="start_refresh_button" value="<%:Start Refresh Log%>" onclick=" return start_refresh() "/></td>
<td width="25%" align="center"><input type="button" class="cbi-button cbi-button-apply" id="del_log_button" value="<%:Clean Log%>" style=" display:inline;" onclick=" return del_log() " /></td>
<td width="25%" align="center"><input type="button" class="cbi-button cbi-button-apply" id="down_log_button" value="<%:Download Log%>" style=" display:inline;" onclick=" return download_log() " /></td>
</tr>
</table>
</fieldset>
<script type="text/javascript">//<![CDATA[
var r
function stop_refresh() {
clearTimeout(r);
return
}
function start_refresh() {
clearTimeout(r);
r=setTimeout("poll_log()",1000*2);
return
}
function createAndDownloadFile(fileName, content) {
var aTag = document.createElement('a');
var blob = new Blob([content]);
aTag.download = fileName;
aTag.href = URL.createObjectURL(blob);
aTag.click();
URL.revokeObjectURL(blob);
}
function download_log(){
var lv = document.getElementById('amlogic.ophub.clog');
var dt = new Date();
var timestamp = dt.getFullYear()+"-"+(dt.getMonth()+1)+"-"+dt.getDate()+"-"+dt.getHours()+"-"+dt.getMinutes()+"-"+dt.getSeconds();
createAndDownloadFile("Amlogic-"+timestamp+".log",lv.innerHTML)
return
}
function del_log() {
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "del_log")%>',null,function(x, data){
var lv = document.getElementById('amlogic.ophub.clog');
lv.innerHTML="";
}
);
return
}
function p(s) {
return s < 10 ? '0' + s: s;
}
function line_tolocal(str){
var strt=new Array();
str.trim().split('\n').forEach(function(v, i) {
var dt = new Date(v.substring(6,26));
if (dt != "Invalid Date"){
strt[i]=dt.getFullYear()+"-"+p(dt.getMonth()+1)+"-"+p(dt.getDate())+" "+p(dt.getHours())+":"+p(dt.getMinutes())+":"+p(dt.getSeconds())+v.substring(27);
}else{
strt[i]=v;}})
var old_log_line = sessionStorage.log_line;
if ( old_log_line != null && strt.length != null ) {
if (old_log_line - strt.length < 0) {
sessionStorage.log_line = strt.length;
return strt.slice('-'+(strt.length-old_log_line))
}
else if (old_log_line == strt.length) {
sessionStorage.log_line = strt.length;
return
}
else if (old_log_line - strt.length > 0) {
sessionStorage.log_line = strt.length;
var lv = document.getElementById('amlogic.ophub.clog');
lv.innerHTML = "";
return strt
}
}
else if ( strt.length != null ) {
sessionStorage.log_line = strt.length;
return strt
}
else {
sessionStorage.log_line = "0";
return strt
}
}
function poll_log(){
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "refresh_log")%>', null,
function(x, data) {
if ( x && x.status == 200 ) {
var lv = document.getElementById('amlogic.ophub.clog');
if (x.responseText && lv) {
var lines=line_tolocal(x.responseText);
if (lines != null) {
lv.innerHTML = lines.reverse().join('\n')+'\n'+lv.innerHTML;
//lv.innerHTML = x.responseText.split('\n').reverse().join('\n')+lv.innerHTML;
}
}
}
}
);
r=setTimeout("poll_log()",1000*2);
}
sessionStorage.removeItem("log_line");
poll_log();
//]]>
</script>
<%+cbi/valuefooter%>
@@ -0,0 +1,48 @@
<style>
.NewsTdHeight{ line-height:32px; }
.imgLeft{ float:left; margin-right:10px; vertical-align:middle; }
.contentRight{ align-items: center; }
</style>
<fieldset class="cbi-section">
<table width="100%" class="NewsTdHeight">
<tr><td width="100%" align="left">
<input class="cbi-button cbi-button-remove" type="button" value="<%:Perform PowerOff%>" onclick="poweroff(this)" />
<p style="display:none">
<img id="img_loading" style="display:block" src="<%=resource%>/amlogic/loading.gif" alt="<%:Loading%>" class="imgLeft" />
<img id="img_poweroff" style="display:none" src="<%=resource%>/amlogic/poweroff.png" alt="<%:PowerOff%>" class="imgLeft" />
<span id="msg_poweroff" class="contentRight"><%:Device is shutting down...%></span>
</p>
</td></tr>
</table>
</fieldset>
<script type="text/javascript">//<![CDATA[
function status_check() {
var time = 5;
var img_loading = document.getElementById("img_loading");
var img_poweroff = document.getElementById("img_poweroff");
var msg = document.getElementById("msg_poweroff");
var set = setInterval(function() {
time--;
msg.innerHTML = "<%:Waiting for the device to shut down...%>";
if(time === 0) {
img_loading.style.display = 'none';
img_poweroff.style.display = 'block';
msg.innerHTML = "<%:The device has been turned off%>";
clearInterval(set);
}
}, 1000);
}
function poweroff(btn) {
if (confirm('<%:Are you sure you want to shut down?%>') != true) { return false; }
btn.style.display = 'none';
document.getElementById('msg_poweroff').parentNode.style.display = 'block';
(new XHR()).post('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_poweroff")%>', { token: '<%=token%>' }, status_check);
}
//]]></script>
@@ -0,0 +1,46 @@
<style>
.NewsTdHeight{ line-height: 20px; }
</style>
<fieldset class="cbi-section">
<table width="100%" class="NewsTdHeight">
<tr><td width="35%" align="right"><input type="button" class="cbi-button cbi-button-reload" value="<%:Rescue the original system kernel%>" onclick="return b_rescue_kernel(this)"/></td><td width="65%" align="left"><span id="_current_rescue_version"><%:Collecting data...%></span> <span id="_check_rescue"></span></td></tr>
</table>
</fieldset>
<script type="text/javascript">//<![CDATA[
function b_rescue_kernel(btn)
{
btn.disabled = true;
btn.value = '<%:Rescuing...%>';
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_amlogic_rescue")%>', null, function(x, status) {
if ( x && x.status == 200 ) {
btn.disabled = false;
btn.value = '<%:Rescue the original system kernel%>';
}
else {
btn.disabled = false;
btn.value = '<%:Rescue the original system kernel%>';
}
return false;
});
}
var _check_rescue = document.getElementById('_check_rescue');
XHR.poll(1, '<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_check_rescue")%>', status.start_check_rescue, function(x, status) {
if ( x && x.status == 200 ) {
if ( status.start_check_rescue != "\n" && status.start_check_rescue != "" ) {
_check_rescue.innerHTML = '<font color="blue"> '+status.start_check_rescue+'</font>';
}
if ( status.start_check_rescue == "\n" || status.start_check_rescue == "" ) {
_check_rescue.innerHTML = '';
}
}
});
var _current_rescue_version = document.getElementById('_current_rescue_version');
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "state")%>', null, function(x, status) {
if ( x && x.status == 200 ) {
_current_rescue_version.innerHTML = status.current_kernel_version ? "<font color=green><%:Current Version%> [ "+status.current_kernel_version+" ] </font>" : "<font color=red>"+"<%:Invalid value.%>"+"</font>";
}
});
//]]></script>
@@ -0,0 +1,152 @@
<style>
.NewsTdHeight{ line-height:20px; }
.SnapshotsTitHeight{ line-height:40px; text-align: center; }
.list{
display: flex;
flex-wrap: wrap;
justify-content: space-between;
text-align: center;
position: relative;
width: 100%;
background-color: #FFF;
}
.item{
border: 1px solid #CACACA;
color: #888;
font-size: 14px;
width: 150px;
height: 130px;
margin:8px;
text-align: center;
align-items:center;
}
.item:hover{background:#e5f3f6;}
.item:not(:nth-child(3n)){
content: "";
width: 150px;
}
.list:after {
content: "";
width: 150px;
}
</style>
<div class="list" id="_check_snapshot">
<%:Collecting data...%>
</div>
<script type="text/javascript">//<![CDATA[
// Delete snapshot function
function delete_snapshot(btn,snapshot_delete_sel)
{
if (confirm('<%:You selected a snapshot:%> [ ' + snapshot_delete_sel + ' ] , <%:Confirm delete?%>') != true) { return false; }
btn.disabled = true;
btn.value = '<%:Deleting...%> ';
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_snapshot_delete")%>',
{
snapshot_delete_sel: snapshot_delete_sel
},
function(x,status)
{
if ( x && x.status == 200 ) {
if(status.rule_delete_status!="0")
{
btn.value = '<%:Delete Failed%>';
}
else
{
btn.value = '<%:Successfully Deleted%>';
}
}
else {
btn.value = '<%:Delete Snapshot%>';
}
}
);
var sdiv = 'snapshots_div_' + snapshot_delete_sel;
document.getElementById(sdiv).style.display = 'none';
btn.disabled = false;
return false;
}
// Restore snapshot function
function restore_snapshot(btn,snapshot_restore_sel)
{
if (confirm('<%:You selected a snapshot:%> [ ' + snapshot_restore_sel + ' ] , <%:Confirm recovery and restart OpenWrt?%>') != true) { return false; }
btn.disabled = true;
btn.value = '<%:Restoring...%> ';
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_snapshot_restore")%>',
{
snapshot_restore_sel: snapshot_restore_sel
},
function(x,status)
{
if ( x && x.status == 200 ) {
if(status.rule_restore_status!="0")
{
btn.value = '<%:Restore Failed%>';
}
else
{
btn.value = '<%:Successfully Restored%>';
}
}
else {
btn.value = '<%:Restore Snapshot%>';
}
}
);
btn.disabled = false;
return false;
}
// Show current snapshot list
mycars_arrlen = 0;
_no_snapshots = "<%:Currently OpenWrt does not support the snapshot function.%>";
_no_snapshots = _no_snapshots + "<%:Please use this plugin to reinstall or upgrade OpenWrt to enable the snapshot function.%>";
var _check_snapshot = document.getElementById('_check_snapshot');
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_snapshot_list")%>', null, function(x, status) {
if ( x && x.status == 200 ) {
let userArer = status.current_snapshot;
let user_arer_clear = userArer.replace(/\.snapshots\//g, "");
let trimstr = user_arer_clear.replace(/(^\s*)|(\s*$)/g, "");
let user_arer = trimstr.replace(/\s+/g, ",");
var mycars = user_arer.split(',');
var mycars_arrlen = mycars.length;
_div_codes = ""
_snapshots_tit = ""
for ( j = 0; j < mycars_arrlen; j++ ) {
if ( mycars[j] == "etc-000" ) {
_snapshots_tit = "<%:Initialize Snapshot%>";
} else if ( mycars[j] == "etc-001" ) {
_snapshots_tit = "<%:Update Snapshot%>";
} else {
_snapshots_tit = mycars[j];
}
_div_codes = _div_codes + '<div class="item" id="snapshots_div_' + mycars[j] + '">';
_div_codes = _div_codes + '<div class="SnapshotsTitHeight">' + _snapshots_tit + '</div>'
_div_codes = _div_codes + '<div class="SnapshotsTitHeight"><input type="button" class="cbi-button cbi-button-apply" value="<%:Restore Snap%>" onclick="return restore_snapshot(this, \'' + mycars[j] + '\')"/></div>'
if ( mycars[j] != "etc-000" && mycars[j] != "etc-001" ) { _div_codes = _div_codes + '<div class="SnapshotsTitHeight"><input type="button" class="cbi-button cbi-button-remove" value="<%:Delete Snap%>" onclick="return delete_snapshot(this, \'' + mycars[j] + '\')"/></div>' }
_div_codes = _div_codes + '</div>';
}
_check_snapshot.innerHTML = _div_codes ? _div_codes : "<font color=red>"+"<%:Invalid value.%>"+"</font>";
} else {
_check_snapshot.innerHTML = "<font color=red>"+ _no_snapshots +"</font>";
}
});
//]]></script>
@@ -0,0 +1,130 @@
<style>
.NewsTdHeight{ line-height:20px; }
</style>
<fieldset class="cbi-section">
<table width="100%" class="NewsTdHeight">
<tr><td width="100%" colspan="2">
<p align="center">
<%:After uploading firmware (.img/.img.gz/.img.xz/.7z suffix) or kernel files (3 kernel files), the update button will be displayed.%>
</p>
</td></tr>
<tr><td width="30%" align="right">
<input id="_have_firmware" type="button" class="cbi-button cbi-button-reload" value="<%:Update OpenWrt firmware%>" onclick="return amlogic_update(this, 'auto@updated@/tmp')"/>
<input id="_have_kernel" type="button" class="cbi-button cbi-button-reload" value="<%:Replace OpenWrt Kernel%>" onclick="return amlogic_kernel(this)"/>
</td><td width="70%" align="left">
<span id="_current_firmware_version"><%:Collecting data...%></span> 
<span id="_check_log_firmware"></span><span id="_check_log_kernel"></span>
</td></tr>
</table>
</fieldset>
<script type="text/javascript">//<![CDATA[
function amlogic_update(btn,amlogic_update_sel)
{
btn.disabled = true;
btn.value = '<%:Updating...%> ';
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_amlogic_update")%>',
{
amlogic_update_sel: amlogic_update_sel
},
function(x,status)
{
if ( x && x.status == 200 ) {
if(status.rule_update_status!="0")
{
btn.value = '<%:Update Failed%>';
}
else
{
btn.value = '<%:Successful Update%>';
}
}
else {
btn.value = '<%:Update OpenWrt firmware%>';
}
}
);
btn.disabled = false;
return false;
}
function amlogic_kernel(btn)
{
btn.disabled = true;
btn.value = '<%:Updating...%> ';
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_amlogic_kernel")%>', null, function(x, status) {
if ( x && x.status == 200 ) {
if(status.rule_kernel_status!="0")
{
btn.value = '<%:Update Failed%>';
}
else
{
btn.value = '<%:Successful Update%>';
}
}
else {
btn.value = '<%:Replace OpenWrt Kernel%>';
}
}
);
btn.disabled = false;
return false;
}
var _have_firmware = document.getElementById('_have_firmware');
var _have_kernel = document.getElementById('_have_kernel');
XHR.poll(1, '<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_check_upfiles")%>', status.start_check_upfiles, function(x, status) {
if ( x && x.status == 200 ) {
if ( status.start_check_upfiles == "firmware\n" || status.start_check_upfiles == "firmware" ) {
_have_firmware.style.display = 'block';
} else {
_have_firmware.style.display = 'none';
}
if ( status.start_check_upfiles == "kernel\n" || status.start_check_upfiles == "kernel" ) {
_have_kernel.style.display = 'block';
} else {
_have_kernel.style.display = 'none';
}
}
});
var _check_log_firmware = document.getElementById('_check_log_firmware');
XHR.poll(1, '<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_check_firmware")%>', status.start_check_firmware, function(x, status) {
if ( x && x.status == 200 ) {
if ( status.start_check_firmware != "\n" && status.start_check_firmware != "" ) {
_check_log_firmware.innerHTML = '<font color="blue"> '+status.start_check_firmware+'</font>';
}
if ( status.start_check_firmware == "\n" || status.start_check_firmware == "" ) {
_check_log_firmware.innerHTML = '';
}
}
});
var _check_log_kernel = document.getElementById('_check_log_kernel');
XHR.poll(1, '<%=luci.dispatcher.build_url("admin", "system", "amlogic", "start_check_kernel")%>', status.start_check_kernel, function(x, status) {
if ( x && x.status == 200 ) {
if ( status.start_check_kernel != "\n" && status.start_check_kernel != "" ) {
_check_log_kernel.innerHTML = '<font color="blue"> '+status.start_check_kernel+'</font>';
}
if ( status.start_check_kernel == "\n" || status.start_check_kernel == "" ) {
_check_log_kernel.innerHTML = '';
}
}
});
var _current_firmware_version = document.getElementById('_current_firmware_version');
//var _current_kernel_version = document.getElementById('_current_kernel_version');
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "amlogic", "state")%>', null, function(x, status) {
if ( x && x.status == 200 ) {
_current_firmware_version.innerHTML = status.current_firmware_version ? "<font color=green><%:Current Version%> [ "+status.current_firmware_version+" ] </font>" : "<font color=red>"+"<%:Invalid value.%>"+"</font>";
//_current_kernel_version.innerHTML = status.current_kernel_version ? "<font color=green><%:Current Version%> [ "+status.current_kernel_version+" ] </font>" : "<font color=red>"+"<%:Invalid value.%>"+"</font>";
}
});
//]]></script>
@@ -0,0 +1,5 @@
<%+cbi/valueheader%>
<label class="cbi-value" style="display:inline-block; width: 150px" for="ulfile"><%:Choose local file:%></label>
<input class="cbi-input-file" style="width: 400px" type="file" id="ulfile" name="ulfile" />
<input type="submit" class="cbi-button cbi-input-apply" name="upload" value="<%:Upload%>" />
<%+cbi/valuefooter%>
+588
View File
@@ -0,0 +1,588 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: https://github.com/ophub/luci-app-amlogic\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ru_RU\n"
"X-Generator: Poedit 2.3.1\n"
msgid "Choose local file:"
msgstr "Выберите локальный файл:"
msgid "Couldn't open file:"
msgstr "Не удалось открыть файл:"
msgid "The file Will download automatically."
msgstr "Файл будет загружен автоматически."
msgid "Create upload file error."
msgstr "Ошибка создания загружаемого файла."
msgid "Download"
msgstr "Скачать"
msgid "Download file"
msgstr "Скачать файл"
msgid "File name"
msgstr "Имя файла"
msgid "File saved to"
msgstr "Файл сохранён в"
msgid "FileTransfer"
msgstr "Передача файлов"
msgid "Install"
msgstr "Установить"
msgid "Attributes"
msgstr "Атрибуты"
msgid "Modify time"
msgstr "Время изменения"
msgid "No specify upload file."
msgstr "Не указан файл для загрузки."
msgid "Path on Route:"
msgstr "Путь на маршрутизаторе:"
msgid "Remove"
msgstr "Удалить"
msgid "Size"
msgstr "Размер"
msgid "Upload"
msgstr "Загрузить"
msgid "Upload file list"
msgstr "Список загруженных файлов"
msgid "There are config file in the upload directory, and you can restore the config. "
msgstr "В каталоге загрузки есть файл конфигурации — вы можете восстановить настройки."
msgid "There are kernel files in the upload directory, and you can replace the kernel."
msgstr "В каталоге загрузки находятся файлы ядра — вы можете заменить ядро."
msgid "There are openwrt firmware file in the upload directory, and you can update the openwrt."
msgstr "В каталоге загрузки есть файл прошивки OpenWrt — вы можете обновить OpenWrt."
msgid "Update plugins first, then update the kernel or firmware."
msgstr "Сначала обновите плагины, затем ядро или прошивку."
msgid "After uploading [Firmware], [Kernel], [IPK] or [Backup Config], the operation buttons will be displayed."
msgstr "После загрузки [прошивки], [ядра], [IPK-пакета] или [резервной конфигурации] появятся соответствующие кнопки управления."
msgid "After uploading firmware (.img/.img.gz/.img.xz/.7z suffix) or kernel files (3 kernel files), the update button will be displayed."
msgstr "После загрузки файлов прошивки (с расширениями .img/.img.gz/.img.xz/.7z) или файлов ядра (3 файла), появится кнопка обновления."
msgid "Amlogic Service"
msgstr "Сервис Amlogic"
msgid "Restore Config / Replace OpenWrt Kernel"
msgstr "Восстановить конфигурацию / Заменить ядро OpenWrt"
msgid "Manually Upload Update"
msgstr "Обновление вручную"
msgid "Install OpenWrt"
msgstr "Установить OpenWrt"
msgid "Select the device model:"
msgstr "Выберите модель устройства:"
msgid "Select List"
msgstr "Выбрать из списка"
msgid "Enter the dtb file name"
msgstr "Введите имя файла DTB"
msgid "Enter the soc name:"
msgstr "Введите имя SoC:"
msgid "Enter the uboot_overload name:"
msgstr "Введите имя uboot_overload:"
msgid "Invalid value."
msgstr "Недопустимое значение."
msgid "Install OpenWrt:"
msgstr "Установка OpenWrt:"
msgid "Install OpenWrt to EMMC, Please select the device model, Or enter the dtb file name."
msgstr "Установка OpenWrt на eMMC. Пожалуйста, выберите модель устройства или введите имя файла DTB."
msgid "Tip: Writing is in progress, and it will automatically restart after completion."
msgstr "Подсказка: идёт запись — после завершения устройство автоматически перезагрузится."
msgid "You have chosen:"
msgstr "Вы выбрали:"
msgid "Start install?"
msgstr "Начать установку?"
msgid "Installing..."
msgstr "Установка..."
msgid "Install Failed"
msgstr "Установка не удалась"
msgid "Successful Install"
msgstr "Установка завершена успешно"
msgid "Update"
msgstr "Обновить"
msgid "Updating..."
msgstr "Обновление..."
msgid "Update Failed"
msgstr "Обновление не удалось"
msgid "Successful Update"
msgstr "Обновление завершено успешно"
msgid "Update OpenWrt firmware"
msgstr "Обновить прошивку OpenWrt"
msgid "kernel"
msgstr "ядро"
msgid "Replace OpenWrt Kernel"
msgstr "Заменить ядро OpenWrt"
msgid "Tip: The kernel is being replaced, and it will automatically restart after completion."
msgstr "Подсказка: идёт замена ядра — после завершения устройство автоматически перезагрузится."
msgid "Supports management of Amlogic s9xxx, Allwinner (V-Plus Cloud), and Rockchip (BeikeYun, Chainedbox L1 Pro) boxes."
msgstr "Поддерживает управление устройствами на базе Amlogic s9xxx, Allwinner (V-Plus Cloud) и Rockchip (BeikeYun, Chainedbox L1 Pro)."
msgid "Supported functions:"
msgstr "Поддерживаемые функции:"
msgid "Provide services such as install to EMMC, Update Firmware and Kernel, Backup and Recovery Config, Snapshot management, etc."
msgstr "Позволяет устанавливать OpenWrt на eMMC, обновлять прошивку и ядро, выполнять резервное копирование и восстановление конфигурации, а также управлять снапшотами (мгновенными снимками системы)."
msgid "Supported Boxes:"
msgstr "Поддерживаемые устройства:"
msgid "Amlogic s922x --- [ Beelink, Beelink-Pro, Ugoos-AM6-Plus, ODROID-N2, Khadas-VIM3, Ali-CT2000 ]"
msgstr "Amlogic s922x — [Beelink, Beelink-Pro, Ugoos-AM6-Plus, ODROID-N2, Khadas-VIM3, Ali-CT2000]"
msgid "Amlogic s905x3 -- [ X96-Max+, HK1-Box, H96-Max-X3, Ugoos-X3, TX3, X96-Air, A95XF3-Air ]"
msgstr "Amlogic s905x3 — [X96-Max+, HK1-Box, H96-Max-X3, Ugoos-X3, TX3, X96-Air, A95XF3-Air]"
msgid "Amlogic s905x2 -- [ X96Max-4G, X96Max-2G, MECOOL-KM3-4G, Tanix-Tx5-Max, A95X-F2 ]"
msgstr "Amlogic s905x2 — [X96Max-4G, X96Max-2G, MECOOL-KM3-4G, Tanix-Tx5-Max, A95X-F2]"
msgid "Amlogic s912 ---- [ H96-Pro-Plus, Octopus-Planet, A1, A2, Z6-Plus, TX92, X92, TX8-MAX, TX9-Pro ]"
msgstr "Amlogic s912 — [H96-Pro-Plus, Octopus-Planet, A1, A2, Z6-Plus, TX92, X92, TX8-MAX, TX9-Pro]"
msgid "Amlogic s905x --- [ HG680P, B860H, TBee, T95, TX9, XiaoMI-3S, X96 ]"
msgstr "Amlogic s905x — [HG680P, B860H, TBee, T95, TX9, XiaoMI-3S, X96]"
msgid "Amlogic s905w --- [ X96-Mini, TX3-Mini, W95, X96W/FunTV, MXQ-Pro-4K ]"
msgstr "Amlogic s905w — [X96-Mini, TX3-Mini, W95, X96W/FunTV, MXQ-Pro-4K]"
msgid "Amlogic s905d --- [ Phicomm-N1, MECOOL-KI-Pro, SML-5442TW ]"
msgstr "Amlogic s905d — [Phicomm-N1, MECOOL-KI-Pro, SML-5442TW]"
msgid "Amlogic s905l --- [ UNT402A, M201-S ]"
msgstr "Amlogic s905l — [UNT402A, M201-S]"
msgid "Amlogic s905l2 -- [ MGV2000, MGV3000, Wojia-TV-IPBS9505, M301A, E900v21E ]"
msgstr "Amlogic s905l2 — [MGV2000, MGV3000, Wojia-TV-IPBS9505, M301A, E900v21E]"
msgid "Amlogic s905l3 -- [ CM211-1, CM311-1, HG680-LC, M401A, UNT400G1, UNT402A, ZXV10-BV310 ]"
msgstr "Amlogic s905l3 — [CM211-1, CM311-1, HG680-LC, M401A, UNT400G1, UNT402A, ZXV10-BV310]"
msgid "Amlogic s905l3a - [ E900V22C/D, CM311-1a-YST, M401A, M411A, UNT403A, UNT413A, IP112H ]"
msgstr "Amlogic s905l3a — [E900V22C/D, CM311-1a-YST, M401A, M411A, UNT403A, UNT413A, IP112H]"
msgid "Amlogic s905l3b - [ CM211-1, CM311-1, E900V22D, E900V21E, E900V22E, M302A/M304A ]"
msgstr "Amlogic s905l3b — [CM211-1, CM311-1, E900V22D, E900V21E, E900V22E, M302A/M304A]"
msgid "Amlogic s905 ---- [ Beelink-Mini-MX-2G, Sunvell-T95M, MXQ-Pro+4K, SumaVision-Q5 ]"
msgstr "Amlogic s905 — [Beelink-Mini-MX-2G, Sunvell-T95M, MXQ-Pro+4K, SumaVision-Q5]"
msgid "Allwinner H6 ---- [ V-Plus Cloud ]"
msgstr "Allwinner H6 — [V-Plus Cloud]"
msgid "Rockchip -------- [ BeikeYun, L1-Pro, FastRhino R66S/R68S, Radxa 5B/E25 ]"
msgstr "Rockchip — [BeikeYun, L1-Pro, FastRhino R66S/R68S, Radxa 5B/E25]"
msgid "Used in KVM ----- [ Can be used in KVM virtual machine of Armbian system. ]"
msgstr "Используется в KVM — [можно использовать в виртуальной машине KVM на базе Armbian]."
msgid "KVM dual system switching"
msgstr "Переключение между двумя системами в KVM"
msgid "You can freely switch between KVM dual partitions, using OpenWrt systems in different partitions."
msgstr "Вы можете свободно переключаться между двумя разделами KVM, используя OpenWrt из разных разделов."
msgid "Switch System"
msgstr "Переключить систему"
msgid "System is switching..."
msgstr "Переключение системы..."
msgid "Waiting for system switching..."
msgstr "Ожидание завершения переключения..."
msgid "System switchover succeeded, restarting..."
msgstr "Переключение успешно, перезагрузка..."
msgid "Are you sure you want to switch systems?"
msgstr "Вы уверены, что хотите переключить систему?"
msgid "Install Ipk"
msgstr "Установить IPK"
msgid "Plugin Settings"
msgstr "Настройки плагина"
msgid "Backup Firmware Config"
msgstr "Резервное копирование конфигурации"
msgid "Backup Config:"
msgstr "Резервная копия конфигурации:"
msgid "Download Backup"
msgstr "Скачать резервную копию"
msgid "Backup OpenWrt config (openwrt_config.tar.gz). Use this file to restore the config in [Manually Upload Update]."
msgstr "Создать резервную копию конфигурации OpenWrt (openwrt_config.tar.gz). Используйте этот файл для восстановления в разделе [Обновление вручную]."
msgid "Edit List:"
msgstr "Редактировать список:"
msgid "Open List"
msgstr "Открыть список"
msgid "Backup Configuration - Custom List"
msgstr "Резервная копия — пользовательский список"
msgid "Write one configuration item per line, and directories should end with a /."
msgstr "По одному элементу на строку. Имена каталогов должны оканчиваться на «/»."
msgid "Restore Backup:"
msgstr "Восстановить из резервной копии:"
msgid "Upload Backup"
msgstr "Загрузить резервную копию"
msgid "Restore"
msgstr "Восстановить"
msgid "Restore Config"
msgstr "Восстановить конфигурацию"
msgid "Restore configuration"
msgstr "Восстановление конфигурации"
msgid "Config File"
msgstr "Файл конфигурации"
msgid "Tip: The config is being restored, and it will automatically restart after completion."
msgstr "Подсказка: идёт восстановление конфигурации — после завершения устройство автоматически перезагрузится."
msgid "Snapshot Management"
msgstr "Управление снапшотами"
msgid "Create Snapshot"
msgstr "Создать снапшот"
msgid "Creating..."
msgstr "Создание..."
msgid "Created successfully"
msgstr "Создано успешно"
msgid "Creation failed"
msgstr "Ошибка создания"
msgid "Initialize Snapshot"
msgstr "Инициализировать снапшот"
msgid "Update Snapshot"
msgstr "Обновить снапшот"
msgid "Restore Snap"
msgstr "Восстановить снапшот"
msgid "Restoring..."
msgstr "Восстановление..."
msgid "Restore Failed"
msgstr "Восстановление не удалось"
msgid "Successfully Restored"
msgstr "Восстановлено успешно"
msgid "Delete Snap"
msgstr "Удалить снапшот"
msgid "You selected a snapshot:"
msgstr "Вы выбрали снапшот:"
msgid "Confirm delete?"
msgstr "Подтвердить удаление?"
msgid "Confirm recovery and restart OpenWrt?"
msgstr "Подтвердить восстановление и перезагрузку OpenWrt?"
msgid "Delete Failed"
msgstr "Удаление не удалось"
msgid "Successfully Deleted"
msgstr "Удалено успешно"
msgid "Create a snapshot of the current system configuration, or restore to a snapshot."
msgstr "Создать снапшот текущей конфигурации системы или восстановиться из снапшота."
msgid "Currently OpenWrt does not support the snapshot function."
msgstr "В текущей версии OpenWrt функция снапшотов не поддерживается."
msgid "Please use this plugin to reinstall or upgrade OpenWrt to enable the snapshot function."
msgstr "Пожалуйста, используйте этот плагин для переустановки или обновления OpenWrt, чтобы включить поддержку снапшотов."
msgid "Deleting..."
msgstr "Удаление..."
msgid "Online Download Update"
msgstr "Обновление через интернет"
msgid "Config Source"
msgstr "Источник конфигурации"
msgid "You can customize the github.com download repository of OpenWrt files and kernels in [Online Download Update]."
msgstr "Вы можете настроить репозиторий на github.com для загрузки файлов OpenWrt и ядер в разделе [Обновление через интернет]."
msgid "Tip: The same files as the current OpenWrt system's BOARD (such as rock5b) and kernel (such as 5.10) will be downloaded."
msgstr "Подсказка: будут загружены файлы, соответствующие текущей платформе (например, rock5b) и версии ядра (например, 5.10)."
msgid "OpenWrt download repository:"
msgstr "Репозиторий OpenWrt:"
msgid "Set the OpenWrt files download repository on github.com in [Online Download Update]."
msgstr "Укажите репозиторий на github.com для загрузки файлов OpenWrt в разделе [Обновление через интернет]."
msgid "OpenWrt download tags keyword:"
msgstr "Ключевое слово тега OpenWrt:"
msgid "Set the OpenWrt files download tags keyword for github.com in [Online Download Update]."
msgstr "Укажите ключевое слово тега для загрузки файлов OpenWrt на github.com в разделе [Обновление через интернет]."
msgid "OpenWrt files suffix:"
msgstr "Расширение файлов OpenWrt:"
msgid "Set the OpenWrt files download suffix for github.com in [Online Download Update]."
msgstr "Укажите расширение файлов OpenWrt, загружаемых с github.com, в разделе [Обновление через интернет]."
msgid "Kernel download repository:"
msgstr "Репозиторий ядра:"
msgid "Set the kernel files download repository on github.com in [Online Download Update]."
msgstr "Укажите репозиторий на github.com для загрузки файлов ядра в разделе [Обновление через интернет]."
msgid "Kernel download tags:"
msgstr "Теги ядра:"
msgid "Set the kernel files download tags on github.com in [Online Download Update]."
msgstr "Укажите теги для загрузки файлов ядра на github.com в разделе [Обновление через интернет]."
msgid "kernel_rk3588 [Rockchip RK3588 Kernel]"
msgstr "kernel_rk3588 [Ядро для Rockchip RK3588]"
msgid "kernel_rk35xx [Rockchip RK35xx Kernel]"
msgstr "kernel_rk35xx [Ядро для Rockchip RK35xx]"
msgid "kernel_stable [Mainline Stable Kernel]"
msgstr "kernel_stable [Стабильное ядро из mainline]"
msgid "kernel_flippy [Mainline Stable Kernel by Flippy]"
msgstr "kernel_flippy [Стабильное ядро от Flippy]"
msgid "kernel_h6 [Allwinner H6 Kernel]"
msgstr "kernel_h6 [Ядро для Allwinner H6]"
msgid "kernel_beta [Beta Kernel]"
msgstr "kernel_beta [Бета-версия ядра]"
msgid "Set version branch:"
msgstr "Ветка версии:"
msgid "Set the version branch of the OpenWrt files and kernel selected in [Online Download Update]."
msgstr "Укажите ветку версии для файлов OpenWrt и ядра в разделе [Обновление через интернет]."
msgid "Keep config update:"
msgstr "Сохранять конфигурацию при обновлении:"
msgid "Set whether to keep the current config during [Online Download Update] and [Manually Upload Update]."
msgstr "Выберите, сохранять ли текущую конфигурацию при обновлении через интернет или вручную."
msgid "Auto write bootloader:"
msgstr "Автоматически записывать bootloader:"
msgid "[Recommended choice] Set whether to auto write bootloader during install and update OpenWrt."
msgstr "[Рекомендуется] Указывает, записывать ли автоматически bootloader при установке или обновлении OpenWrt."
msgid "Set the file system type:"
msgstr "Тип файловой системы:"
msgid "[Default ext4] Set the file system type of the shared partition (/mnt/mmcblk*p4) when install OpenWrt."
msgstr "[По умолчанию ext4] Укажите тип файловой системы для общего раздела (/mnt/mmcblk*p4) при установке OpenWrt."
msgid "Save Config:"
msgstr "Сохранить конфигурацию:"
msgid "Save"
msgstr "Сохранить"
msgid "Check All Components Update"
msgstr "Проверка обновлений"
msgid "Provide OpenWrt Firmware, Kernel and Plugin online check, download and update service."
msgstr "Предоставляет онлайн-проверку, загрузку и обновление прошивки OpenWrt, ядра и плагинов."
msgid "Only update Amlogic Service"
msgstr "Обновить только сервис Amlogic"
msgid "Update system kernel only"
msgstr "Обновить только ядро системы"
msgid "Complete system update"
msgstr "Полное обновление системы"
msgid "Check Update"
msgstr "Проверить обновления"
msgid "Checking..."
msgstr "Проверка..."
msgid "Current Version"
msgstr "Текущая версия"
msgid "Latest Version"
msgstr "Последняя версия"
msgid "Rescue Kernel"
msgstr "Аварийное восстановление ядра"
msgid "When a kernel update fails and causes the OpenWrt system to be unbootable, the kernel can be restored by mutual recovery from eMMC/NVMe/sdX."
msgstr "Если обновление ядра привело к невозможности загрузки OpenWrt, его можно восстановить с другого носителя (eMMC/NVMe/sdX)."
msgid "Rescue the original system kernel"
msgstr "Восстановить исходное ядро системы"
msgid "Rescuing..."
msgstr "Восстановление..."
msgid "Current Device:"
msgstr "Текущее устройство:"
msgid "Display the PLATFORM classification of the device."
msgstr "Отображает класс PLATFORM устройства."
msgid "Update plugins first, then update the kernel or firmware. More options can be configured in [Plugin Settings]."
msgstr "Сначала обновите плагины, затем ядро или прошивку. Дополнительные настройки доступны в [Настройках плагина]."
msgid "Collecting data..."
msgstr "Сбор данных..."
msgid "Server Logs"
msgstr "Журнал операций"
msgid "Display the execution log of the current operation."
msgstr "Отображает журнал выполнения текущей операции."
msgid "Stop Refresh Log"
msgstr "Остановить обновление журнала"
msgid "Start Refresh Log"
msgstr "Начать обновление журнала"
msgid "Clean Log"
msgstr "Очистить журнал"
msgid "Download Log"
msgstr "Скачать журнал"
msgid "CPU Settings"
msgstr "Настройки CPU"
msgid "CPU Freq"
msgstr "Частота CPU"
msgid "CPU Freq Settings"
msgstr "Настройки частоты CPU"
msgid "Set CPU Scaling Governor to Max Performance or Balance Mode"
msgstr "Выберите режим управления частотой CPU: максимальная производительность или баланс."
msgid "CPU Scaling Governor:"
msgstr "Режим управления частотой:"
msgid "ondemand"
msgstr "Ondemand — автоматический баланс"
msgid "performance"
msgstr "Performance — максимальная производительность"
msgid "schedutil"
msgstr "Schedutil — умный планировщик"
msgid "CPU Freq from 48000 to 716000 (Khz)"
msgstr "Диапазон частоты CPU: от 48000 до 716000 КГц"
msgid "Min Freq:"
msgstr "Мин. частота:"
msgid "Max Freq:"
msgstr "Макс. частота:"
msgid "CPU Switching Threshold:"
msgstr "Порог переключения частоты CPU:"
msgid "Kernel make a decision on whether it should increase the frequency (%)"
msgstr "При загрузке CPU выше указанного процента (%), ядро увеличит частоту."
msgid "CPU Switching Sampling rate:"
msgstr "Период проверки частоты CPU:"
msgid "The sampling rate determines how frequently the governor checks to tune the CPU (ms)"
msgstr "Частота проверки загрузки CPU (мс). Примечание: слишком частое переключение может вызвать дрожание задержек в сети."
msgid "Microarchitectures:"
msgstr "Микроархитектура:"
msgid "Loading"
msgstr "Загрузка"
msgid "PowerOff"
msgstr "Выключить"
msgid "Shut down your router device."
msgstr "Выключить устройство маршрутизатора."
msgid "Perform PowerOff"
msgstr "Выполнить выключение"
msgid "Are you sure you want to shut down?"
msgstr "Вы уверены, что хотите выключить устройство?"
msgid "Device is shutting down..."
msgstr "Устройство выключается..."
msgid "Waiting for the device to shut down..."
msgstr "Ожидание завершения выключения..."
msgid "The device has been turned off"
msgstr "Устройство выключено"
+593
View File
@@ -0,0 +1,593 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: https://github.com/ophub/luci-app-amlogic \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: zh_CN\n"
"X-Generator: Poedit 2.3.1\n"
msgid "Choose local file:"
msgstr "选择本地文件:"
msgid "Couldn't open file:"
msgstr "无法打开文件:"
msgid "The file Will download automatically."
msgstr "文件将自动下载"
msgid "Create upload file error."
msgstr "创建上传文件失败。"
msgid "Download"
msgstr "下载"
msgid "Download file"
msgstr "下载文件"
msgid "File name"
msgstr "文件名"
msgid "File saved to"
msgstr "文件保存到"
msgid "FileTransfer"
msgstr "文件传输"
msgid "Install"
msgstr "安装"
msgid "Attributes"
msgstr "属性"
msgid "Modify time"
msgstr "修改时间"
msgid "No specify upload file."
msgstr "未指定上传文件。"
msgid "Path on Route:"
msgstr "路由根目录:"
msgid "Remove"
msgstr "移除"
msgid "Size"
msgstr "大小"
msgid "Upload"
msgstr "上传"
msgid "Upload file list"
msgstr "上传文件列表"
msgid "There are config file in the upload directory, and you can restore the config. "
msgstr "上传文件列表中有配置文件,你可以恢复配置。"
msgid "There are kernel files in the upload directory, and you can replace the kernel."
msgstr "上传文件列表中有内核文件,你可以升级内核。"
msgid "There are openwrt firmware file in the upload directory, and you can update the openwrt."
msgstr "上传文件列表中有 OpenWrt 固件文件,你可以升级 OpenWrt。"
msgid "Update plugins first, then update the kernel or firmware."
msgstr "首先更新插件,再更新内核或固件。"
msgid "After uploading [Firmware], [Kernel], [IPK] or [Backup Config], the operation buttons will be displayed."
msgstr "当上传 [固件文件],[内核文件],[IPK文件],[配置文件] 后,将自动显示相关操作按钮。"
msgid "After uploading firmware (.img/.img.gz/.img.xz/.7z suffix) or kernel files (3 kernel files), the update button will be displayed."
msgstr "当上传文件列表中有 OpenWrt 固件(.img/.img.gz/.img.xz/.7z 后缀)或内核文件(3个内核文件)时,将自动显示相关操作按钮。"
msgid "Amlogic Service"
msgstr "晶晨宝盒"
msgid "Restore Config / Replace OpenWrt Kernel"
msgstr "恢复配置 / 升级 OpenWrt 内核"
msgid "Manually Upload Update"
msgstr "手动上传更新"
msgid "Install OpenWrt"
msgstr "安装 OpenWrt"
msgid "Select the device model:"
msgstr "选择设备型号:"
msgid "Select List"
msgstr "选择列表"
msgid "Enter the dtb file name"
msgstr "输入自定义 dtb 文件名"
msgid "Enter the soc name:"
msgstr "输入自定义 soc 名称:"
msgid "Enter the uboot_overload name:"
msgstr "输入自定义 uboot_overload 名称:"
msgid "Invalid value."
msgstr "无效值"
msgid "Install OpenWrt:"
msgstr "安装 OpenWrt:"
msgid "Install OpenWrt to EMMC, Please select the device model, Or enter the dtb file name."
msgstr "将 OpenWrt 安装到 EMMC,请选择设备型号,或输入 dtb 文件名。"
msgid "Tip: Writing is in progress, and it will automatically restart after completion."
msgstr "提示:正在写入,完成后将自动重启。"
msgid "You have chosen:"
msgstr "你选择了:"
msgid "Start install?"
msgstr "开始安装吗?"
msgid "Installing..."
msgstr "正在安装..."
msgid "Install Failed"
msgstr "安装失败"
msgid "Successful Install"
msgstr "安装成功"
msgid "Update"
msgstr "升级"
msgid "Updating..."
msgstr "正在更新..."
msgid "Update Failed"
msgstr "更新失败"
msgid "Successful Update"
msgstr "更新成功"
msgid "Update OpenWrt firmware"
msgstr "升级 OpenWrt 固件"
msgid "kernel"
msgstr "内核"
msgid "Replace OpenWrt Kernel"
msgstr "更换 OpenWrt 内核"
msgid "Tip: The kernel is being replaced, and it will automatically restart after completion."
msgstr "提示:正在替换内核,完成后将自动重启。"
msgid "Supports management of Amlogic s9xxx, Allwinner (V-Plus Cloud), and Rockchip (BeikeYun, Chainedbox L1 Pro) boxes."
msgstr "支持对晶晨 s9xxx 系列(斐讯N1、HK1等),全志(微加云),以及瑞芯微(贝壳云、我家云)的盒子进行在线管理。"
msgid "Supported functions:"
msgstr "支持的功能:"
msgid "Provide services such as install to EMMC, Update Firmware and Kernel, Backup and Recovery Config, Snapshot management, etc."
msgstr "支持将 OpenWrt 系统写入 EMMC、升级固件与内核,备份与恢复自定义配置,快照管理等功能。"
msgid "Supported Boxes:"
msgstr "支持的盒子:"
msgid "Amlogic s922x --- [ Beelink, Beelink-Pro, Ugoos-AM6-Plus, ODROID-N2, Khadas-VIM3, Ali-CT2000 ]"
msgstr "晶晨 s922x --- [ Beelink, Beelink-Pro, Ugoos-AM6-Plus, ODROID-N2, Khadas-VIM3, Ali-CT2000 ]"
msgid "Amlogic s905x3 -- [ X96-Max+, HK1-Box, H96-Max-X3, Ugoos-X3, TX3, X96-Air, A95XF3-Air ]"
msgstr "晶晨 s905x3 -- [ X96-Max+, HK1-Box, H96-Max-X3, Ugoos-X3, TX3, X96-Air, A95XF3-Air ]"
msgid "Amlogic s905x2 -- [ X96Max-4G, X96Max-2G, MECOOL-KM3-4G, Tanix-Tx5-Max, A95X-F2 ]"
msgstr "晶晨 s905x2 -- [ X96Max-4G, X96Max-2G, MECOOL-KM3-4G, Tanix-Tx5-Max, A95X-F2 ]"
msgid "Amlogic s912 ---- [ H96-Pro-Plus, Octopus-Planet, A1, A2, Z6-Plus, TX92, X92, TX8-MAX, TX9-Pro ]"
msgstr "晶晨 s912 ---- [ H96-Pro-Plus, 章鱼星球, A1, A2, Z6-Plus, TX92, X92, TX8-MAX, TX9-Pro ]"
msgid "Amlogic s905x --- [ HG680P, B860H, TBee, T95, TX9, XiaoMI-3S, X96 ]"
msgstr "晶晨 s905x --- [ 烽火HG680, 中兴B860H, TBee, T95, TX9, XiaoMI-3S, X96 ]"
msgid "Amlogic s905w --- [ X96-Mini, TX3-Mini, W95, X96W/FunTV, MXQ-Pro-4K ]"
msgstr "晶晨 s905w --- [ X96-Mini, TX3-Mini, W95, X96W/FunTV, MXQ-Pro-4K ]"
msgid "Amlogic s905d --- [ Phicomm-N1, MECOOL-KI-Pro, SML-5442TW ]"
msgstr "晶晨 s905d --- [ 斐讯-N1, MECOOL-KI-Pro, SML-5442TW ]"
msgid "Amlogic s905l --- [ UNT402A, M201-S ]"
msgstr "晶晨 s905l --- [ UNT402A, M201-S ]"
msgid "Amlogic s905l2 -- [ MGV2000, MGV3000, Wojia-TV-IPBS9505, M301A, E900v21E ]"
msgstr "晶晨 s905l2 -- [ MGV2000, MGV3000, Wojia-TV-IPBS9505, M301A, E900v21E ]"
msgid "Amlogic s905l3 -- [ CM211-1, CM311-1, HG680-LC, M401A, UNT400G1, UNT402A, ZXV10-BV310 ]"
msgstr "晶晨 s905l3 -- [ CM211-1, CM311-1, HG680-LC, M401A, UNT400G1, UNT402A, ZXV10-BV310 ]"
msgid "Amlogic s905l3a - [ E900V22C/D, CM311-1a-YST, M401A, M411A, UNT403A, UNT413A, IP112H ]"
msgstr "晶晨 s905l3a - [ E900V22C/D, CM311-1a-YST, M401A, M411A, UNT403A, UNT413A, IP112H ]"
msgid "Amlogic s905l3b - [ CM211-1, CM311-1, E900V22D, E900V21E, E900V22E, M302A/M304A ]"
msgstr "晶晨 s905l3b - [ CM211-1, CM311-1, E900V22D, E900V21E, E900V22E, M302A/M304A ]"
msgid "Amlogic s905 ---- [ Beelink-Mini-MX-2G, Sunvell-T95M, MXQ-Pro+4K, SumaVision-Q5 ]"
msgstr "晶晨 s905 ---- [ Beelink-Mini-MX-2G, Sunvell-T95M, MXQ-Pro+4K, SumaVision-Q5 ]"
msgid "Allwinner H6 ---- [ V-Plus Cloud ]"
msgstr "全志 H6 ------ [ 微加云 ]"
msgid "Rockchip -------- [ BeikeYun, L1-Pro, FastRhino R66S/R68S, Radxa 5B/E25 ]"
msgstr "瑞芯微 ------- [ 贝壳云, 我家云, 电犀牛R66S/R68S, 瑞莎5B/E25 ]"
msgid "Used in KVM ----- [ Can be used in KVM virtual machine of Armbian system. ]"
msgstr "KVM 中使用 --- [ 可以在 Armbian 系统的 KVM 虚拟机中使用。 ]"
msgid "KVM dual system switching"
msgstr "KVM 双系统切换"
msgid "You can freely switch between KVM dual partitions, using OpenWrt systems in different partitions."
msgstr "您可以在 KVM 双分区之间自由切换,使用不同分区中的 OpenWrt 系统。"
msgid "Switch System"
msgstr "切换系统"
msgid "System is switching..."
msgstr "系统切换中..."
msgid "Waiting for system switching..."
msgstr "等待系统完成切换..."
msgid "System switchover succeeded, restarting..."
msgstr "系统切换成功,正在重启..."
msgid "Are you sure you want to switch systems?"
msgstr "你确定要切换系统吗?"
msgid "Install Ipk"
msgstr "安装Ipk"
msgid "Plugin Settings"
msgstr "插件设置"
msgid "Backup Firmware Config"
msgstr "备份固件配置"
msgid "Backup Config:"
msgstr "备份配置:"
msgid "Download Backup"
msgstr "下载备份"
msgid "Backup OpenWrt config (openwrt_config.tar.gz). Use this file to restore the config in [Manually Upload Update]."
msgstr "备份当前 OpenWrt 的相关配置信息(openwrt_config.tar.gz)。使用此文件可在 [手动上传更新] 中恢复配置。"
msgid "Edit List:"
msgstr "编辑列表:"
msgid "Open List"
msgstr "打开列表"
msgid "Backup Configuration - Custom List"
msgstr "备份配置 - 自定义列表"
msgid "Write one configuration item per line, and directories should end with a /."
msgstr "每行写一个配置项,目录需要以/结尾。"
msgid "Restore Backup:"
msgstr "恢复备份:"
msgid "Upload Backup"
msgstr "上传备份"
msgid "Restore"
msgstr "恢复"
msgid "Restore Config"
msgstr "恢复配置"
msgid "Restore configuration"
msgstr "还原配置"
msgid "Config File"
msgstr "配置文件"
msgid "Tip: The config is being restored, and it will automatically restart after completion."
msgstr "提示:正在还原配置,完成后将自动重启。"
msgid "Snapshot Management"
msgstr "快照管理"
msgid "Create Snapshot"
msgstr "创建快照"
msgid "Creating..."
msgstr "正在创建"
msgid "Created successfully"
msgstr "创建成功"
msgid "Creation failed"
msgstr "创建失败"
msgid "Initialize Snapshot"
msgstr "初始化快照"
msgid "Update Snapshot"
msgstr "更新点快照"
msgid "Restore Snap"
msgstr "还原快照"
msgid "Restoring..."
msgstr "正在还原"
msgid "Restore Failed"
msgstr "还原失败"
msgid "Successfully Restored"
msgstr "还原成功"
msgid "Delete Snap"
msgstr "删除快照"
msgid "You selected a snapshot:"
msgstr "你选择了快照:"
msgid "Confirm delete?"
msgstr "确定删除吗?"
msgid "Confirm recovery and restart OpenWrt?"
msgstr "确定恢复并重启 OpenWrt 吗?"
msgid "Delete Failed"
msgstr "删除失败"
msgid "Successfully Deleted"
msgstr "删除成功"
msgid "Create a snapshot of the current system configuration, or restore to a snapshot."
msgstr "创建当前系统配置的快照,或还原到某个快照。"
msgid "Currently OpenWrt does not support the snapshot function."
msgstr "当前 OpenWrt 不支持快照功能。"
msgid "Please use this plugin to reinstall or upgrade OpenWrt to enable the snapshot function."
msgstr "请使用本插件重新安装或升级 OpenWrt 开启快照功能。"
msgid "Deleting..."
msgstr "正在删除..."
msgid "Online Download Update"
msgstr "在线下载更新"
msgid "Config Source"
msgstr "配置来源"
msgid "You can customize the github.com download repository of OpenWrt files and kernels in [Online Download Update]."
msgstr "您可以自定义 [在线下载和更新] 中 OpenWrt 固件和内核的 github.com 下载仓库。"
msgid "Tip: The same files as the current OpenWrt system's BOARD (such as rock5b) and kernel (such as 5.10) will be downloaded."
msgstr "提示:将下载与当前 OpenWrt 系统的 BOARD(如:rock5b)和内核(如:5.10)相同的文件。"
msgid "OpenWrt download repository:"
msgstr "OpenWrt 文件的下载仓库:"
msgid "Set the OpenWrt files download repository on github.com in [Online Download Update]."
msgstr "设置 [在线下载更新] 中 github.com 的 OpenWrt 文件的下载仓库。"
msgid "OpenWrt download tags keyword:"
msgstr "OpenWrt 下载标签关键字:"
msgid "Set the OpenWrt files download tags keyword for github.com in [Online Download Update]."
msgstr "设置 [在线下载更新] 中 github.com 的 OpenWrt 文件下载标签关键字。"
msgid "OpenWrt files suffix:"
msgstr "OpenWrt 文件的后缀:"
msgid "Set the OpenWrt files download suffix for github.com in [Online Download Update]."
msgstr "设置 [在线下载更新] 中 github.com 的 OpenWrt 文件的后缀。"
msgid "Kernel download repository:"
msgstr "内核的下载仓库:"
msgid "Set the kernel files download repository on github.com in [Online Download Update]."
msgstr "设置 [在线下载更新] 中 github.com 的内核文件下载仓库。"
msgid "Kernel download tags:"
msgstr "内核的下载标签:"
msgid "Set the kernel files download tags on github.com in [Online Download Update]."
msgstr "设置 [在线下载更新] 中 github.com 的内核文件下载标签。"
msgid "kernel_rk3588 [Rockchip RK3588 Kernel]"
msgstr "kernel_rk3588 [Rockchip RK3588 内核]"
msgid "kernel_rk35xx [Rockchip RK35xx Kernel]"
msgstr "kernel_rk35xx [Rockchip RK35xx 内核]"
msgid "kernel_stable [Mainline Stable Kernel]"
msgstr "kernel_stable [主线稳定内核]"
msgid "kernel_flippy [Mainline Stable Kernel by Flippy]"
msgstr "kernel_flippy [Flippy 的主线稳定内核]"
msgid "kernel_h6 [Allwinner H6 Kernel]"
msgstr "kernel_h6 [Allwinner H6 内核]"
msgid "kernel_beta [Beta Kernel]"
msgstr "kernel_beta [测试版内核]"
msgid "Set version branch:"
msgstr "设置版本分支:"
msgid "Set the version branch of the OpenWrt files and kernel selected in [Online Download Update]."
msgstr "设置 [在线下载更新] 时 OpenWrt 文件与内核所选用的版本分支。"
msgid "Keep config update:"
msgstr "保留配置更新:"
msgid "Set whether to keep the current config during [Online Download Update] and [Manually Upload Update]."
msgstr "设置是否在 [在线下载更新] 和 [手动上传更新] 时保留当前的配置。"
msgid "Auto write bootloader:"
msgstr "自动写入 bootloader:"
msgid "[Recommended choice] Set whether to auto write bootloader during install and update OpenWrt."
msgstr "[推荐选择] 设置在安装和更新 OpenWrt 固件时是否自动写入 bootloader 文件。"
msgid "Set the file system type:"
msgstr "设置文件系统类型:"
msgid "[Default ext4] Set the file system type of the shared partition (/mnt/mmcblk*p4) when install OpenWrt."
msgstr "[默认 ext4] 设置安装 OpenWrt 时共享分区 (/mnt/mmcblk*p4) 的文件系统类型。"
msgid "Save Config:"
msgstr "保存配置:"
msgid "Save"
msgstr "保存"
msgid "Check All Components Update"
msgstr "插件和内核检查更新"
msgid "Provide OpenWrt Firmware, Kernel and Plugin online check, download and update service."
msgstr "提供 OpenWrt 固件,内核和插件在线检查,下载和更新服务。"
msgid "Only update Amlogic Service"
msgstr "仅更新晶晨宝盒"
msgid "Update system kernel only"
msgstr "仅更新系统内核"
msgid "Complete system update"
msgstr "完整更新全系统"
msgid "Check Update"
msgstr "检查更新"
msgid "Checking..."
msgstr "正在检查更新..."
msgid "Current Version"
msgstr "当前版本"
msgid "Latest Version"
msgstr "最新版本"
msgid "Rescue Kernel"
msgstr "救援内核"
msgid "When a kernel update fails and causes the OpenWrt system to be unbootable, the kernel can be restored by mutual recovery from eMMC/NVMe/sdX."
msgstr "当内核更新失败造成 OpenWrt 系统无法启动时,可以从 eMMC/NVME/sdX 相互恢复内核。"
msgid "Rescue the original system kernel"
msgstr "救援原系统内核"
msgid "Rescuing..."
msgstr "正在救援..."
msgid "Current Device:"
msgstr "当前设备:"
msgid "Display the PLATFORM classification of the device."
msgstr "显示设备的 PLATFORM 分类。"
msgid "Update plugins first, then update the kernel or firmware. More options can be configured in [Plugin Settings]."
msgstr "首先更新插件,再更新内核或固件。更多选项可以在插件设置中配置。"
msgid "Collecting data..."
msgstr "正在收集数据…"
msgid "Check All Components Update"
msgstr "插件和内核检查更新"
msgid "Server Logs"
msgstr "操作日志"
msgid "Display the execution log of the current operation."
msgstr "显示当前操作的执行日志。"
msgid "Stop Refresh Log"
msgstr "停止刷新"
msgid "Start Refresh Log"
msgstr "开始刷新"
msgid "Clean Log"
msgstr "清理日志"
msgid "Download Log"
msgstr "下载日志"
msgid "CPU Settings"
msgstr "CPU 设置"
msgid "CPU Freq"
msgstr "CPU 性能优化调节"
msgid "CPU Freq Settings"
msgstr "CPU 性能优化调节设置"
msgid "Set CPU Scaling Governor to Max Performance or Balance Mode"
msgstr "设置路由器的 CPU 性能模式(高性能/均衡省电)"
msgid "CPU Scaling Governor:"
msgstr "CPU 调速器:"
msgid "ondemand"
msgstr "Ondemand 自动平衡模式"
msgid "performance"
msgstr "Performance 高性能模式"
msgid "schedutil"
msgstr "Schedutil 敏捷调度器模式"
msgid "CPU Freq from 48000 to 716000 (Khz)"
msgstr "CPU 频率范围为 48000 到 716000 (Khz)"
msgid "Min Freq:"
msgstr "最小频率:"
msgid "Max Freq:"
msgstr "最大频率:"
msgid "CPU Switching Threshold:"
msgstr "CPU 切换频率触发阈值:"
msgid "Kernel make a decision on whether it should increase the frequency (%)"
msgstr "当 CPU 占用率超过 (%) 的情况下触发内核切换频率"
msgid "CPU Switching Sampling rate:"
msgstr "CPU 切换周期:"
msgid "The sampling rate determines how frequently the governor checks to tune the CPU (ms)"
msgstr "CPU 检查切换的周期 (ms) 。注意:过于频繁的切换频率会引起网络延迟抖动"
msgid "Microarchitectures:"
msgstr "微架构:"
msgid "Loading"
msgstr "载入中"
msgid "PowerOff"
msgstr "关机"
msgid "Shut down your router device."
msgstr "关闭你的路由器设备。"
msgid "Perform PowerOff"
msgstr "执行关机"
msgid "Are you sure you want to shut down?"
msgstr "你确定要关机吗?"
msgid "Device is shutting down..."
msgstr "设备正在关机..."
msgid "Waiting for the device to shut down..."
msgstr "等待设备关机..."
msgid "The device has been turned off"
msgstr "设备已经关机"
+1
View File
@@ -0,0 +1 @@
zh-cn
+17
View File
@@ -0,0 +1,17 @@
config amlogic 'config'
option enable '1'
option amlogic_firmware_repo 'https://github.com/breakingbadboy/OpenWrt'
option amlogic_firmware_tag 'ARMv8'
option amlogic_firmware_suffix '.img.gz'
option amlogic_kernel_path 'https://github.com/breakingbadboy/OpenWrt'
option amlogic_kernel_tags ''
option amlogic_kernel_branch ''
option amlogic_firmware_config '1'
option amlogic_write_bootloader '0'
option amlogic_shared_fstype 'ext4'
config settings 'armcpu'
option governor0 'schedutil'
option minfreq0 '500000'
option maxfreq0 '1512000'
+62
View File
@@ -0,0 +1,62 @@
#!/bin/sh /etc/rc.common
START=60
NAME=amlogic
uci_get_by_type() {
local ret=$(uci get $NAME.@$1[0].$2 2>/dev/null)
echo ${ret:=$3}
}
uci_set_by_type() {
uci set $NAME.@$1[0].$2=$3 2>/dev/null
uci commit $NAME
}
start() {
[ -x "/usr/sbin/fixcpufreq.pl" ] && /usr/sbin/fixcpufreq.pl && sync
local cpu_policys=$(ls /sys/devices/system/cpu/cpufreq 2>/dev/null | grep -E 'policy[0-9]{1,3}' | xargs)
if [ "${cpu_policys}" = "" ]; then
cpu_policys="policy0"
fi
config_load $NAME
for policy_name in ${cpu_policys}; do
local policy_id="${policy_name//policy/}"
# Get an optional value list for the current device
local governor_list="$(cat /sys/devices/system/cpu/cpufreq/${policy_name}/scaling_available_frequencies 2>/dev/null | xargs)"
local second_place_order="$(echo ${governor_list} | awk '{print $1}')"
local second_place_reverse="$(echo ${governor_list} | awk '{print $NF}')"
# Get the default value in the Config file
local governor=$(uci_get_by_type settings governor${policy_id} schedutil)
local minfreq=$(uci_get_by_type settings minfreq${policy_id} ${second_place_order})
local maxfreq=$(uci_get_by_type settings maxfreq${policy_id} ${second_place_reverse})
# Update result to the corresponding file
echo $governor >/sys/devices/system/cpu/cpufreq/${policy_name}/scaling_governor
echo $minfreq >/sys/devices/system/cpu/cpufreq/${policy_name}/scaling_min_freq
echo $maxfreq >/sys/devices/system/cpu/cpufreq/${policy_name}/scaling_max_freq
# If the governor is ondemand, configure its specific parameters.
if [ "$governor" = "ondemand" ]; then
local ondemand_dir="/sys/devices/system/cpu/cpufreq/${policy_name}/ondemand"
# Check if the per-policy ondemand directory exists.
if [ -d "$ondemand_dir" ]; then
# Read ondemand parameters from UCI, or use default values (e.g., 80 and 20) if not set.
local up_threshold=$(uci_get_by_type settings up_threshold${policy_id} 80)
local sampling_down_factor=$(uci_get_by_type settings sampling_down_factor${policy_id} 20)
# Write the values to the system files.
echo $up_threshold > "${ondemand_dir}/up_threshold"
echo $sampling_down_factor > "${ondemand_dir}/sampling_down_factor"
fi
fi
done
}
reload() {
start
return 0
}
@@ -0,0 +1,21 @@
#!/bin/sh
[ ! -f "/usr/share/ucitrack/luci-app-amlogic.json" ] && {
cat > /usr/share/ucitrack/luci-app-amlogic.json << EEOF
{
"config": "amlogic",
"init": "amlogic"
}
EEOF
}
sed -i 's/cbi.submit\"] = true/cbi.submit\"] = \"1\"/g' /usr/lib/lua/luci/dispatcher.lua
uci -q batch <<-EOF >/dev/null
delete ucitrack.@amlogic[-1]
add ucitrack amlogic
set ucitrack.@amlogic[-1].init=amlogic
commit ucitrack
EOF
rm -rf /tmp/luci-*
exit 0
+165
View File
@@ -0,0 +1,165 @@
#!/usr/bin/perl
use strict;
use File::Basename;
my $uci_config_name;
if(-f "/etc/config/amlogic") {
$uci_config_name="amlogic";
} elsif(-f "/etc/config/cpufreq") {
$uci_config_name="cpufreq";
} else {
print "Can not found amlogic or cpufreq config file!\n";
exit(0);
}
my @policy_ids;
my @policy_homes = </sys/devices/system/cpu/cpufreq/policy?>;
if(@policy_homes) {
foreach my $policy_home (@policy_homes) {
push @policy_ids, substr($policy_home, -1);
}
} else {
print "Can not found any policy!\n";
exit 0;
}
our $need_commit = 0;
for(my $i=0; $i <= $#policy_ids; $i++) {
&fix_invalid_value($uci_config_name, $policy_ids[$i], $policy_homes[$i]);
}
if($need_commit > 0) {
&uci_commit($uci_config_name);
}
exit 0;
################################# function ####################################
sub fix_invalid_value {
my($uci_config, $policy_id, $policy_home) = @_;
my %gove_hash = &get_gove_hash($policy_home);
my @freqs = &get_freq_list($policy_home);
my %freq_hash = &get_freq_hash(@freqs);
my $min_freq = &get_min_freq(@freqs);
my $max_freq = &get_max_freq(@freqs);
my $uci_section = "settings";
my $uci_option;
if($uci_config eq "cpufreq" ) {
$uci_option = "governor";
} else {
$uci_option = "governor" . $policy_id;
}
# 如果未设置 governor, 或该 goveernor 不存在, 则修败默认值为 schedutil
my $config_gove = &uci_get_by_type($uci_config, $uci_section, $uci_option, "NA");
if( ($config_gove eq "NA") ||
($gove_hash{$config_gove} != 1)) {
&uci_set_by_type($uci_config, $uci_section, $uci_option, "schedutil");
$need_commit++;
}
# 如果出现不存在的 minfreq, 则修改为实际的 min_freq
if($uci_config eq "cpufreq" ) {
# "minifreq" is a spelling error that has always existed in the upstream source code
$uci_option = "minifreq";
} else {
$uci_option = "minfreq" . $policy_id;
}
my $config_min_freq = &uci_get_by_type($uci_config, $uci_section, $uci_option, "0");
if($freq_hash{$config_min_freq} != 1) {
&uci_set_by_type($uci_config, $uci_section, $uci_option, $min_freq);
$need_commit++;
}
# 如果出现不存在的 maxfreq
# 或 maxfreq < minfreq, 则修改为实际的 max_freq
if($uci_config eq "cpufreq" ) {
$uci_option = "maxfreq";
} else {
$uci_option = "maxfreq" . $policy_id;
}
my $config_max_freq = &uci_get_by_type($uci_config, $uci_section, $uci_option, "0");
if( ( $freq_hash{$config_max_freq} != 1) ||
( $config_max_freq < $config_min_freq)) {
&uci_set_by_type($uci_config, $uci_section, $uci_option, $max_freq);
$need_commit++;
}
}
sub get_freq_list {
my $policy_home = shift;
my @ret_ary;
open my $fh, "<", "${policy_home}/scaling_available_frequencies" or die;
$_ = <$fh>;
chomp;
@ret_ary = split /\s+/;
close($fh);
return @ret_ary;
}
sub get_freq_hash {
my @freq_ary = @_;
my %ret_hash;
foreach my $freq (@freq_ary) {
if($freq =~ m/\d+/) {
$ret_hash{$freq} = 1;
}
}
return %ret_hash;
}
sub get_min_freq {
my @freq_ary = @_;
return (sort {$a<=>$b} @freq_ary)[0];
}
sub get_max_freq {
my @freq_ary = @_;
return (sort {$a<=>$b} @freq_ary)[-1];
}
sub get_gove_hash {
my $policy_home = shift;
my %ret_hash;
open my $fh, "<", "${policy_home}/scaling_available_governors" or die;
$_ = <$fh>;
chomp;
my @gov_ary = split /\s+/;
foreach my $gov (@gov_ary) {
#print "gov: $gov\n";
if($gov =~ m/\w+/) {
$ret_hash{$gov} = 1;
}
}
close($fh);
return %ret_hash;
}
sub uci_get_by_type {
my($config,$section,$option,$default) = @_;
my $ret;
$ret=`uci get ${config}.\@${section}\[0\].${option} 2>/dev/null`;
# 消除回车换行
$ret =~ s/[\n\r]//g;
if($ret eq '') {
return $default;
} else {
return $ret;
}
}
sub uci_set_by_type {
my($config,$section,$option,$value) = @_;
my $ret;
system("uci set ${config}.\@${section}\[0\].${option}=${value}");
return;
}
sub uci_commit {
my $config = shift;
system("uci commit ${config}");
return;
}
+598
View File
@@ -0,0 +1,598 @@
#!/bin/bash
#======================================================================
# Function: Backup and restore config files in the /etc directory
# Copyright (C) 2020-- https://github.com/unifreq/openwrt_packit
# Copyright (C) 2021-- https://github.com/ophub/luci-app-amlogic
#======================================================================
VERSION="v1.3"
ZSTD_LEVEL=6
SNAPSHOT_PRESTR=".snapshots/"
BACKUP_DIR="/.reserved"
BACKUP_NAME="openwrt_config.tar.gz"
BACKUP_FILE="${BACKUP_DIR}/${BACKUP_NAME}"
# Customize backup list
backup_list_conf="/etc/amlogic_backup_list.conf"
if [[ -s "${backup_list_conf}" ]]; then
while IFS= read -r line; do
BACKUP_LIST+="${line} "
done <"${backup_list_conf}"
else
BACKUP_LIST='./etc/AdGuardHome.yaml \
./etc/amlogic_backup_list.conf \
./etc/adblocklist/ \
./etc/amule/ \
./etc/balance_irq \
./etc/bluetooth/ \
./etc/china_ssr.txt \
./etc/cifs/cifsdpwd.db \
./etc/smbd/smbdpwd.db \
./etc/ksmbd/ksmbdpwd.db \
./etc/config/ \
./etc/crontabs/ \
./etc/dae/ \
./etc/daed/ \
./usr/share/openclash/core/ \
./etc/openclash/backup/ \
./etc/openclash/config/ \
./etc/openclash/custom/ \
./etc/openclash/game_rules/ \
./etc/openclash/rule_provider/ \
./etc/openclash/proxy_provider/ \
./etc/dnsforwarder/ \
./etc/dnsmasq.conf \
./etc/dnsmasq.d/ \
./etc/dnsmasq.oversea/ \
./etc/dnsmasq.ssr/ \
./etc/docker/daemon.json \
./etc/docker/key.json \
./etc/dropbear/ \
./etc/easy-rsa/ \
./etc/environment \
./etc/exports \
./etc/firewall.user \
./etc/gfwlist/ \
./etc/haproxy.cfg \
./etc/hosts \
./etc/ipsec.conf \
./etc/ipsec.d/ \
./etc/ipsec.secrets \
./etc/ipsec.user \
./etc/ipset/ \
./etc/mosdns/config.yaml \
./etc/mwan3.user \
./etc/nginx/nginx.conf \
./etc/ocserv/ \
./etc/openvpn/ \
./etc/pptpd.conf \
./etc/qBittorrent/ \
./etc/rc.local \
./etc/samba/smbpasswd \
./etc/shadow \
./etc/smartdns/ \
./etc/sqm/ \
./etc/ssh/*key* \
./etc/ssl/private/ \
./etc/ssrplus/ \
./etc/sysupgrade.conf \
./etc/tailscale/ \
./etc/transmission/ \
./etc/uhttpd.crt \
./etc/uhttpd.key \
./etc/urandom.seed \
./etc/v2raya/ \
./etc/verysync/ \
./root/.ssh/'
fi
error_msg() {
echo -e " [ERROR] ${1}"
exit 1
}
if dmesg | grep 'meson' >/dev/null 2>&1; then
PLATFORM="amlogic"
elif dmesg | grep 'rockchip' >/dev/null 2>&1; then
PLATFORM="rockchip"
elif dmesg | grep 'sun50i-h6' >/dev/null 2>&1; then
PLATFORM="allwinner"
else
source /etc/flippy-openwrt-release
case ${PLATFORM} in
amlogic | rockchip | allwinner | qemu-aarch64) : ;;
*) error_msg "Unknown platform, only support amlogic or rockchip or allwinner h6 or qemu-aarch64!" ;;
esac
fi
get_root_partition_name() {
local paths=("/" "/overlay" "/rom")
local partition_name
for path in "${paths[@]}"; do
partition_name=$(df "${path}" | awk 'NR==2 {print $1}' | awk -F '/' '{print $3}')
[[ -n "${partition_name}" ]] && break
done
[[ -z "${partition_name}" ]] && error_msg "Cannot find the root partition!"
echo "${partition_name}"
}
# Get the partition message of the root file system
get_root_partition_msg() {
local paths=("/" "/overlay" "/rom")
local partition_name
for path in "${paths[@]}"; do
partition_msg=$(lsblk -l -o NAME,PATH,MOUNTPOINT,UUID,FSTYPE,LABEL | awk '$3 ~ "^" "'"${path}"'" "$" {print $0}')
[[ -n "${partition_msg}" ]] && break
done
[[ -z "${partition_msg}" ]] && error_msg "Cannot find the root partition message!"
echo "${partition_msg}"
}
backup() {
cd /
echo -n "Backup config files ... "
[ -d "${BACKUP_DIR}" ] || mkdir -p "${BACKUP_DIR}"
eval tar czf "${BACKUP_FILE}" "${BACKUP_LIST}" 2>/dev/null
sync
if [ -f "${BACKUP_FILE}" ]; then
echo "Has been backed up to [ ${BACKUP_FILE} ], please download and save."
exit 0
else
error_msg "Backup failed!"
fi
}
restore() {
# Find the partition where root is located
ROOT_PTNAME="$(get_root_partition_name)"
# Find the disk where the partition is located, only supports mmcblk?p? sd?? hd?? vd?? and other formats
case ${ROOT_PTNAME} in
mmcblk?p[1-4])
EMMC_NAME=$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-2)}')
PARTITION_NAME="p"
LB_PRE="EMMC_"
;;
[hsv]d[a-z][1-4])
EMMC_NAME=$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-1)}')
PARTITION_NAME=""
LB_PRE=""
;;
*)
error_msg "Unable to recognize the disk type of ${ROOT_PTNAME}!"
;;
esac
[ -d "${BACKUP_DIR}" ] || mkdir -p "${BACKUP_DIR}"
[ -f "/tmp/upload/${BACKUP_NAME}" ] && mv -f "/tmp/upload/${BACKUP_NAME}" ${BACKUP_FILE}
[ -f "/mnt/${EMMC_NAME}${PARTITION_NAME}4/${BACKUP_NAME}" ] && mv -f "/mnt/${EMMC_NAME}${PARTITION_NAME}4/${BACKUP_NAME}" ${BACKUP_FILE}
sync
if [ -f "${BACKUP_FILE}" ]; then
echo -n "restore config files ... "
cd /
tar xzf "${BACKUP_FILE}" 2>/dev/null && sync
echo "Successful recovery. Will start automatically, please refresh later!"
sleep 3
reboot
exit 0
else
error_msg "The backup file [ ${BACKUP_FILE} ] not found!"
fi
}
gen_fstab() {
# Find the partition where root is located
ROOT_PTNAME="$(get_root_partition_name)"
# Find the disk where the partition is located, only supports mmcblk?p? sd?? hd?? vd?? and other formats
case ${ROOT_PTNAME} in
mmcblk?p[1-4])
EMMC_NAME=$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-2)}')
PARTITION_NAME="p"
;;
[hsv]d[a-z][1-4])
EMMC_NAME=$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-1)}')
PARTITION_NAME=""
;;
*)
error_msg "Unable to recognize the disk type of ${ROOT_PTNAME}!"
;;
esac
ROOT_MSG="$(get_root_partition_msg)"
ROOT_NAME=$(echo $ROOT_MSG | awk '{print $1}')
ROOT_DEV=$(echo $ROOT_MSG | awk '{print $2}')
ROOT_UUID=$(echo $ROOT_MSG | awk '{print $4}')
ROOT_FSTYPE=$(echo $ROOT_MSG | awk '{print $5}')
ROOT_LABEL=$(echo $ROOT_MSG | awk '{print $6}')
BOOT_NAME="${EMMC_NAME}${PARTITION_NAME}1"
BOOT_MSG=$(lsblk -l -o NAME,UUID,FSTYPE,LABEL | grep "${BOOT_NAME}")
BOOT_DEV="/dev/${BOOT_NAME}"
BOOT_UUID=$(echo $BOOT_MSG | awk '{print $2}')
BOOT_FSTYPE=$(echo $BOOT_MSG | awk '{print $3}')
BOOT_LABEL=$(echo $BOOT_MSG | awk '{print $4}')
cat >/etc/config/fstab <<EOF
config global
option anon_swap '0'
option anon_mount '1'
option auto_swap '0'
option auto_mount '1'
option delay_root '5'
option check_fs '0'
config mount
option target '/rom'
option uuid '${ROOT_UUID}'
option enabled '1'
option enabled_fsck '1'
option fstype '${ROOT_FSTYPE}'
EOF
if [ "${ROOT_FSTYPE}" == "btrfs" ]; then
echo " option options 'compress=zstd:${ZSTD_LEVEL}'" >>/etc/config/fstab
fi
cat >>/etc/config/fstab <<EOF
config mount
option target '/boot'
EOF
if [ "${BOOT_FSTYPE}" == "vfat" ]; then
echo " option label '${BOOT_LABEL}'" >>/etc/config/fstab
else
echo " option uuid '${BOOT_UUID}'" >>/etc/config/fstab
fi
cat >>/etc/config/fstab <<EOF
option enabled '1'
option enabled_fsck '1'
option fstype '${BOOT_FSTYPE}'
EOF
echo "/etc/config/fstab generated."
echo "Please reboot before continuing."
exit 0
}
print_list() {
echo "${BACKUP_LIST}"
exit 0
}
list_snapshot() {
echo "----------------------------------------------------------------"
btrfs subvolume list -rt /
echo "----------------------------------------------------------------"
read -p "Press [ enter ] to return." q
}
create_snapshot() {
default_snap_name="etc-$(date +"%m.%d.%H%M%S")"
echo "The default snapshot name is: ${default_snap_name}"
echo "If you want to modify the snapshot name, please enter it below. Cannot contain spaces."
echo "If you do not want to modify it, just press [ Enter ]. Or press the [ q ] key to go back directly."
while :; do
read -p "[${default_snap_name}] : " nname
if [ "${nname}" == "" ]; then
snap_name="${default_snap_name}"
break
elif echo "${nname}" | grep -E "\s+" >/dev/null; then
echo "The name [${nname}] contains spaces, please re-enter!"
continue
elif [ "${nname}" == "q" ] || [ "${nname}" == "Q" ]; then
return
else
if btrfs subvolume list -rt / | awk '{print $4}' | grep "^\\${SNAPSHOT_PRESTR}${nname}$" >/dev/null; then
echo "Name: [ ${nname} ] has been used, please re-enter!"
continue
else
snap_name="${nname}"
break
fi
fi
done
(
cd /
chattr -ia etc/config/fstab
btrfs subvolume snapshot -r /etc "${SNAPSHOT_PRESTR}${snap_name}"
if [[ "$?" -eq "0" ]]; then
echo "The snapshot is created successfully: ${snap_name}"
else
echo "Snapshot creation failed!"
fi
)
read -p "Press [ enter ] to return." q
}
restore_snapshot() {
echo "Below are the existing etc snapshots, please enter the name of one of them."
echo "Tip: [ etc-000 ] This is the factory initial configuration."
echo " [ etc-001 ] if it exists, it is the initial configuration after upgrading from the previous version."
echo "----------------------------------------------------------------"
btrfs subvolume list -rt /
echo "----------------------------------------------------------------"
read -p "Please enter the name of the snapshot to be restored (only the part after ${SNAPSHOT_PRESTR} needs to be entered): " snap_name
if btrfs subvolume list -rt / | grep "${SNAPSHOT_PRESTR}${snap_name}" >/dev/null; then
while :; do
echo "Once the snapshot is restored, the current [ /etc ] will be overwritten!"
read -p "Are you sure you want to restore the snapshot: [$snap_name]? y/n [n] " yn
case $yn in
y | Y)
(
cd /
chattr -ia etc/config/fstab
mv etc etc.backup
btrfs subvolume snapshot "${SNAPSHOT_PRESTR}${snap_name}" etc
if [[ "$?" -eq "0" ]]; then
btrfs subvolume delete -c etc.backup
echo "Successfully restored, please enter [ reboot ] to restart the openwrt."
else
rm -rf etc
mv etc.backup etc
echo "Recovery failed, [ etc ] has not changed!"
fi
)
read -p "Press [ enter ] to return." q
break
;;
*)
break
;;
esac
done
else
read -p "The snapshot name is incorrect, please run the program again! Press [ Enter ] to go back." q
fi
}
delete_snapshot() {
echo "Below are the existing [ etc ] snapshots, please enter the name of one of them."
echo "Tip: [ etc-000 ] This is the factory initial configuration (cannot be deleted)"
echo " [ etc-001 ] if it exists, it is the initial configuration after upgrading from the previous version (cannot be deleted)"
echo "----------------------------------------------------------------"
btrfs subvolume list -rt /
echo "----------------------------------------------------------------"
read -p "Please enter the name of the snapshot to be deleted (only the part after ${SNAPSHOT_PRESTR} needs to be entered): " snap_name
if [ "${snap_name}" == "etc-000" ] || [ "${snap_name}" == "etc-001" ]; then
read -p "The key snapshot cannot be deleted! Press [ enter ] to return." q
elif [ "${snap_name}" == "" ]; then
read -p "Name is empty! Press [ enter ] to return." q
else
if btrfs subvolume list -rt / | grep "${SNAPSHOT_PRESTR}${snap_name}" >/dev/null; then
read -p "Are you sure you want to delete ${snap_name}? y/n [n] " yn
case $yn in
y | Y)
(
cd /
btrfs subvolume delete -c "${SNAPSHOT_PRESTR}${snap_name}"
if [[ "$?" -eq "0" ]]; then
echo "Snapshot [ ${snap_name} ] has been deleted."
else
echo "Snapshot [ ${snap_name} ] failed to delete!"
fi
)
read -p "Press [ Enter ] to return." q
;;
*)
break
;;
esac
else
read -p "The name of the snapshot is incorrect, press [ Enter ] to return." q
fi
fi
}
migrate_snapshot() {
cur_rootdev="$(get_root_partition_name)"
dev_pre=$(echo "${cur_rootdev}" | awk '{print substr($1, 1, length($1)-1);}')
rootdev_idx=$(echo "${cur_rootdev}" | awk '{print substr($1, length($1),1);}')
case $rootdev_idx in
2)
old_rootpath="/mnt/${dev_pre}3"
;;
3)
old_rootpath="/mnt/${dev_pre}2"
;;
*)
echo "Judge the old version of rootfs path failed!"
read -p "Press [ enter ] to return." q
return
;;
esac
echo "The following are snapshots of etc found from the old version of rootfs, please enter the name of one of them."
echo "Tip: Automatically exclude etc-000 and etc-001"
echo "-----------------------------------------------------------------------------------"
btrfs subvolume list -rt "${old_rootpath}" | grep -v "${SNAPSHOT_PRESTR}etc-000" | grep -v "${SNAPSHOT_PRESTR}etc-001"
echo "-----------------------------------------------------------------------------------"
read -p "Please enter the name of the snapshot to be migrated (only the part after $(SNAPSHOT_PRESTR) needs to be entered): " old_snap_name
if [ "${old_snap_name}" == "" ]; then
read -p "The name is empty, Press [ enter ] to return." q
return
elif ! btrfs subvolume list -rt "${old_rootpath}" | awk '{print $4}' | grep "^${SNAPSHOT_PRESTR}${old_snap_name}$" >/dev/null; then
echo "The name was entered incorrectly, and the corresponding snapshot was not found!"
read -p "Press [ enter ] to return." q
return
elif [ "${old_snap_name}" == "etc-000" ] || [ "${old_snap_name}" == "etc-001" ]; then
echo "Critical snapshots are not allowed to migrate!"
read -p "Press [ enter ] to return." q
return
fi
# Find out if there is a snapshot with the same name under the current rootfs
if btrfs subvolume list -rt / | awk '{print $4}' | grep "^\\${SNAPSHOT_PRESTR}${old_snap_name}$" >/dev/null; then
echo "A snapshot with the name [ ${old_snap_name} ] already exists and cannot be migrated! (But you can delete the existing snapshot with the same name and then migrate)"
read -p "Press [ enter ] to return." q
return
fi
need_size=$(du -h -d0 ${old_rootpath}/${SNAPSHOT_PRESTR}${old_snap_name} | tail -n1 | awk '{print $1}')
echo "----------------------------------------------------------------------------------------------"
df -h
echo "----------------------------------------------------------------------------------------------"
echo -e "Note: To migrate the snapshot [ ${old_snap_name} ] of [ ${old_rootpath} ] to the current rootfs, it takes about [ ${need_size} ] space,"
echo -e " Please confirm whether the partition [/dev/${cur_rootdev}] where [/] is located has enough free space (Available)?"
read -p "Are you sure to migrate? y/n [n] " yn
if [ "$yn" == "y" ] || [ "$yn" == "Y" ]; then
(
cd /
btrfs send ${old_rootpath}/${SNAPSHOT_PRESTR}${old_snap_name} | btrfs receive ${SNAPSHOT_PRESTR}
if [ $? -eq 0 ]; then
btrfs property set -ts ${SNAPSHOT_PRESTR}${old_snap_name} ro false
cp ${SNAPSHOT_PRESTR}etc-000/config/fstab ${SNAPSHOT_PRESTR}${old_snap_name}/config/
cp ${SNAPSHOT_PRESTR}etc-000/fstab ${SNAPSHOT_PRESTR}${old_snap_name}/
cp ${SNAPSHOT_PRESTR}etc-000/openwrt_release ${SNAPSHOT_PRESTR}${old_snap_name}/
cp ${SNAPSHOT_PRESTR}etc-000/openwrt_version ${SNAPSHOT_PRESTR}${old_snap_name}/
cp ${SNAPSHOT_PRESTR}etc-000/flippy-openwrt-release ${SNAPSHOT_PRESTR}${old_snap_name}/
cp ${SNAPSHOT_PRESTR}etc-000/banner ${SNAPSHOT_PRESTR}${old_snap_name}/banner
btrfs property set -ts ${SNAPSHOT_PRESTR}${old_snap_name} ro true
echo "The migration is complete, if you want to apply the snapshot [ ${old_snap_name} ], please use the restore snapshot function."
else
echo "The migration failed!"
fi
read -p "Press [ enter ] to return." q
return
)
fi
}
snapshot_help() {
clear
cat <<EOF
============================================================================================================================
1. What is a snapshot?
A snapshot is the state record of a certain subvolume at a certain point in time, and a snapshot is a special subvolume;
When the local snapshot is first generated, it shares the disk space with the original subvolume,
so it does not occupy additional space, and only the files that have changed subsequently occupy space;
Snapshots migrated from other places are not snapshots in essence, but just ordinary subvolumes, so they take up space.
2. How to display existing snapshots?
input the command: btrfs subvolume list -rt /
---------------------------------------------------------------------------------------------
EOF
btrfs subvolume list -rt /
cat <<EOF
---------------------------------------------------------------------------------------------
2. How to create a snapshot?
btrfs subvolume snapshot -r /etc /.snapshots/snapshot_1 # -r It means to generate a read-only snapshot
3. How to delete a snapshot?
btrfs subvolume delete -c /.snapshots/snapshot_1 # -c 是 commit 的意思
4. How to rename a snapshot?
Just use the [ mv ] command of the operating system, for example:
mv /.snapshots/snapshot_1 /.snapshots/snapshot_2
5. How to restore the snapshot?
mv /etc /etc.backup # Back up /etc to /etc.backup, that is, rename the subvolume
btrfs subvolume snapshot /.snapshots/etc-001 /etc # Use snapshot etc-001 to generate snapshot etc, no -r parameter
# (Yes, snapshots can also be re-generated snapshots)
btrfs delete -c /etc.backup # After the previous step is successful, you can delete the etc backup just now
6. How to restore a certain file from the snapshot?
Example A: Restore the mount point configuration file from snapshot etc-000: /etc/config/fstab
cp /.snapshots/etc-000/config/fstab /etc/config/
Example B: Restore network configuration from snapshot etc-001:
cp /.snapshots/etc-001/config/network /etc/config/
Example C: Restore the ssr configuration file from snapshot etc-001:
cp /.snapshots/etc-001/config/shadowsocksr /etc/config/
# (Yes, it is the [ cp ] command of the operating system)
7. How to migrate snapshots from remote?
btrfs supports ssh remote migration snapshots, for example:
ssh 192.168.1.1 btrfs send /.snapshots/snapshot_x | btrfs receive /.snapshots
After the command is completed, the remote snapshot_x is copied to the local /.snapshots/snapshot_x
(as mentioned above, the migration is a subvolume, which takes up space)
============================================================================================================================
EOF
exit 0
}
print_help() {
echo "Usage: $0 -b [ backup ]"
echo " $0 -r [ restore ]"
echo " $0 -g [ generate fstab ]"
echo " $0 -p [ print backup list ]"
echo " $0 -l [ list snapshots ]"
echo " $0 -c [ create snapshot ]"
echo " $0 -s [ restore snapshot ]"
echo " $0 -d [ delete snapshot ]"
echo " $0 -h [ help ]"
echo " $0 -q [ quit ]"
exit 0
}
menu() {
while :; do
clear
cat <<EOF
┌────────[ backup config ]────────┐
│ │
│ b. backup config │
│ r. restore config │
│ g. generate fstab │
│ p. print backup list │
│ │
├─────[ Snapshot management ]─────┤
│ │
│ l. list snapshots │
│ c. create snapshot │
│ d. delete snapshot │
│ R. restore snapshot │
│ m. migrate snapshot │
│ s. snapshot help │
│ │
╞═════════════════════════════════╡
│ │
│ h. help │
│ q. quit │
│ │
└─────────────────────────────────┘
EOF
echo -ne "please select: [ ]\b\b"
read select
case $select in
b | backup) backup ;;
r | restore)
restore
gen_fstab
;;
g | gen_fstab) gen_fstab ;;
p | print_list) print_list ;;
l | list_snapshot) list_snapshot ;;
c | create_snapshot) create_snapshot ;;
d | delete_snapshot) delete_snapshot ;;
R | restore_snapshot) restore_snapshot ;;
m | migrate_snapshot) migrate_snapshot ;;
s | snapshot_help) snapshot_help ;;
h | help) print_help ;;
q | quit) exit 0 ;;
esac
done
}
getopts 'brgplcRmsdhq' opts
case $opts in
b | backup) backup ;;
r | restore)
restore
gen_fstab
;;
g | gen_fstab) gen_fstab ;;
p | print_list) print_list ;;
l | list_snapshot) list_snapshot ;;
c | create_snapshot) create_snapshot ;;
d | delete_snapshot) delete_snapshot ;;
R | restore_snapshot) restore_snapshot ;;
m | migrate_snapshot) migrate_snapshot ;;
s | snapshot_help) snapshot_help ;;
h | help) print_help ;;
q | quit) exit 0 ;;
*) menu ;;
esac
+155
View File
@@ -0,0 +1,155 @@
#!/bin/bash
#===========================================================================
#
# This file is licensed under the terms of the GNU General Public
# License version 2. This program is licensed "as is" without any
# warranty of any kind, whether express or implied.
#
# This file is a part of the make OpenWrt for Amlogic s9xxx tv box
# https://github.com/ophub/luci-app-amlogic
#
# Description: Backup and restore the system in emmc
# Copyright (C) 2017- The function borrowed from armbian/ddbr, Author: xXx
# Copyright (C) 2021- https://github.com/unifreq/openwrt_packit
# Copyright (C) 2021- https://github.com/ophub/luci-app-amlogic
#
# Command: openwrt-ddbr
#
#========================= Set default parameters ===========================
#
# Set font color
blue_font_prefix="\033[34m"
purple_font_prefix="\033[35m"
green_font_prefix="\033[32m"
yellow_font_prefix="\033[33m"
red_font_prefix="\033[31m"
font_color_suffix="\033[0m"
INFO="[${blue_font_prefix}INFO${font_color_suffix}]"
STEPS="[${purple_font_prefix}STEPS${font_color_suffix}]"
SUCCESS="[${green_font_prefix}SUCCESS${font_color_suffix}]"
OPT="[${yellow_font_prefix}OPT${font_color_suffix}]"
ERROR="[${red_font_prefix}ERROR${font_color_suffix}]"
#
# Check the output path
out_path="/ddbr"
# File name for backup/restore
ddbr_image="BACKUP-arm-64-emmc.img.gz"
# Need remaining space, unit: GB
need_space="2"
#
#===========================================================================
# Encountered a serious error, abort the script execution
error_msg() {
echo -e "${ERROR} ${1}"
exit 1
}
# Get the partition name of the root file system
get_root_partition_name() {
local paths=("/" "/overlay" "/rom")
local partition_name
for path in "${paths[@]}"; do
partition_name=$(df "${path}" | awk 'NR==2 {print $1}' | awk -F '/' '{print $3}')
[[ -n "${partition_name}" ]] && break
done
[[ -z "${partition_name}" ]] && error_msg "Cannot find the root partition!"
echo "${partition_name}"
}
# Check emmc
do_checkemmc() {
# Get device name
mydevice_name="$(cat /proc/device-tree/model | tr -d '\000')"
echo -e "${INFO} The device name: [ ${mydevice_name} ]"
# Find the partition where root is located
root_ptname="$(get_root_partition_name)"
# Find the EMMC drive
emmc="$(lsblk -l -o NAME | grep -oE "mmcblk[0-9]boot0" | sort | uniq | sed "s/boot0//g")"
# Find emmc disk, find emmc that does not contain the boot0 partition
[[ -z "${emmc}" ]] && emmc="$(lsblk -l -o NAME | grep -oE '(mmcblk[0-9]?)' | grep -vE ^${root_ptname:0:-2} | uniq)"
# Check if emmc exists
[[ -z "${emmc}" ]] && error_msg "The eMMC storage not found in this device!"
# Show the emmc name
echo -e "${INFO} The device eMMC name: [ /dev/${emmc} ]"
# Find the disk where the partition is located, only supports mmcblk?p? sd?? hd?? vd?? and other formats
case "${root_ptname}" in
mmcblk?p[1-4])
disk_name="$(echo ${root_ptname} | awk '{print substr($1, 1, length($1)-2)}')"
if lsblk -l -o NAME | grep "${disk_name}boot0" >/dev/null; then
error_msg "The current system is running on emmc. Please perform backup/restore operation in [ SD/TF/USB ]!"
fi
link_ptname="p"
;;
[hsv]d[a-z][1-4])
disk_name="$(echo ${root_ptname} | awk '{print substr($1, 1, length($1)-1)}')"
link_ptname=""
;;
nvme?n?p[1-4])
disk_name="$(echo ${root_ptname} | awk '{print substr($1, 1, length($1)-2)}')"
link_ptname="p"
;;
*)
error_msg "Unable to recognize the disk type of ${root_ptname}!"
;;
esac
# Set check parameters
out_path="/mnt/${disk_name}${link_ptname}4"
dev_intsize="$(fdisk -s /dev/${emmc})"
[[ -z "$(echo "${dev_intsize}" | sed -n "/^[0-9]\+$/p")" ]] && error_msg "Unable to get EMMC size."
echo -e "${INFO} The device EMMC size: [ $(($dev_intsize / 1024 / 1024))GB ]"
# check directory
[[ -d "${out_path}" ]] || mkdir -p ${out_path}
echo -e "${INFO} The ddbr file path: [ ${out_path}/${ddbr_image} ]\n"
}
# Check the remaining space
do_checkspace() {
remaining_space="$(df -Tk ${out_path} | grep '/dev/' | awk '{print $5}' | echo $(($(xargs) / 1024 / 1024)))"
if [[ -z "$(echo "${remaining_space}" | sed -n "/^[0-9]\+$/p")" ]]; then
error_msg "The path is not available, the remaining space cannot be obtained."
fi
if [[ "${remaining_space}" -lt "${need_space}" ]]; then
error_msg "The remaining space is [ ${remaining_space} ] Gb, and more than [ ${need_space} ] Gb space is required."
fi
}
# Backup the emmc system
do_backup() {
echo -e "${STEPS} Start to backup the system in emmc."
do_checkspace
echo -e "Saving and Compressing [ /dev/${emmc} ] to [ ${out_path}/${ddbr_image} ], Please wait..."
rm -f ${out_path}/${ddbr_image} 2>/dev/null && sync
dd if=/dev/${emmc} | pv -s ${dev_intsize}"K" | gzip >${out_path}/${ddbr_image}
[[ "${?}" -eq "0" ]] && sync && echo -e "${SUCCESS} Backup is complete."
}
# Restore the emmc system
do_restore() {
echo -e "${STEPS} Start to restore the system in emmc."
[[ ! -f ${out_path}/${ddbr_image} ]] && error_msg "The [ ${out_path}/${ddbr_image} ] File not found."
echo -e "Restoring [ ${out_path}/${ddbr_image} ] to [ /dev/${emmc} ], Please wait..."
gunzip -c ${out_path}/${ddbr_image} | pv -s ${dev_intsize}"K" | dd of=/dev/${emmc}
[[ "${?}" -eq "0" ]] && sync && echo -e "${SUCCESS} Restore is complete."
}
echo -e "${STEPS} Welcome to use the EMMC system backup/restore service."
# Check script permission
[[ -x "/usr/sbin/openwrt-ddbr" ]] || error_msg "Please grant execution permission: [ chmod +x /usr/sbin/openwrt-ddbr ]"
# Check emmc
do_checkemmc
# Prompt the user to select backup/restore
echo -ne "${OPT} Do you want to backup or restore? Backup=(b) Restore=(r): "
read br
case "${br}" in
b | B | backup) do_backup ;;
r | R | restore) do_restore ;;
*) exit 0 ;;
esac
+721
View File
@@ -0,0 +1,721 @@
#!/bin/bash
#======================================================================================
# Function: Install openwrt to emmc for Amlogic S9xxx STB
# Copyright (C) 2020-- https://github.com/unifreq/openwrt_packit
# Copyright (C) 2021-- https://github.com/ophub/luci-app-amlogic
#======================================================================================
#
# The script supports directly setting parameters for installation, skipping interactive selection
# openwrt-install-amlogic ${AUTO_MAINLINE_UBOOT} ${ID} ${FDTFILE}:${SOC}:${UBOOT_OVERLOAD} ${SHARED_FSTYPE}
# E.g: openwrt-install-amlogic yes 11 auto ext4
# E.g: openwrt-install-amlogic no 99 meson-gxl-s905d-phicomm-n1.dtb:s905d:u-boot-n1.bin ext4
# Tip: When custom dtb file, set ${SOC_ID} to 99, and parameter ${FDTFILE}:${SOC}:${UBOOT_OVERLOAD} must be set
# Tip: ${SHARED_FSTYPE}: Shared partition can be ext4, xfs, btrfs, f2fs
# You can also execute the script directly, and interactively select related functions
# E.g: openwrt-install-amlogic
#
#======================================================================================
# Encountered a serious error, abort the script execution
error_msg() {
echo -e "[ERROR] ${1}"
exit 1
}
# Get the partition name of the root file system
get_root_partition_name() {
local paths=("/" "/overlay" "/rom")
local partition_name
for path in "${paths[@]}"; do
partition_name=$(df "${path}" | awk 'NR==2 {print $1}' | awk -F '/' '{print $3}')
[[ -n "${partition_name}" ]] && break
done
[[ -z "${partition_name}" ]] && error_msg "Cannot find the root partition!"
echo "${partition_name}"
}
# Receive one-key command related parameters
AUTO_MAINLINE_UBOOT="${1}"
ZSTD_LEVEL="6"
op_release="/etc/flippy-openwrt-release"
# For [luci-app-amlogic] input parameter: DTB, SOC & UBOOT_OVERLOAD
# When there is no input parameter, select manually
SPECIFY_ID=""
SPECIFY_SOC=""
SPECIFY_DTB=""
SPECIFY_UBOOT=""
[[ -n "${2}" ]] && {
SPECIFY_ID="${2}"
if [[ "${2}" -eq "99" ]]; then
if [[ -n "${3}" ]]; then
# E.g: meson-gxl-s905d-phicomm-n1.dtb:s905d:u-boot-n1.bin
SPECIFY_DTB="$(echo "${3}" | awk -F ':' '{print $1}')"
SPECIFY_SOC="$(echo "${3}" | awk -F ':' '{print $2}')"
SPECIFY_UBOOT="$(echo "${3}" | awk -F ':' '{print $3}')"
else
error_msg "Please enter the DTB file name!"
fi
fi
}
# shared partition can be ext4, xfs, btrfs, f2fs
SHARED_FSTYPE="${4}"
echo "AUTO_MAINLINE_UBOOT: ${AUTO_MAINLINE_UBOOT}"
echo "SPECIFY_DTB: ${SPECIFY_DTB}"
echo "SPECIFY_SOC: ${SPECIFY_SOC}"
echo "SPECIFY_UBOOT: ${SPECIFY_UBOOT}"
echo "SHARED_FSTYPE: ${SHARED_FSTYPE}"
# Current device model
MYDEVICE_NAME=$(cat /proc/device-tree/model | tr -d '\000')
if [[ -z "${MYDEVICE_NAME}" ]]; then
error_msg "The device name is empty and cannot be recognized."
elif [[ ! -f "${op_release}" ]]; then
error_msg "The [ ${op_release} ] file is missing."
else
echo -e "Current device: ${MYDEVICE_NAME} [ amlogic ]"
sleep 3
fi
# Find the device name of /
root_devname="$(get_root_partition_name)"
if lsblk -l | grep -E "^${root_devname}boot0" >/dev/null; then
error_msg "you are running in emmc mode, please boot system with usb or tf card!"
fi
install_emmc="$(lsblk -l -o NAME | grep -oE '(mmcblk[0-9]?boot0)' | sed "s/boot0//g")"
if [[ "${install_emmc}" == "" ]]; then
error_msg "No emmc can be found to install the openwrt system!"
fi
# EMMC DEVICE NAME
EMMC_NAME="${install_emmc}"
EMMC_DEVPATH="/dev/${EMMC_NAME}"
echo ${EMMC_DEVPATH}
EMMC_SIZE=$(lsblk -l -b -o NAME,SIZE | grep ${EMMC_NAME} | sort | uniq | head -n1 | awk '{print $2}')
echo "${EMMC_NAME} : ${EMMC_SIZE} bytes"
ROOT_NAME=$(lsblk -l -o NAME,MAJ:MIN,MOUNTPOINT | grep -e '/$' | awk '{print $1}')
echo "ROOTFS: ${ROOT_NAME}"
BOOT_NAME=$(lsblk -l -o NAME,MAJ:MIN,MOUNTPOINT | grep -e '/boot$' | awk '{print $1}')
echo "BOOT: ${BOOT_NAME}"
# box model database
# The field separator is :
# " " or "" or NA or NULL means this field is null
# The fields list:
# 1. id
# 2. model name
# 3. SOC
# 4. FDTFILE
# 5. UBOOT_OVERLOAD
# 6. MAINLINE_UBOOT
# 7. ANDROID_UBOOT
# 8. brief description
#
# allow use external modal database
if [[ -f "/etc/model_database.txt" ]]; then
model_database="$(cat /etc/model_database.txt)"
else
error_msg "[ /etc/model_database.txt ] file is missing."
fi
function display_database() {
while read -r line; do
if [[ "$line" =~ ^# ]]; then
# Process comment lines, starting with #
line="${line/#+\s+/}"
echo "$line >>>"
else
# Process data lines, starting with id
IFS=':' read -r -a fields <<<"$line"
printf "%5s %-48s%-10s%-s\n" "${fields[0]}" "${fields[1]}" "${fields[2]}" "${fields[7]}"
fi
done < <(echo "${model_database}")
}
function search_model() {
local id="${1}"
local ret_count="$(echo "${model_database}" | awk -F ':' "\$1~/^$id\$/ {print \$0}" | wc -l)"
if [[ "${ret_count}" -eq "1" ]]; then
echo "${model_database}" | awk -F ':' "\$1~/^$id\$/ {print \$0}" | sed -e 's/NA//g' -e 's/NULL//g' -e 's/[ ][ ]*//g'
fi
}
echo "Please select s9xxx box model:"
echo "----------------------------------------------------------------------------------------------------"
display_database
echo "----------------------------------------------------------------------------------------------------"
# For [luci-app-amlogic] input parameter: SOC & DTB
# When there is no input parameter, select manually
if [[ -n "${SPECIFY_ID}" ]]; then
boxtype="${SPECIFY_ID}"
else
echo -n "Please choose: "
read boxtype
fi
if [[ "${boxtype}" -eq "99" ]]; then
FDTFILE="${SPECIFY_DTB}"
AMLOGIC_SOC="${SPECIFY_SOC}"
UBOOT_OVERLOAD="${SPECIFY_UBOOT}"
MAINLINE_UBOOT=""
ANDROID_UBOOT=""
elif [[ "${boxtype}" -eq "0" ]]; then
read -p "Please Input SoC Name(such as s9xxx): " AMLOGIC_SOC
AMLOGIC_SOC="${AMLOGIC_SOC}"
read -p "Please Input DTB Name(such as meson-xxx.dtb): " FDTFILE
FDTFILE="${FDTFILE}"
read -p "Please Input UBOOT_OVERLOAD Name(such as u-boot-xxx.bin): " UBOOT_OVERLOAD
UBOOT_OVERLOAD="${UBOOT_OVERLOAD}"
read -p "Please Input MAINLINE_UBOOT Name(such as /lib/u-boot/xxx-u-boot.bin.sd.bin): " MAINLINE_UBOOT
MAINLINE_UBOOT="${MAINLINE_UBOOT}"
read -p "Please Input ANDROID_UBOOT Name(such as /lib/u-boot/xxx-bootloader.img): " ANDROID_UBOOT
ANDROID_UBOOT="${ANDROID_UBOOT}"
else
ret="$(search_model ${boxtype})"
if [[ -z "${ret}" ]]; then
error_msg "Input error, exit!"
fi
# 3. soc
# 4. FDTFILE
# 5. UBOOT_OVERLOAD
# 6. MAINLINE_UBOOT
# 7. ANDROID_UBOOT
AMLOGIC_SOC="$(echo "${ret}" | awk -F ':' '{print $3}')"
FDTFILE="$(echo "${ret}" | awk -F ':' '{print $4}')"
UBOOT_OVERLOAD="$(echo "${ret}" | awk -F ':' '{print $5}')"
MAINLINE_UBOOT="$(echo "${ret}" | awk -F ':' '{print $6}')"
ANDROID_UBOOT="$(echo "${ret}" | awk -F ':' '{print $7}')"
fi
if [[ -z "${FDTFILE}" || ! -f "/boot/dtb/amlogic/${FDTFILE}" ]]; then
error_msg "/boot/dtb/amlogic/${FDTFILE} does not exist!"
fi
echo "AMLOGIC_SOC Value [ ${AMLOGIC_SOC} ]"
echo "FDTFILE Value [ ${FDTFILE} ]"
echo "UBOOT_OVERLOAD Value [ ${UBOOT_OVERLOAD} ]"
echo "MAINLINE_UBOOT Value [ ${MAINLINE_UBOOT} ]"
echo "ANDROID_UBOOT Value [ ${ANDROID_UBOOT} ]"
sed -i "s|^SOC=.*|SOC='${AMLOGIC_SOC}'|g" ${op_release} 2>/dev/null
sed -i "s|^FDTFILE=.*|FDTFILE='${FDTFILE}'|g" ${op_release} 2>/dev/null
sed -i "s|^UBOOT_OVERLOAD=.*|UBOOT_OVERLOAD='${UBOOT_OVERLOAD}'|g" ${op_release} 2>/dev/null
sed -i "s|^MAINLINE_UBOOT=.*|MAINLINE_UBOOT='${MAINLINE_UBOOT}'|g" ${op_release} 2>/dev/null
sed -i "s|^ANDROID_UBOOT=.*|ANDROID_UBOOT='${ANDROID_UBOOT}'|g" ${op_release} 2>/dev/null
K510="1"
[[ "$(hexdump -n 15 -x "/boot/zImage" 2>/dev/null | head -n 1 | awk '{print $7}')" == "0108" ]] && K510="0"
echo -e "K510 [ ${K510} ]"
# backup old bootloader
if [[ ! -f "/root/BackupOldBootloader.img" ]]; then
echo "Backup bootloader -> [ BackupOldBootloader.img ] ... "
dd if=/dev/$EMMC_NAME of=/root/BackupOldBootloader.img bs=1M count=4 conv=fsync
echo "Backup bootloader complete."
echo
fi
swapoff -a
# umount all other mount points
MOUNTS=$(lsblk -l -o MOUNTPOINT)
for mnt in $MOUNTS; do
if [ "$mnt" == "MOUNTPOINT" ]; then
continue
fi
if [ "$mnt" == "" ]; then
continue
fi
if [ "$mnt" == "/" ]; then
continue
fi
if [ "$mnt" == "/boot" ]; then
continue
fi
if [ "$mnt" == "/opt" ]; then
continue
fi
if [ "$mnt" == "[SWAP]" ]; then
echo "swapoff -a"
swapoff -a
continue
fi
if echo $mnt | grep $EMMC_NAME; then
echo "umount -f $mnt"
umount -f $mnt
if [ $? -ne 0 ]; then
error_msg "$mnt Cannot be uninstalled, the installation process is aborted."
fi
fi
done
# Delete old partition if exists
p=$(lsblk -l | grep -e "${EMMC_NAME}p" | wc -l)
echo "A total of [ $p ] old partitions on EMMC will be deleted"
>/tmp/fdisk.script
while [ $p -ge 1 ]; do
echo "d" >>/tmp/fdisk.script
if [ $p -gt 1 ]; then
echo "$p" >>/tmp/fdisk.script
fi
p=$((p - 1))
done
# you can change ROOT size(MB) >= 320
ROOT1="2048"
ROOT2="2048"
if [[ "${AMLOGIC_SOC}" == "s912" ]] && [[ "${boxtype}" == "213" || "${boxtype}" == "2e" ]]; then
BOOT="512"
BLANK1="700"
BLANK2="220"
BLANK3="0"
BLANK4="0"
elif [[ "${AMLOGIC_SOC}" == "s912" || "${AMLOGIC_SOC}" == "s905d" ]]; then
BOOT="512"
BLANK1="68"
BLANK2="220"
BLANK3="0"
BLANK4="0"
elif [[ "${AMLOGIC_SOC}" == "s905x" ]]; then
BOOT="160"
BLANK1="700"
BLANK2="0"
BLANK3="0"
BLANK4="0"
elif [[ "${FDTFILE}" == "meson-sm1-skyworth-lb2004-a4091.dtb" ]]; then
BOOT="512"
BLANK1="108"
BLANK2="562"
BLANK3="0"
BLANK4="0"
elif [[ "${AMLOGIC_SOC}" == "s905l3a" ]] && [[ "${boxtype}" == "304" || "${boxtype}" == "34" ]]; then
# e900v22c/d(s905l3a)
BOOT="256"
BLANK1="570"
BLANK2="0"
BLANK3="0"
BLANK4="0"
elif [[ "${AMLOGIC_SOC}" == "s905l3a" ]] && [[ "${boxtype}" == "305" || "${boxtype}" == "33" ]]; then
# CM311-1a-YST(s905l3a)
BOOT="512"
BLANK1="108"
BLANK2="778"
BLANK3="0"
BLANK4="0"
elif [[ "${AMLOGIC_SOC}" == "s905l3b" ]]; then
# M302A/M304A(s905l3b)
BOOT="512"
BLANK1="128"
BLANK2="720"
BLANK3="0"
BLANK4="0"
elif [[ "${AMLOGIC_SOC}" == "s905x3" ]] && [[ "${boxtype}" == "525" || "${boxtype}" == "5n" ]]; then
# Whale(s905x3)
BOOT="512"
BLANK1="108"
BLANK2="650"
BLANK3="0"
BLANK4="0"
elif [[ "${boxtype}" =~ ^(409|410|49|4a)$ ]]; then
# WXY-OES(A311D):409/49, WXY-OES-PLUS(S922X):410/4a
BOOT="512"
BLANK1="700"
BLANK2="0"
BLANK3="0"
BLANK4="0"
else
BOOT="160"
BLANK1="68"
BLANK2="0"
BLANK3="162"
BLANK4="0"
fi
DST_TOTAL_MB=$((EMMC_SIZE / 1024 / 1024))
start1=$((BLANK1 * 2048))
end1=$((start1 + (BOOT * 2048) - 1))
start2=$(((BLANK2 * 2048) + end1 + 1))
end2=$((start2 + (ROOT1 * 2048) - 1))
start3=$(((BLANK3 * 2048) + end2 + 1))
end3=$((start3 + (ROOT2 * 2048) - 1))
start4=$(((BLANK4 * 2048) + end3 + 1))
end4=$((DST_TOTAL_MB * 2048 - 1))
cat >>/tmp/fdisk.script <<EOF
n
p
1
$start1
$end1
n
p
2
$start2
$end2
n
p
3
$start3
$end3
n
p
$start4
$end4
t
1
c
t
2
83
t
3
83
t
4
83
w
EOF
fdisk /dev/${EMMC_NAME} </tmp/fdisk.script 2>/dev/null
if [ $? -ne 0 ]; then
echo "The fdisk partition fails, Please try again."
dd if=/root/BackupOldBootloader.img of=/dev/${EMMC_NAME} conv=fsync && sync
dd if=/dev/zero of=/dev/${EMMC_NAME} bs=512 count=1 && sync
exit 1
fi
echo "Partition complete."
# write some zero data to part begin
seek=$((start1 / 2048))
dd if=/dev/zero of=/dev/${EMMC_NAME} bs=1M count=1 seek=$seek conv=fsync
seek=$((start2 / 2048))
dd if=/dev/zero of=/dev/${EMMC_NAME} bs=1M count=1 seek=$seek conv=fsync
seek=$((start3 / 2048))
dd if=/dev/zero of=/dev/${EMMC_NAME} bs=1M count=1 seek=$seek conv=fsync
seek=$((start4 / 2048))
dd if=/dev/zero of=/dev/${EMMC_NAME} bs=1M count=1 seek=$seek conv=fsync
#Mainline U-BOOT detection
FLASH_MAINLINE_UBOOT=0
if [[ -n "${MAINLINE_UBOOT}" && -f "${MAINLINE_UBOOT}" ]]; then
cat <<EOF
----------------------------------------------------------------------------------
Found an available mainline bootloader (Mainline u-boot), you can flash into EMMC.
----------------------------------------------------------------------------------
EOF
while :; do
# For [luci-app-amlogic] input parameter: SOC & DTB
# When there is no input parameter, select manually
if [[ "${AUTO_MAINLINE_UBOOT}" == "yes" ]]; then
if [[ "${K510}" -eq "1" ]]; then
yn="y"
else
yn="n"
fi
elif [[ "${AUTO_MAINLINE_UBOOT}" == "no" ]]; then
yn="n"
else
read -p "Please choose whether to write the mainline bootloader to EMMC? y/n " yn
fi
case $yn in
y | Y)
FLASH_MAINLINE_UBOOT=1
break
;;
n | N)
FLASH_MAINLINE_UBOOT=0
break
;;
esac
done
fi
if [[ "${FLASH_MAINLINE_UBOOT}" -eq "1" ]]; then
echo -e "Write Mainline bootloader: [ ${MAINLINE_UBOOT} ]"
dd if=${MAINLINE_UBOOT} of=/dev/${EMMC_NAME} bs=1 count=444 conv=fsync
dd if=${MAINLINE_UBOOT} of=/dev/${EMMC_NAME} bs=512 skip=1 seek=1 conv=fsync
elif [[ -n "${ANDROID_UBOOT}" && -f "${ANDROID_UBOOT}" ]]; then
echo -e "Write Android bootloader: [ ${ANDROID_UBOOT} ]"
dd if=${ANDROID_UBOOT} of=/dev/${EMMC_NAME} bs=1 count=444 conv=fsync
dd if=${ANDROID_UBOOT} of=/dev/${EMMC_NAME} bs=512 skip=1 seek=1 conv=fsync
else
echo "Did not change the original bootloader."
fi
# fix wifi macaddr
if [ -x /usr/bin/fix_wifi_macaddr.sh ]; then
/usr/bin/fix_wifi_macaddr.sh
fi
# mkfs
echo "Start creating file system ... "
echo "Create a boot file system ... "
echo "format boot partiton..."
mkfs.fat -n EMMC_BOOT -F 32 /dev/${EMMC_NAME}p1
mkdir -p /mnt/${EMMC_NAME}p1
sleep 2
umount -f /mnt/${EMMC_NAME}p1 2>/dev/null
echo "format rootfs1 partiton..."
ROOTFS1_UUID=$(/usr/bin/uuidgen)
mkfs.btrfs -f -U ${ROOTFS1_UUID} -L EMMC_ROOTFS1 -m single /dev/${EMMC_NAME}p2
mkdir -p /mnt/${EMMC_NAME}p2
sleep 2
umount -f /mnt/${EMMC_NAME}p2 2>/dev/null
echo "format rootfs2 partiton..."
ROOTFS2_UUID=$(/usr/bin/uuidgen)
mkfs.btrfs -f -U ${ROOTFS2_UUID} -L EMMC_ROOTFS2 -m single /dev/${EMMC_NAME}p3
mkdir -p /mnt/${EMMC_NAME}p3
sleep 2
umount -f /mnt/${EMMC_NAME}p3 2>/dev/null
# mount and copy
echo "Wait for the boot file system to mount ... "
i=1
max_try=10
while [ $i -le $max_try ]; do
mount -t vfat /dev/${EMMC_NAME}p1 /mnt/${EMMC_NAME}p1 2>/dev/null
sleep 2
mnt=$(lsblk -l -o MOUNTPOINT | grep /mnt/${EMMC_NAME}p1)
if [ "$mnt" == "" ]; then
if [ $i -lt $max_try ]; then
echo "Not mounted successfully, try again ..."
i=$((i + 1))
else
error_msg "Cannot mount the boot file system, give up!"
fi
else
echo "Successfully mounted."
echo "copy boot ..."
cd /mnt/${EMMC_NAME}p1
rm -rf /boot/'System Volume Information/'
(cd /boot && tar cf - .) | tar xf -
sync
echo "Edit uEnv.txt ..."
[[ -f "uEnv.txt" ]] && {
sed -i -E \
-e "s|/dtb/amlogic.*|/dtb/amlogic/${FDTFILE}|" \
-e "s|UUID=[^ ]*|UUID=${ROOTFS1_UUID}|" \
-e "s|rootflags=compress=zstd:[^ ]*|rootflags=compress=zstd:${ZSTD_LEVEL}|" \
uEnv.txt
}
# Replace the extlinux/extlinux.conf if it exists
[[ -f "extlinux/extlinux.conf" ]] && {
sed -i -E \
-e "s|/dtb/amlogic.*|/dtb/amlogic/${FDTFILE}|" \
-e "s|UUID=[^ ]*|UUID=${ROOTFS1_UUID}|" \
-e "s|rootflags=compress=zstd:[^ ]*|rootflags=compress=zstd:${ZSTD_LEVEL}|" \
extlinux/extlinux.conf
}
rm -f s905_autoscript* aml_autoscript*
if [ ${K510} -eq 1 ]; then
if [ -f ${UBOOT_OVERLOAD} ]; then
cp -f -v ${UBOOT_OVERLOAD} u-boot.emmc
elif [ -f "u-boot.ext" ]; then
cp -f -v u-boot.ext u-boot.emmc
fi
fi
mv -f boot-emmc.ini boot.ini
mv -f boot-emmc.cmd boot.cmd
mv -f boot-emmc.scr boot.scr
sync
echo "complete."
cd /
umount -f /mnt/${EMMC_NAME}p1
break
fi
done
echo "complete."
echo "Wait for the rootfs file system to mount ... "
i=1
while [ $i -le $max_try ]; do
mount -t btrfs -o compress=zstd:${ZSTD_LEVEL} /dev/${EMMC_NAME}p2 /mnt/${EMMC_NAME}p2 2>/dev/null
sleep 2
mnt=$(lsblk -l -o MOUNTPOINT | grep /mnt/${EMMC_NAME}p2)
if [ "$mnt" == "" ]; then
if [ $i -lt $max_try ]; then
echo "Not mounted successfully, try again ..."
i=$((i + 1))
else
error_msg "Cannot mount rootfs file system, give up!"
fi
else
echo "Successfully mounted"
echo "Create folder ... "
cd /mnt/${EMMC_NAME}p2
btrfs subvolume create etc
mkdir -p bin boot dev lib opt mnt overlay proc rom root run sbin sys tmp usr www .reserved .snapshots
ln -sf lib/ lib64
ln -sf tmp/ var
sync
echo "complete."
COPY_SRC="root etc bin sbin lib opt usr www"
echo "Copy data ... "
for src in $COPY_SRC; do
echo "copy [ $src ] ..."
(cd / && tar cf - $src) | tar xf -
sync
done
echo "Copy complete."
sync
cat >etc/docker/daemon.json <<EOF
{
"bip": "172.31.0.1/24",
"data-root": "/mnt/${EMMC_NAME}p4/docker/",
"log-level": "warn",
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "5"
},
"registry-mirrors": [
"https://mirror.baidubce.com/",
"https://hub-mirror.c.163.com"
]
}
EOF
# change data_root value in /etc/config/dockerd
if [[ -f "/etc/init.d/dockerman" ]] && [[ -f "/etc/config/dockerd" ]]; then
sed -i "s|option data_root.*|option data_root '/mnt/${EMMC_NAME}p4/docker/'|g" etc/config/dockerd
fi
rm -rf opt/docker && ln -sf /mnt/${EMMC_NAME}p4/docker/ opt/docker >/dev/null
rm -rf usr/bin/AdGuardHome && ln -sf /mnt/${EMMC_NAME}p4/AdGuardHome usr/bin/ >/dev/null
echo "Edit configuration file ..."
#cd /mnt/${EMMC_NAME}p2/usr/bin/
#rm -f openwrt-install-amlogic openwrt-update-amlogic
cd /mnt/${EMMC_NAME}p2/etc/rc.d
ln -sf ../init.d/dockerd S99dockerd
rm -f S??shortcut-fe
if grep "sfe_flow '1'" ../config/turboacc >/dev/null; then
if find ../../lib/modules -name 'shortcut-fe-cm.ko'; then
ln -sf ../init.d/shortcut-fe S99shortcut-fe
fi
fi
cd /mnt/${EMMC_NAME}p2/etc
cat >fstab <<EOF
UUID=${ROOTFS1_UUID} / btrfs compress=zstd:${ZSTD_LEVEL} 0 1
LABEL=EMMC_BOOT /boot vfat defaults 0 2
#tmpfs /tmp tmpfs defaults,nosuid 0 0
EOF
cd /mnt/${EMMC_NAME}p2/etc/config
cat >fstab <<EOF
config global
option anon_swap '0'
option anon_mount '1'
option auto_swap '0'
option auto_mount '1'
option delay_root '5'
option check_fs '0'
config mount
option target '/rom'
option uuid '${ROOTFS1_UUID}'
option enabled '1'
option enabled_fsck '1'
option fstype 'btrfs'
option options 'compress=zstd:${ZSTD_LEVEL}'
config mount
option target '/boot'
option label 'EMMC_BOOT'
option enabled '1'
option enabled_fsck '1'
option fstype 'vfat'
EOF
echo -n "Create initial etc snapshot -> .snapshots/etc-000"
cd /mnt/${EMMC_NAME}p2 &&
btrfs subvolume snapshot -r etc .snapshots/etc-000
sync
cd /
umount -f /mnt/${EMMC_NAME}p2
break
fi
done
echo "complete."
echo "Create a shared file system."
mkdir -p /mnt/${EMMC_NAME}p4
# When there is no input parameter, select manually
if [[ -n "${SHARED_FSTYPE}" ]]; then
TARGET_SHARED_FSTYPE=${SHARED_FSTYPE}
else
cat <<EOF
---------------------------------------------------------------------------------
Please select the type of shared file system:
1. ext4: [Default options] suitable for general use.
2. btrfs: Which can extend the service life of ssd/mmc.
3. f2fs: Fast reading and writing speed, but the compatibility is slightly poor.
4. xfs: Very good file system, alternative to ext4.
---------------------------------------------------------------------------------
EOF
read -p "Please Input ID: " TARGET_SHARED_FSTYPE
fi
case $TARGET_SHARED_FSTYPE in
2 | btrfs)
mkfs.btrfs -f -L EMMC_SHARED -m single /dev/${EMMC_NAME}p4 >/dev/null
mount -t btrfs /dev/${EMMC_NAME}p4 /mnt/${EMMC_NAME}p4
;;
3 | f2fs)
mkfs.f2fs -f -l EMMC_SHARED /dev/${EMMC_NAME}p4 >/dev/null
mount -t f2fs /dev/${EMMC_NAME}p4 /mnt/${EMMC_NAME}p4
;;
4 | xfs)
mkfs.xfs -f -L EMMC_SHARED /dev/${EMMC_NAME}p4 >/dev/null
mount -t xfs /dev/${EMMC_NAME}p4 /mnt/${EMMC_NAME}p4
;;
*)
mkfs.ext4 -F -L EMMC_SHARED /dev/${EMMC_NAME}p4 >/dev/null
mount -t ext4 /dev/${EMMC_NAME}p4 /mnt/${EMMC_NAME}p4
;;
esac
mkdir -p /mnt/${EMMC_NAME}p4/docker /mnt/${EMMC_NAME}p4/AdGuardHome/data
sync
echo "Successful installed, please unplug the USB, re-insert the power supply to start the openwrt."
exit 0
+516
View File
@@ -0,0 +1,516 @@
#!/bin/bash
#====================================================================================
#
# Function: Update the kernel for OpenWrt (Amlogic s9xxx, Allwinner, Rockchip)
# Copyright (C) 2020-- https://github.com/unifreq/openwrt_packit
# Copyright (C) 2021-- https://github.com/ophub/luci-app-amlogic
#
# Support the kernel: boot-*.tar.gz, dtb-*.tar.gz, modules-*.tar.gz
# It is recommended to install MAINLINE_UBOOT for kernel versions above 5.10.y
# openwrt-kernel ${AUTO_MAINLINE_UBOOT}
# E.g: openwrt-kernel yes
# openwrt-kernel no
#
#================================== Functions list ==================================
#
# error_msg : Output error message
# get_textoffset : Get kernel TEXT_OFFSET
# init_var : Initialize all variables
# check_kernel : Check kernel files list
# chech_files_same : Check file consistency
# restore_kernel : Restore current kernel
# update_kernel : Update the kernel
# update_uboot : Update the uboot
#
#============================== Set default parameters ==============================
#
# Receive one-key command related parameters
AUTO_MAINLINE_UBOOT="no"
# Set the release check file
release_file="/etc/flippy-openwrt-release"
#
#====================================================================================
# Encountered a serious error, abort the script execution
error_msg() {
echo -e "[Error] ${1}"
exit 1
}
# Get the partition name of the /boot file system
get_boot_partition_name() {
local paths="/boot"
local partition_name
partition_name=$(df "${paths}" | awk 'NR==2 {print $1}' | awk -F '/' '{print $3}')
echo "${partition_name}"
}
# Get the partition name of the root file system
get_root_partition_name() {
local paths=("/" "/overlay" "/rom")
local partition_name
for path in "${paths[@]}"; do
partition_name=$(df "${path}" | awk 'NR==2 {print $1}' | awk -F '/' '{print $3}')
[[ -n "${partition_name}" ]] && break
done
echo "${partition_name}"
}
# Get kernel TEXT_OFFSET, For u-boot.ext and u-boot.emmc
get_textoffset() {
boot_tgz_file="${1}"
vmlinuz_name="${2}"
K510="1"
temp_dir="$(mktemp -d)"
(
cd ${temp_dir}
tar -xf "${boot_tgz_file}" "${vmlinuz_name}"
)
# With TEXT_OFFSET patch is [ 0108 ], without TEXT_OFFSET patch is [ 0000 ]
[[ "$(hexdump -n 15 -x "${temp_dir}/${vmlinuz_name}" 2>/dev/null | head -n 1 | awk '{print $7}')" == "0108" ]] && K510="0"
}
init_var() {
# Receive one-key command related parameters
[[ "${1}" == "yes" ]] && AUTO_MAINLINE_UBOOT="yes"
# Check dependencies
[[ -n "$(busybox which tar)" ]] || error_msg "Missing [ tar ] in OpenWrt firmware, unable to update kernel"
# Check release file
if [[ -s "${release_file}" ]]; then
source "${release_file}"
PLATFORM="${PLATFORM}"
MODEL_ID="${MODEL_ID}"
UBOOT_OVERLOAD="${UBOOT_OVERLOAD}"
MAINLINE_UBOOT="${MAINLINE_UBOOT}"
ANDROID_UBOOT="${ANDROID_UBOOT}"
SOC="${SOC}"
LOCK_KERNEL="${LOCK_KERNEL}"
else
error_msg "${release_file} file is missing!"
fi
[[ -n "${PLATFORM}" ]] || error_msg "Missing ${PLATFORM} value in ${release_file} file."
# Define supported platforms
support_platform=("allwinner" "rockchip" "amlogic" "qemu-aarch64")
[[ -n "$(echo "${support_platform[@]}" | grep -w "${PLATFORM}")" ]] || error_msg "[ ${PLATFORM} ] is not supported."
# Check and repair partition mount points
[[ -z "$(get_boot_partition_name)" || -z "$(get_root_partition_name)" ]] && {
echo -e "Partition mount point error, start repairing..."
openwrt-backup -g
}
# Set /boot/vmlinuz-* replication names for different SoCs
MYBOOT_VMLINUZ="$(ls -l /boot/*Image 2>/dev/null | awk '{print $9}' | head -n 1)"
MYBOOT_VMLINUZ="${MYBOOT_VMLINUZ##*/}"
[[ -n "${MYBOOT_VMLINUZ}" ]] || error_msg "Failed to get Image name: [ ${MYBOOT_VMLINUZ} ]"
# Find the partition where root is located
ROOT_PTNAME="$(get_root_partition_name)"
# Find the disk where the partition is located, only supports mmcblk?p? sd?? hd?? vd?? and other formats
case "${ROOT_PTNAME}" in
mmcblk?p[1-9])
EMMC_NAME="$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-2)}')"
PARTITION_NAME="p"
;;
[hsv]d[a-z][1-9])
EMMC_NAME="$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-1)}')"
PARTITION_NAME=""
;;
nvme?n?p[1-9])
EMMC_NAME="$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-2)}')"
PARTITION_NAME="p"
;;
*)
error_msg "Unable to recognize the disk type of ${ROOT_PTNAME}!"
;;
esac
P4_PATH="/mnt/${EMMC_NAME}${PARTITION_NAME}4"
# Move kernel related files to the ${P4_PATH} directory
mv -f /tmp/upload/* ${P4_PATH} 2>/dev/null
# Current device model
MYDEVICE_NAME="$(cat /proc/device-tree/model | tr -d '\000')"
[[ "${PLATFORM}" == "qemu-aarch64" ]] && MYDEVICE_NAME="KVM Virtual Machine"
echo -e "Current device: ${MYDEVICE_NAME} [ ${PLATFORM} ], Use in [ ${EMMC_NAME} ]"
sync && echo ""
}
# Check kernel files list
check_kernel() {
cd ${P4_PATH}
# Determine custom kernel filename
kernel_boot="$(ls boot-*.tar.gz 2>/dev/null | head -n 1)"
kernel_name="${kernel_boot:5:-7}"
KERNEL_VERSION="$(echo ${kernel_name} | grep -oE '^[1-9].[0-9]{1,3}.[0-9]+')"
echo -e "Kernel name: ${kernel_name}"
# check if kernel is locked
if [ -n "${LOCK_KERNEL}" ]; then
if [ "${LOCK_KERNEL}" != "${kernel_name}" ]; then
if ! echo "${kernel_name}" | grep -E '^5.10.\d+-.*?rk35.*?$' >/dev/null; then
error_msg "The kernel version is locked to [ ${LOCK_KERNEL} ], but your kernel is [ ${kernel_name} ]. "
fi
fi
fi
# Check if the file is added with TEXT_OFFSET patch
get_textoffset "${P4_PATH}/${kernel_boot}" "vmlinuz-${kernel_name}"
echo -e "K510 [ ${K510} ]"
if [[ "${PLATFORM}" == "amlogic" && "${K510}" -eq "1" ]]; then
[[ -n "${UBOOT_OVERLOAD}" && -f "/boot/${UBOOT_OVERLOAD}" ]] || error_msg "The UBOOT_OVERLOAD file is missing and cannot be update."
fi
# Check the sha256sums file
sha256sums_file="sha256sums"
sha256sums_check="1"
[[ -s "${sha256sums_file}" && -n "$(cat ${sha256sums_file})" ]] || sha256sums_check="0"
[[ -n "$(busybox which sha256sum)" ]] || sha256sums_check="0"
[[ "${sha256sums_check}" -eq "1" ]] && echo -e "Enable sha256sum checking..."
# Loop check file
i="1"
if [[ "${PLATFORM}" == "qemu-aarch64" ]]; then
kernel_list=("boot" "modules")
else
kernel_list=("boot" "dtb-${PLATFORM}" "modules")
fi
for kernel_file in ${kernel_list[*]}; do
# Set check filename
tmp_file="${kernel_file}-${kernel_name}.tar.gz"
# Check if file exists
[[ -s "${tmp_file}" ]] || error_msg "The [ ${kernel_file} ] file is missing."
# Check if the file sha256sum is correct
if [[ "${sha256sums_check}" -eq "1" ]]; then
tmp_sha256sum="$(sha256sum "${tmp_file}" | awk '{print $1}')"
tmp_checkcode="$(cat ${sha256sums_file} | grep ${tmp_file} | awk '{print $1}')"
[[ "${tmp_sha256sum}" == "${tmp_checkcode}" ]] || error_msg "${tmp_file}: sha256sum verification failed."
echo -e "(${i}/3) [ ${tmp_file} ] file sha256sum check same."
fi
let i++
done
sync && echo ""
}
# Check the consistency of amlogic device files
chech_files_same() {
i="0"
max_try="5"
while [[ "${i}" -le "${max_try}" ]]; do
if [[ "$(sha256sum "${1}" | awk '{print $1}')" == "$(sha256sum "${2}" | awk '{print $1}')" ]]; then
echo "" && break
else
cp -f ${1} ${2}
i="$((i + 1))"
fi
done
[[ "${i}" -gt "${max_try}" ]] && echo "God, it's different after ${max_try} copies: [ ${1} ]"
}
# Restore the kernel when the update fails
restore_kernel() {
(
cd /boot
rm -rf \
config-${kernel_name} \
System.map-${kernel_name} \
initrd.img-${kernel_name} \
uInitrd-${kernel_name} \
vmlinuz-${kernel_name} \
initrd.img \
uInitrd \
zImage \
Image \
vmlinuz \
dtb* 2>/dev/null
tar -xzf /tmp/boot-backup.tar.gz 2>/dev/null
)
error_msg "Kernel update failed and has been reverted."
}
# Update the kernel
update_kernel() {
local cur_kernel_name=$(uname -r)
local boot_fstype=$(df -T /boot | tail -n1 | awk '{print $2}')
echo -e "Start unpacking the kernel..."
# 01. for /boot five files
# Backup the current_kernel
(
cd /boot
tar -czf /tmp/boot-backup.tar.gz \
config-${cur_kernel_name} \
System.map-${cur_kernel_name} \
initrd.img-${cur_kernel_name} \
uInitrd-${cur_kernel_name} \
vmlinuz-${cur_kernel_name} \
initrd.img \
uInitrd \
zImage \
Image \
vmlinuz \
dtb* 2>/dev/null
rm -rf \
config-${cur_kernel_name} \
System.map-${cur_kernel_name} \
initrd.img-${cur_kernel_name} \
uInitrd-${cur_kernel_name} \
vmlinuz-${cur_kernel_name} \
initrd.img \
uInitrd \
zImage \
Image \
vmlinuz \
dtb* 2>/dev/null
)
# Extract the new kernel
tar -xf ${P4_PATH}/boot-${kernel_name}.tar.gz -C /boot
# Check if the file exists
local valid_files
if [[ "${PLATFORM}" == "qemu-aarch64" ]]; then
valid_files="vmlinuz-${kernel_name} initrd.img-${kernel_name} config-${kernel_name} System.map-${kernel_name}"
rm -f /boot/uInitrd*
else
valid_files="vmlinuz-${kernel_name} uInitrd-${kernel_name} config-${kernel_name} System.map-${kernel_name}"
# wxy-oect: MODEL_ID numbers r304,r306 and w[0-9]{3}, require special handling of uInitrd
[[ "${MODEL_ID}" =~ ^(r304|r306|w[0-9]{3})$ ]] || rm -f /boot/initrd.img*
fi
for f in ${valid_files}; do [[ -f "/boot/${f}" ]] || restore_kernel; done
# Check if the files are the same
(
cd /boot
if [[ "${PLATFORM}" == "qemu-aarch64" ]]; then
ln -sf initrd.img-${kernel_name} initrd.img
ln -sf vmlinuz-${kernel_name} ${MYBOOT_VMLINUZ}
elif [[ "$boot_fstype" == "vfat" ]]; then
cp -f uInitrd-${kernel_name} uInitrd
[[ -z "$(chech_files_same uInitrd-${kernel_name} uInitrd)" ]] || restore_kernel
cp -f vmlinuz-${kernel_name} ${MYBOOT_VMLINUZ}
[[ -z "$(chech_files_same vmlinuz-${kernel_name} ${MYBOOT_VMLINUZ})" ]] || restore_kernel
else
ln -sf uInitrd-${kernel_name} uInitrd
ln -sf vmlinuz-${kernel_name} ${MYBOOT_VMLINUZ}
fi
# wxy-oect: MODEL_ID numbers r304 and r306, require special handling of uInitrd
[[ "${MODEL_ID}" =~ ^(r304|r306)$ ]] && ln -sf initrd.img-${kernel_name} uInitrd
)
echo -e "(1/3) Unpacking [ boot-${kernel_name}.tar.gz ] done."
if [[ "${PLATFORM}" == "qemu-aarch64" ]]; then
echo -e "(2/3) skip unpack dtb files."
else
# 02. for /boot/dtb/${PLATFORM}/*
if [[ "${boot_fstype}" == "vfat" ]]; then
(cd /boot && mkdir -p dtb/${PLATFORM})
else
(cd /boot && mkdir -p dtb-${kernel_name}/${PLATFORM} && ln -sf dtb-${kernel_name} dtb)
fi
tar -xf ${P4_PATH}/dtb-${PLATFORM}-${kernel_name}.tar.gz -C /boot/dtb/${PLATFORM}
[[ "$(ls /boot/dtb/${PLATFORM} -l 2>/dev/null | grep "^-" | wc -l)" -ge "1" ]] || error_msg "/boot/dtb/${PLATFORM} file is missing."
echo -e "(2/3) Unpacking [ dtb-${PLATFORM}-${kernel_name}.tar.gz ] done."
fi
# 03. for /lib/modules/*
rm -rf /lib/modules/*
tar -xf ${P4_PATH}/modules-${kernel_name}.tar.gz -C /lib/modules
(
cd /lib/modules/${kernel_name}
rm -f *.ko
find ./ -type f -name '*.ko' -exec ln -s {} ./ \;
sync && sleep 3
x=$(ls *.ko -l 2>/dev/null | grep "^l" | wc -l)
[[ "${x}" -eq "0" ]] && error_msg "Error *.ko Files not found."
)
echo -e "(3/3) Unpacking [ modules-${kernel_name}.tar.gz ] done."
# Delete kernel tmpfiles
rm -f ${P4_PATH}/*-${kernel_name}.tar.gz
rm -f ${P4_PATH}/sha256sums
sync && echo ""
}
# Update the uboot
update_uboot() {
# Only amlogic SoCs needs to be updated
if [[ "${PLATFORM}" == "amlogic" ]]; then
# Copy u-boot.ext and u-boot.emmc
if [[ "${K510}" -eq "1" && -n "${UBOOT_OVERLOAD}" && -f "/boot/${UBOOT_OVERLOAD}" ]]; then
[[ ! -f "/boot/u-boot.ext" ]] && cp -f "/boot/${UBOOT_OVERLOAD}" /boot/u-boot.ext && chmod +x /boot/u-boot.ext
[[ ! -f "/boot/u-boot.emmc" ]] && cp -f "/boot/u-boot.ext" /boot/u-boot.emmc && chmod +x /boot/u-boot.emmc
echo -e "The ${UBOOT_OVERLOAD} file copy is complete."
elif [[ "${K510}" -eq "0" ]]; then
rm -f "/boot/u-boot.ext" "/boot/u-boot.emmc"
fi
# Write Mainline bootloader
if [[ -f "${MAINLINE_UBOOT}" && "${AUTO_MAINLINE_UBOOT}" == "yes" ]]; then
echo -e "Write Mainline bootloader: [ ${MAINLINE_UBOOT} ] to [ /dev/${EMMC_NAME} ]"
dd if=${MAINLINE_UBOOT} of=/dev/${EMMC_NAME} bs=1 count=442 conv=fsync
dd if=${MAINLINE_UBOOT} of=/dev/${EMMC_NAME} bs=512 skip=1 seek=1 conv=fsync
echo -e "The MAINLINE_UBOOT file write is complete."
fi
fi
# Update release file
sed -i "s|^KERNEL_VERSION=.*|KERNEL_VERSION='${kernel_name}'|g" ${release_file} 2>/dev/null
# Update banner file
sed -i "s| Kernel.*| Kernel: ${kernel_name}|g" /etc/banner 2>/dev/null
sync && echo ""
}
# Rescue the kernel
sos_kernel() {
echo -e "Start rescuing kernel..."
# Supports specifying disks, such as: [ openwrt-kernel -s mmcblk1 ]
box_disk="${2}"
if [[ -n "${box_disk}" ]]; then
# Format the disk names
box_disk="${box_disk//\/dev\//}"
# Check if the disk exists
[[ -b "/dev/${box_disk}" ]] || error_msg "The specified disk [ ${box_disk} ] does not exist."
# Check if the disk is the same as the current system disk
[[ "${box_disk}" == "${EMMC_NAME}" ]] && error_msg "The specified disk [ ${box_disk} ] is the same as the current system disk [ ${EMMC_NAME} ]."
echo -e "The device name of the specified disk: [ ${box_disk} ]"
else
# Find emmc disk, first find emmc containing boot0 partition
box_disk="$(lsblk -l -o NAME | grep -oE '(mmcblk[0-9]?|nvme[0-9]?n[0-9]?|[hsv]d[a-z])' | grep -vE ^${EMMC_NAME} | sort -u | head -n 1)"
# Check if disk exists
[[ -z "${box_disk}" ]] && error_msg "Unable to locate the storage requiring rescue."
echo -e "The device name of the target disk: [ ${box_disk} ]"
fi
rescue_disk="/dev/${box_disk}"
echo -e "The current OpenWrt is running on [ /dev/${EMMC_NAME} ], and the target disk for restoration is [ ${rescue_disk} ]."
# Create a temporary mount directory
umount ${P4_PATH}/bootfs 2>/dev/null
umount ${P4_PATH}/rootfs 2>/dev/null
rm -rf ${P4_PATH}/bootfs ${P4_PATH}/rootfs 2>/dev/null
mkdir -p ${P4_PATH}/{bootfs/,rootfs/} && sync
[[ "${?}" -ne "0" ]] && error_msg "Failed to create temporary mount directory [ ${P4_PATH} ]"
# Mount target bootfs partition
[[ "${box_disk}" =~ ^([hsv]d[a-z]) ]] && rescue_disk_partition_name="" || rescue_disk_partition_name="p"
mount ${rescue_disk}${rescue_disk_partition_name}1 ${P4_PATH}/bootfs
[[ "${?}" -ne "0" ]] && error_msg "mount ${rescue_disk}${PARTITION_NAME}1 failed!"
echo -e "The [ ${rescue_disk}${rescue_disk_partition_name}1 ] partition is mounted on [ ${P4_PATH}/bootfs ]."
# Search uuid file
if [[ -f "${P4_PATH}/bootfs/uEnv.txt" ]]; then
search_file="uEnv.txt"
elif [[ -f "${P4_PATH}/bootfs/armbianEnv.txt" ]]; then
search_file="armbianEnv.txt"
elif [[ -f "${P4_PATH}/bootfs/extlinux/extlinux.conf" ]]; then
search_file="extlinux/extlinux.conf"
else
error_msg "The [ uEnv.txt, armbianEnv.txt, extlinux/extlinux.conf ] file does not exist, stop rescuing."
fi
# Get the target partition uuid and rootfs
target_parttion_uuid="$(grep '=UUID=' ${P4_PATH}/bootfs/${search_file} | sed -n 's/.*=UUID=\([a-f0-9-]*\).*/\1/p')"
[[ -z "${target_parttion_uuid}" ]] && error_msg "The [ ${search_file} ] file does not contain the UUID value."
target_rootfs="$(blkid | grep ${target_parttion_uuid} | awk -F':' '{print $1;}')"
[[ -z "${target_rootfs}" ]] && error_msg "The [ ${target_parttion_uuid} ] UUID does not exist in the system."
# Mount target rootfs partition
mount ${target_rootfs} ${P4_PATH}/rootfs
[[ "${?}" -ne "0" ]] && error_msg "mount ${rescue_disk}${PARTITION_NAME}2 failed!"
echo -e "The [ ${target_rootfs} ] partition is mounted on [ ${P4_PATH}/rootfs ]."
# Identify the current kernel files
kernel_signature="$(uname -r)"
# 01. For /boot files
[[ -d "${P4_PATH}/bootfs" ]] && {
cd ${P4_PATH}/bootfs
rm -rf config-* initrd.img-* System.map-* vmlinuz-* uInitrd* *Image dtb* u-boot.ext u-boot.emmc
[[ -f "/boot/u-boot.ext" ]] && {
cp -f /boot/u-boot.ext .
cp -f /boot/u-boot.ext u-boot.emmc
chmod +x u-boot.ext u-boot.emmc
}
cp -rf /boot/{*-${kernel_signature},uInitrd,*Image,dtb} .
[[ "${?}" -ne "0" ]] && error_msg "(1/2) [ boot ] kernel files rescue failed."
echo -e "(1/2) [ boot ] kernel files rescue succeeded."
[[ -f "/boot/emmc_autoscript.cmd" ]] && cp -f /boot/emmc_autoscript.cmd .
[[ -f "/boot/emmc_autoscript" ]] && cp -f /boot/emmc_autoscript .
[[ -f "/boot/s905_autoscript.cmd" ]] && cp -f /boot/s905_autoscript.cmd .
[[ -f "/boot/s905_autoscript" ]] && cp -f /boot/s905_autoscript .
} || error_msg "(1/2) The [ ${P4_PATH}/bootfs ] folder does not exist, stop rescuing."
# 02. For /lib/modules/${kernel_signature}
[[ -d "${P4_PATH}/rootfs/lib/modules" ]] && {
cd ${P4_PATH}/rootfs/lib/modules
rm -rf *
cp -rf /lib/modules/${kernel_signature} .
[[ "${?}" -ne "0" ]] && error_msg "(2/2) [ modules ] kernel files rescue failed."
echo -e "(2/2) [ modules ] kernel files rescue succeeded."
} || error_msg "(2/2) The [ ${P4_PATH}/rootfs/lib/modules ] folder does not exist, stop rescuing."
# Unmount the emmc partition
cd ${P4_PATH}
umount -f ${P4_PATH}/bootfs
[[ "${?}" -ne "0" ]] && error_msg "Failed to umount [ ${P4_PATH}/bootfs ]"
umount -f ${P4_PATH}/rootfs
[[ "${?}" -ne "0" ]] && error_msg "Failed to umount [ ${P4_PATH}/rootfs ]"
# Remove the temporary mount directory
rm -rf ${P4_PATH}/bootfs ${P4_PATH}/rootfs
sync && echo ""
}
echo -e "Welcome to the OpenWrt Kernel Management Tool."
# Operation environment check
[[ -x "/usr/sbin/openwrt-kernel" ]] || error_msg "Please grant execution permission: chmod +x /usr/sbin/openwrt-kernel"
# Execute relevant functions based on the options
if [[ "${@}" =~ ^-s(\s)* ]]; then
# Initialize all variables
init_var "${@}"
# Start rescuing the kernel
sos_kernel "${@}"
# Kernel restore successful
sync && sleep 3
echo -e "Kernel rescue successful, please remove the disk and restart the OpenWrt system."
exit 0
else
# Initialize all variables
init_var "${@}"
# Check kernel files list
check_kernel
# Update the kernel
update_kernel
# Update the uboot
update_uboot
# Kernel update successful
sync && sleep 3
echo "Successfully updated, automatic restarting..."
reboot
exit 0
fi
+662
View File
@@ -0,0 +1,662 @@
#!/bin/bash
#======================================================================================
# Function: Update openwrt to emmc for Allwinner STB
# Copyright (C) 2020-- https://github.com/unifreq/openwrt_packit
# Copyright (C) 2021-- https://github.com/ophub/luci-app-amlogic
#======================================================================================
#
# The script supports directly setting parameters for update, skipping interactive selection
# openwrt-update-allwinner ${OPENWRT_FILE} ${AUTO_MAINLINE_UBOOT} ${RESTORE_CONFIG}
# E.g: openwrt-update-allwinner openwrt_s905d.img.gz yes restore
# E.g: openwrt-update-allwinner openwrt_s905d.img.gz no no-restore
# You can also execute the script directly, and interactively select related functions
# E.g: openwrt-update-allwinner
#
#======================================================================================
# Encountered a serious error, abort the script execution
error_msg() {
echo -e "[ERROR] ${1}"
exit 1
}
# Get the partition name of the /boot file system
get_boot_partition_name() {
local paths="/boot"
local partition_name
partition_name=$(df "${paths}" | awk 'NR==2 {print $1}' | awk -F '/' '{print $3}')
echo "${partition_name}"
}
# Get the partition name of the root file system
get_root_partition_name() {
local paths=("/" "/overlay" "/rom")
local partition_name
for path in "${paths[@]}"; do
partition_name=$(df "${path}" | awk 'NR==2 {print $1}' | awk -F '/' '{print $3}')
[[ -n "${partition_name}" ]] && break
done
echo "${partition_name}"
}
# Get the partition message of the root file system
get_root_partition_msg() {
local paths=("/" "/overlay" "/rom")
local partition_name
for path in "${paths[@]}"; do
partition_msg=$(lsblk -l -o NAME,PATH,TYPE,UUID,MOUNTPOINT | awk '$3~/^part$/ && $5 ~ "^" "'"${path}"'" "$" {print $0}')
[[ -n "${partition_msg}" ]] && break
done
[[ -z "${partition_msg}" ]] && error_msg "Cannot find the root partition message!"
echo "${partition_msg}"
}
# Receive one-key command related parameters
IMG_NAME=${1}
AUTO_MAINLINE_UBOOT=${2}
BACKUP_RESTORE_CONFIG=${3}
# Current FDT file
if [[ -f "/boot/uEnv.txt" ]]; then
source /boot/uEnv.txt 2>/dev/null
MYDTB_FDTFILE=$(basename $FDT)
elif [[ -f "/boot/armbianEnv.txt" ]]; then
source /boot/armbianEnv.txt 2>/dev/null
MYDTB_FDTFILE="$(basename $fdtfile)"
elif [[ -f "/etc/flippy-openwrt-release" ]]; then
source /etc/flippy-openwrt-release 2>/dev/null
MYDTB_FDTFILE="${FDTFILE}"
fi
[[ -z "${MYDTB_FDTFILE}" ]] && error_msg "Invalid FDTFILE: [ ${MYDTB_FDTFILE} ]"
# Current device model
MYDEVICE_NAME=$(cat /proc/device-tree/model | tr -d '\000')
if [[ -z "${MYDEVICE_NAME}" ]]; then
error_msg "The device name is empty and cannot be recognized."
elif [[ "$(echo ${MYDEVICE_NAME} | grep "V-Plus Cloud")" == "" ]]; then
error_msg "[ ${MYDEVICE_NAME} ] is not [ V-Plus Cloud ] device, please select the correct script."
else
echo -e "Current device: ${MYDEVICE_NAME} [ vplus ]"
sleep 3
fi
# Check and repair partition mount points
[[ -z "$(get_boot_partition_name)" || -z "$(get_root_partition_name)" ]] && {
echo -e "Partition mount point error, start repairing..."
openwrt-backup -g
}
# Find the partition where root is located
ROOT_PTNAME="$(get_root_partition_name)"
# Find the disk where the partition is located, only supports mmcblk?p? sd?? hd?? vd?? and other formats
case ${ROOT_PTNAME} in
mmcblk?p[1-4])
EMMC_NAME=$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-2)}')
PARTITION_NAME="p"
LB_PRE="EMMC_"
;;
[hsv]d[a-z][1-4])
EMMC_NAME=$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-1)}')
PARTITION_NAME=""
LB_PRE=""
;;
*)
error_msg "Unable to recognize the disk type of ${ROOT_PTNAME}!"
;;
esac
cd /mnt/${EMMC_NAME}${PARTITION_NAME}4/
mv -f /tmp/upload/* . 2>/dev/null && sync
if [[ "${IMG_NAME}" == *.img ]]; then
echo -e "Update using [ ${IMG_NAME} ] file. Please wait a moment ..."
elif [ $(ls *.img -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
IMG_NAME=$(ls *.img | head -n 1)
echo -e "Update using [ ${IMG_NAME} ] ] file. Please wait a moment ..."
elif [ $(ls *.img.xz -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
xz_file=$(ls *.img.xz | head -n 1)
echo -e "Update using [ ${xz_file} ] file. Please wait a moment ..."
xz -d ${xz_file} 2>/dev/null
IMG_NAME=$(ls *.img | head -n 1)
elif [ $(ls *.img.gz -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
gz_file=$(ls *.img.gz | head -n 1)
echo -e "Update using [ ${gz_file} ] file. Please wait a moment ..."
gzip -df ${gz_file} 2>/dev/null
IMG_NAME=$(ls *.img | head -n 1)
elif [ $(ls *.7z -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
gz_file=$(ls *.7z | head -n 1)
echo -e "Update using [ ${gz_file} ] file. Please wait a moment ..."
bsdtar -xmf ${gz_file} 2>/dev/null
[ $? -eq 0 ] || 7z x ${gz_file} -aoa -y 2>/dev/null
IMG_NAME=$(ls *.img | head -n 1)
elif [ $(ls *.zip -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
zip_file=$(ls *.zip | head -n 1)
echo -e "Update using [ ${zip_file} ] file. Please wait a moment ..."
unzip -o ${zip_file} 2>/dev/null
IMG_NAME=$(ls *.img | head -n 1)
else
echo -e "Please upload or specify the update openwrt firmware file."
echo -e "Upload method: system menu → Amlogic Service → Manually Upload Update"
echo -e "Specify method: Place the openwrt firmware file in [ /mnt/${EMMC_NAME}${PARTITION_NAME}4/ ]"
echo -e "The supported file suffixes are: *.img, *.img.xz, *.img.gz, *.7z, *.zip"
echo -e "After upload the openwrt firmware file, run again."
exit 1
fi
sync
# check file
if [ ! -f "${IMG_NAME}" ]; then
error_msg "No update file found."
else
echo "Start update from [ ${IMG_NAME} ]"
fi
# find boot partition
BOOT_PART_MSG=$(lsblk -l -o NAME,PATH,TYPE,UUID,MOUNTPOINT | awk '$3~/^part$/ && $5 ~ /^\/boot$/ {print $0}')
if [ "${BOOT_PART_MSG}" == "" ]; then
error_msg "The boot partition is not exists or not mounted, so it cannot be upgraded with this script!"
fi
BR_FLAG=1
echo -ne "Whether to backup and restore the current config files? y/n [y]\b\b"
if [[ ${BACKUP_RESTORE_CONFIG} == "restore" ]]; then
yn="y"
elif [[ ${BACKUP_RESTORE_CONFIG} == "no-restore" ]]; then
yn="n"
else
read yn
fi
case $yn in
n* | N*)
BR_FLAG=0
;;
esac
BOOT_NAME=$(echo ${BOOT_PART_MSG} | awk '{print $1}')
BOOT_PATH=$(echo ${BOOT_PART_MSG} | awk '{print $2}')
BOOT_UUID=$(echo ${BOOT_PART_MSG} | awk '{print $4}')
# find root partition
ROOT_PART_MSG="$(get_root_partition_msg)"
ROOT_NAME=$(echo ${ROOT_PART_MSG} | awk '{print $1}')
ROOT_PATH=$(echo ${ROOT_PART_MSG} | awk '{print $2}')
ROOT_UUID=$(echo ${ROOT_PART_MSG} | awk '{print $4}')
case ${ROOT_NAME} in
${EMMC_NAME}${PARTITION_NAME}2)
NEW_ROOT_NAME="${EMMC_NAME}${PARTITION_NAME}3"
NEW_ROOT_LABEL="${LB_PRE}ROOTFS2"
;;
${EMMC_NAME}${PARTITION_NAME}3)
NEW_ROOT_NAME="${EMMC_NAME}${PARTITION_NAME}2"
NEW_ROOT_LABEL="${LB_PRE}ROOTFS1"
;;
*)
error_msg "The root partition location is invalid, so it cannot be upgraded with this script!"
;;
esac
# find new root partition
NEW_ROOT_PART_MSG=$(lsblk -l -o NAME,PATH,TYPE,UUID,MOUNTPOINT | grep "${NEW_ROOT_NAME}" | awk '$3 ~ /^part$/ && $5 !~ /^\/$/ && $5 !~ /^\/boot$/ {print $0}')
if [ "${NEW_ROOT_PART_MSG}" == "" ]; then
error_msg "The new root partition is not exists, so it cannot be upgraded with this script!"
fi
NEW_ROOT_NAME=$(echo $NEW_ROOT_PART_MSG | awk '{print $1}')
NEW_ROOT_PATH=$(echo $NEW_ROOT_PART_MSG | awk '{print $2}')
NEW_ROOT_UUID=$(echo $NEW_ROOT_PART_MSG | awk '{print $4}')
NEW_ROOT_MP=$(echo $NEW_ROOT_PART_MSG | awk '{print $5}')
# losetup
losetup -f -P $IMG_NAME
if [ $? -eq 0 ]; then
LOOP_DEV=$(losetup | grep "$IMG_NAME" | awk '{print $1}')
if [ "$LOOP_DEV" == "" ]; then
error_msg "loop device not found!"
fi
else
error_msg "losetup $IMG_FILE failed!"
fi
# fix loopdev issue in kernel 5.19
function fix_loopdev() {
local parentdev=${1##*/}
if [ ! -d /sys/block/${parentdev} ]; then
return
fi
subdevs=$(lsblk -l -o NAME | grep -E "^${parentdev}.+\$")
for subdev in $subdevs; do
if [ ! -d /sys/block/${parentdev}/${subdev} ]; then
return
elif [ -b /dev/${sub_dev} ]; then
continue
fi
source /sys/block/${parentdev}/${subdev}/uevent
mknod /dev/${subdev} b ${MAJOR} ${MINOR}
unset MAJOR MINOR DEVNAME DEVTYPE DISKSEQ PARTN PARTNAME
done
}
fix_loopdev ${LOOP_DEV}
WAIT=3
echo -n "The loopdev is $LOOP_DEV, wait ${WAIT} seconds "
while [ $WAIT -ge 1 ]; do
echo -n "."
sleep 1
WAIT=$((WAIT - 1))
done
echo
# umount loop devices (openwrt will auto mount some partition)
MOUNTED_DEVS=$(lsblk -l -o NAME,PATH,MOUNTPOINT | grep "$LOOP_DEV" | awk '$3 !~ /^$/ {print $2}')
for dev in $MOUNTED_DEVS; do
while :; do
echo -n "umount $dev ... "
umount -f $dev
sleep 1
mnt=$(lsblk -l -o NAME,PATH,MOUNTPOINT | grep "$dev" | awk '$3 !~ /^$/ {print $2}')
if [ "$mnt" == "" ]; then
echo "ok"
break
else
echo "try again ..."
fi
done
done
# mount src part
WORK_DIR=$PWD
P1=${WORK_DIR}/boot
P2=${WORK_DIR}/root
mkdir -p $P1 $P2
echo -n "mount ${LOOP_DEV}p1 -> ${P1} ... "
mount -t vfat -o ro ${LOOP_DEV}p1 ${P1}
if [ $? -ne 0 ]; then
echo "mount failed"
losetup -D
exit 1
else
echo "ok"
fi
echo -n "mount ${LOOP_DEV}p2 -> ${P2} ... "
ZSTD_LEVEL=6
mount -t btrfs -o ro,compress=zstd:${ZSTD_LEVEL} ${LOOP_DEV}p2 ${P2}
if [ $? -ne 0 ]; then
echo "mount failed"
umount -f ${P1}
losetup -D
exit 1
else
echo "ok"
fi
# Prepare the dockerman config file
if [ -f ${P2}/etc/init.d/dockerman ] && [ -f ${P2}/etc/config/dockerd ]; then
flg=0
# get current docker data root
data_root=$(uci get dockerd.globals.data_root 2>/dev/null)
if [ "$data_root" == "" ]; then
flg=1
# get current config from /etc/docker/daemon.json
if [ -f "/etc/docker/daemon.json" ] && [ -x "/usr/bin/jq" ]; then
data_root=$(jq -r '."data-root"' /etc/docker/daemon.json)
bip=$(jq -r '."bip"' /etc/docker/daemon.json)
[ "$bip" == "null" ] && bip="172.31.0.1/24"
log_level=$(jq -r '."log-level"' /etc/docker/daemon.json)
[ "$log_level" == "null" ] && log_level="warn"
_iptables=$(jq -r '."iptables"' /etc/docker/daemon.json)
[ "$_iptables" == "null" ] && _iptables="true"
registry_mirrors=$(jq -r '."registry-mirrors"[]' /etc/docker/daemon.json 2>/dev/null)
fi
fi
if [ "$data_root" == "" ]; then
data_root="/opt/docker/" # the default data root
fi
if ! uci get dockerd.globals >/dev/null 2>&1; then
uci set dockerd.globals='globals'
uci commit
fi
# delete alter config , use inner config
if uci get dockerd.globals.alt_config_file >/dev/null 2>&1; then
uci delete dockerd.globals.alt_config_file
uci commit
fi
if [ $flg -eq 1 ]; then
uci set dockerd.globals.data_root=$data_root
[ "$bip" != "" ] && uci set dockerd.globals.bip=$bip
[ "$log_level" != "" ] && uci set dockerd.globals.log_level=$log_level
[ "$_iptables" != "" ] && uci set dockerd.globals.iptables=$_iptables
if [ "$registry_mirrors" != "" ]; then
for reg in $registry_mirrors; do
uci add_list dockerd.globals.registry_mirrors=$reg
done
fi
uci set dockerd.globals.auto_start='1'
uci commit
fi
fi
#format NEW_ROOT
echo "umount ${NEW_ROOT_MP}"
umount -f "${NEW_ROOT_MP}"
if [ $? -ne 0 ]; then
echo "umount failed, please reboot and try again!"
umount -f ${P1}
umount -f ${P2}
losetup -D
exit 1
fi
echo "format ${NEW_ROOT_PATH}"
NEW_ROOT_UUID=$(uuidgen)
mkfs.btrfs -f -U ${NEW_ROOT_UUID} -L ${NEW_ROOT_LABEL} ${NEW_ROOT_PATH}
if [ $? -ne 0 ]; then
echo "format ${NEW_ROOT_PATH} failed!"
umount -f ${P1}
umount -f ${P2}
losetup -D
exit 1
fi
echo "mount ${NEW_ROOT_PATH} to ${NEW_ROOT_MP}"
mount -t btrfs -o compress=zstd:${ZSTD_LEVEL} ${NEW_ROOT_PATH} ${NEW_ROOT_MP}
if [ $? -ne 0 ]; then
echo "mount ${NEW_ROOT_PATH} to ${NEW_ROOT_MP} failed!"
umount -f ${P1}
umount -f ${P2}
losetup -D
exit 1
fi
# begin copy rootfs
cd ${NEW_ROOT_MP}
echo "Start copy data from ${P2} to ${NEW_ROOT_MP} ..."
ENTRYS=$(ls)
for entry in $ENTRYS; do
if [ "$entry" == "lost+found" ]; then
continue
fi
echo -n "remove old $entry ... "
rm -rf $entry
if [ $? -eq 0 ]; then
echo "ok"
else
error_msg "failed"
fi
done
echo
echo "create etc subvolume ..."
btrfs subvolume create etc
echo -n "make dirs ... "
mkdir -p .snapshots .reserved bin boot dev lib opt mnt overlay proc rom root run sbin sys tmp usr www
ln -sf lib/ lib64
ln -sf tmp/ var
echo "done"
echo
COPY_SRC="root etc bin sbin lib opt usr www"
echo "copy data ... "
for src in $COPY_SRC; do
echo -n "copy $src ... "
(cd ${P2} && tar cf - $src) | tar xf -
sync
echo "done"
done
SHFS="/mnt/${EMMC_NAME}${PARTITION_NAME}4"
echo "Modify config files ... "
rm -f "./etc/rc.local.orig" "./etc/first_run.sh" "./etc/part_size"
rm -f ./etc/bench.log
if [ -x ./usr/sbin/balethirq.pl ]; then
if grep "balethirq.pl" "./etc/rc.local"; then
echo "balance irq is enabled"
else
echo "enable balance irq"
sed -e "/exit/i\/usr/sbin/balethirq.pl" -i ./etc/rc.local
fi
fi
cat >./etc/fstab <<EOF
UUID=${NEW_ROOT_UUID} / btrfs compress=zstd:${ZSTD_LEVEL} 0 1
LABEL=${LB_PRE}BOOT /boot vfat defaults 0 2
#tmpfs /tmp tmpfs defaults,nosuid 0 0
EOF
cat >./etc/config/fstab <<EOF
config global
option anon_swap '0'
option anon_mount '1'
option auto_swap '0'
option auto_mount '1'
option delay_root '5'
option check_fs '0'
config mount
option target '/rom'
option uuid '${NEW_ROOT_UUID}'
option enabled '1'
option enabled_fsck '1'
option fstype 'btrfs'
option options 'compress=zstd:${ZSTD_LEVEL}'
config mount
option target '/boot'
option label '${LB_PRE}BOOT'
option enabled '1'
option enabled_fsck '0'
option fstype 'vfat'
EOF
(
cd etc/rc.d
rm -f S??shortcut-fe
if grep "sfe_flow '1'" ../config/turboacc >/dev/null; then
if find ../../lib/modules -name 'shortcut-fe-cm.ko'; then
ln -sf ../init.d/shortcut-fe S99shortcut-fe
fi
fi
)
# move /etc/config/balance_irq to /etc/balance_irq
[ -f "./etc/config/balance_irq" ] && mv ./etc/config/balance_irq ./etc/
sync
echo "create the first etc snapshot -> .snapshots/etc-000"
btrfs subvolume snapshot -r etc .snapshots/etc-000
[ -d ${SHFS}/docker ] || mkdir -p ${SHFS}/docker
rm -rf opt/docker && ln -sf ${SHFS}/docker/ opt/docker
if [ -f /mnt/${NEW_ROOT_NAME}/etc/config/AdGuardHome ]; then
[ -d ${SHFS}/AdGuardHome/data ] || mkdir -p ${SHFS}/AdGuardHome/data
if [ ! -L /usr/bin/AdGuardHome ]; then
[ -d /usr/bin/AdGuardHome ] &&
cp -a /usr/bin/AdGuardHome/* ${SHFS}/AdGuardHome/
fi
ln -sf ${SHFS}/AdGuardHome /mnt/${NEW_ROOT_NAME}/usr/bin/AdGuardHome
fi
BOOTLOADER="./lib/u-boot/u-boot-sunxi-with-spl.bin"
if [ -f ${BOOTLOADER} ]; then
echo "update u-boot ... "
# erase from 8kb to 4mb
dd if=/dev/zero of=/dev/${EMMC_NAME} bs=1024 seek=8 count=4088 conv=fsync
# write u-boot
dd if=${BOOTLOADER} of=/dev/${EMMC_NAME} bs=1024 seek=8 conv=fsync
echo "done"
fi
sync
echo "copy done"
echo
BACKUP_LIST=$(${P2}/usr/sbin/openwrt-backup -p)
if [ $BR_FLAG -eq 1 ]; then
echo -n "Restore your old config files ... "
(
cd /
eval tar czf ${NEW_ROOT_MP}/.reserved/openwrt_config.tar.gz "${BACKUP_LIST}" 2>/dev/null
)
tar xzf ${NEW_ROOT_MP}/.reserved/openwrt_config.tar.gz
[ -f ./etc/config/dockerman ] && sed -e "s/option wan_mode 'false'/option wan_mode 'true'/" -i ./etc/config/dockerman 2>/dev/null
[ -f ./etc/config/dockerd ] && sed -e "s/option wan_mode '0'/option wan_mode '1'/" -i ./etc/config/dockerd 2>/dev/null
[ -f ./etc/config/verysync ] && sed -e 's/config setting/config verysync/' -i ./etc/config/verysync
# 还原 fstab
cp -f .snapshots/etc-000/fstab ./etc/fstab
cp -f .snapshots/etc-000/config/fstab ./etc/config/fstab
# 还原 luci
cp -f .snapshots/etc-000/config/luci ./etc/config/luci
# 还原/etc/config/rpcd
cp -f .snapshots/etc-000/config/rpcd ./etc/config/rpcd
sync
echo "done"
echo
fi
rm -f ./etc/bench.log
cat >>./etc/crontabs/root <<EOF
17 3 * * * /etc/coremark.sh
EOF
sed -e 's/ttyAMA0/ttyS0/' -i ./etc/inittab
sss=$(date +%s)
ddd=$((sss / 86400))
sed -e "s/:0:0:99999:7:::/:${ddd}:0:99999:7:::/" -i ./etc/shadow
# 修复amule每次升级后重复添加条目的问题
sed -e "/amule:x:/d" -i ./etc/shadow
# 修复dropbear每次升级后重复添加sshd条目的问题
sed -e "/sshd:x:/d" -i ./etc/shadow
if ! grep "sshd:x:22:sshd" ./etc/group >/dev/null; then
echo "sshd:x:22:sshd" >>./etc/group
fi
if ! grep "sshd:x:22:22:sshd:" ./etc/passwd >/dev/null; then
echo "sshd:x:22:22:sshd:/var/run/sshd:/bin/false" >>./etc/passwd
fi
if ! grep "sshd:x:" ./etc/shadow >/dev/null; then
echo "sshd:x:${ddd}:0:99999:7:::" >>./etc/shadow
fi
if [ $BR_FLAG -eq 1 ]; then
if [ -x ./bin/bash ] && [ -f ./etc/profile.d/30-sysinfo.sh ]; then
sed -e 's/\/bin\/ash/\/bin\/bash/' -i ./etc/passwd
fi
sync
echo "done"
echo
fi
sed -e "s/option hw_flow '1'/option hw_flow '0'/" -i ./etc/config/turboacc
(
cd etc/rc.d
rm -f S??shortcut-fe
if grep "sfe_flow '1'" ../config/turboacc >/dev/null; then
if find ../../lib/modules -name 'shortcut-fe-cm.ko'; then
ln -sf ../init.d/shortcut-fe S99shortcut-fe
fi
fi
)
sync
eval tar czf .reserved/openwrt_config.tar.gz "${BACKUP_LIST}" 2>/dev/null
rm -f ./etc/part_size ./etc/first_run.sh
mv ./etc/rc.local ./etc/rc.local.orig
cat >"./etc/rc.local" <<EOF
if ! ls /etc/rc.d/S??dockerd >/dev/null 2>&1;then
/etc/init.d/dockerd enable
/etc/init.d/dockerd start
fi
if ! ls /etc/rc.d/S??dockerman >/dev/null 2>&1 && [ -f /etc/init.d/dockerman ];then
/etc/init.d/dockerman enable
/etc/init.d/dockerman start
fi
opkg remove --force-removal-of-dependent-packages shairport-sync-openssl
mv /etc/rc.local.orig /etc/rc.local
chmod 755 /etc/rc.local
exec /etc/rc.local
exit
EOF
chmod 755 ./etc/rc.local*
# move /etc/config/balance_irq to /etc/balance_irq
[ -f "./etc/config/balance_irq" ] && mv ./etc/config/balance_irq ./etc/
echo "create the second etc snapshot -> .snapshots/etc-001"
btrfs subvolume snapshot -r etc .snapshots/etc-001
# 2021.04.01添加
# 强制锁定fstab,防止用户擅自修改挂载点
# 开启了快照功能之后,不再需要锁定fstab
#chattr +ia ./etc/config/fstab
cd ${WORK_DIR}
echo "Start copy data from ${P1} to /boot ..."
cd /boot
echo -n "remove old boot files ..."
rm -rf *
echo "done"
echo -n "copy new boot files ... "
(cd ${P1} && tar cf - .) | tar xf -
sync
echo "done"
echo
echo -n "Update boot args ... "
cat >uEnv.txt <<EOF
LINUX=/zImage
INITRD=/uInitrd
# Example:
# FDT=/dtb/allwinner/sun50i-h6-vplus-cloud.dtb
# FDT=/dtb/allwinner/sun50i-h6-vplus-cloud-2ghz.dtb
FDT=/dtb/allwinner/${MYDTB_FDTFILE}
APPEND=root=UUID=${NEW_ROOT_UUID} rootfstype=btrfs rootflags=compress=zstd:${ZSTD_LEVEL} console=ttyS0,115200n8 no_console_suspend consoleblank=0 fsck.fix=yes fsck.repair=yes net.ifnames=0 cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory swapaccount=1
EOF
# Compatible with armbianEnv.txt file
[[ -f "armbianEnv.txt" ]] && {
echo "Update armbianEnv.txt settings."
sed -i "s|^rootdev=.*|rootdev=UUID=${NEW_ROOT_UUID}|g" armbianEnv.txt
rm -f uEnv.txt
}
# Replace the UUID for extlinux/extlinux.conf if it exists
[[ -f "extlinux/extlinux.conf" ]] && {
sed -i -E "s|UUID=[^ ]*|UUID=${NEW_ROOT_UUID}|" extlinux/extlinux.conf 2>/dev/null
}
sync
echo "done"
echo
cd $WORK_DIR
umount -f ${P1} ${P2} 2>/dev/null
losetup -D 2>/dev/null
rmdir ${P1} ${P2} 2>/dev/null
rm -f ${IMG_NAME} 2>/dev/null
rm -f sha256sums 2>/dev/null
sync
echo "Successfully updated, automatic restarting..."
sleep 3
reboot
exit 0
+859
View File
@@ -0,0 +1,859 @@
#!/bin/bash
#======================================================================================
# Function: Update openwrt to emmc for Amlogic S9xxx STB
# Copyright (C) 2020-- https://github.com/unifreq/openwrt_packit
# Copyright (C) 2021-- https://github.com/ophub/luci-app-amlogic
#======================================================================================
#
# The script supports directly setting parameters for update, skipping interactive selection
# openwrt-update-amlogic ${OPENWRT_FILE} ${AUTO_MAINLINE_UBOOT} ${RESTORE_CONFIG}
# E.g: openwrt-update-amlogic openwrt_s905d.img.gz yes restore
# E.g: openwrt-update-amlogic openwrt_s905d.img.gz no no-restore
# You can also execute the script directly, and interactively select related functions
# E.g: openwrt-update-amlogic
#
#======================================================================================
# Encountered a serious error, abort the script execution
error_msg() {
echo -e "[ERROR] ${1}"
exit 1
}
# Get the partition name of the /boot file system
get_boot_partition_name() {
local paths="/boot"
local partition_name
partition_name=$(df "${paths}" | awk 'NR==2 {print $1}' | awk -F '/' '{print $3}')
echo "${partition_name}"
}
# Get the partition name of the root file system
get_root_partition_name() {
local paths=("/" "/overlay" "/rom")
local partition_name
for path in "${paths[@]}"; do
partition_name=$(df "${path}" | awk 'NR==2 {print $1}' | awk -F '/' '{print $3}')
[[ -n "${partition_name}" ]] && break
done
echo "${partition_name}"
}
# Get the partition message of the root file system
get_root_partition_msg() {
local paths=("/" "/overlay" "/rom")
local partition_name
for path in "${paths[@]}"; do
partition_msg=$(lsblk -l -o NAME,PATH,TYPE,UUID,MOUNTPOINT | awk '$3~/^part$/ && $5 ~ "^" "'"${path}"'" "$" {print $0}')
[[ -n "${partition_msg}" ]] && break
done
[[ -z "${partition_msg}" ]] && error_msg "Cannot find the root partition message!"
echo "${partition_msg}"
}
# Receive one-key command related parameters
IMG_NAME="${1}"
AUTO_MAINLINE_UBOOT="${2}"
BACKUP_RESTORE_CONFIG="${3}"
# Current device model
MYDEVICE_NAME=$(cat /proc/device-tree/model | tr -d '\000')
if [[ -z "${MYDEVICE_NAME}" ]]; then
error_msg "The device name is empty and cannot be recognized."
elif [[ ! -f "/etc/flippy-openwrt-release" ]]; then
error_msg "The [ /etc/flippy-openwrt-release ] file is missing."
else
echo -e "Current device: ${MYDEVICE_NAME} [ amlogic ]"
sleep 3
fi
# Check and repair partition mount points
[[ -z "$(get_boot_partition_name)" || -z "$(get_root_partition_name)" ]] && {
echo -e "Partition mount point error, start repairing..."
openwrt-backup -g
}
# Find the partition where root is located
ROOT_PTNAME="$(get_root_partition_name)"
# Find the disk where the partition is located, only supports mmcblk?p? sd?? hd?? vd?? and other formats
case ${ROOT_PTNAME} in
mmcblk?p[1-4])
EMMC_NAME=$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-2)}')
if lsblk -l -o NAME | grep "${EMMC_NAME}boot0" >/dev/null; then
ROOT_DISK_TYPE="EMMC"
else
ROOT_DISK_TYPE="SD"
fi
PARTITION_NAME="p"
LB_PRE="${ROOT_DISK_TYPE}_"
;;
[hsv]d[a-z][1-4])
EMMC_NAME=$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-1)}')
ROOT_DISK_TYPE="USB"
PARTITION_NAME=""
LB_PRE="${ROOT_DISK_TYPE}_"
;;
*)
error_msg "Unable to recognize the disk type of ${ROOT_PTNAME}!"
;;
esac
DOCKER_ROOT="/mnt/${EMMC_NAME}${PARTITION_NAME}4/docker/"
cd /mnt/${EMMC_NAME}${PARTITION_NAME}4/
mv -f /tmp/upload/* . 2>/dev/null && sync
if [[ "${IMG_NAME}" == *.img ]]; then
echo -e "Update using [ ${IMG_NAME} ] file. Please wait a moment ..."
elif [ $(ls *.img -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
IMG_NAME=$(ls *.img | head -n 1)
echo -e "Update using [ ${IMG_NAME} ] ] file. Please wait a moment ..."
elif [ $(ls *.img.xz -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
xz_file=$(ls *.img.xz | head -n 1)
echo -e "Update using [ ${xz_file} ] file. Please wait a moment ..."
xz -d ${xz_file} 2>/dev/null
IMG_NAME=$(ls *.img | head -n 1)
elif [ $(ls *.img.gz -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
gz_file=$(ls *.img.gz | head -n 1)
echo -e "Update using [ ${gz_file} ] file. Please wait a moment ..."
gzip -df ${gz_file} 2>/dev/null
IMG_NAME=$(ls *.img | head -n 1)
elif [ $(ls *.7z -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
gz_file=$(ls *.7z | head -n 1)
echo -e "Update using [ ${gz_file} ] file. Please wait a moment ..."
bsdtar -xmf ${gz_file} 2>/dev/null
[ $? -eq 0 ] || 7z x ${gz_file} -aoa -y 2>/dev/null
IMG_NAME=$(ls *.img | head -n 1)
elif [ $(ls *.zip -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
zip_file=$(ls *.zip | head -n 1)
echo -e "Update using [ ${zip_file} ] file. Please wait a moment ..."
unzip -o ${zip_file} 2>/dev/null
IMG_NAME=$(ls *.img | head -n 1)
else
echo -e "Please upload or specify the update openwrt firmware file."
echo -e "Upload method: system menu → Amlogic Service → Manually Upload Update"
echo -e "Specify method: Place the openwrt firmware file in [ /mnt/${EMMC_NAME}${PARTITION_NAME}4/ ]"
echo -e "The supported file suffixes are: *.img, *.img.xz, *.img.gz, *.7z, *.zip"
echo -e "After upload the openwrt firmware file, run again."
exit 1
fi
sync
# check file
if [ ! -f "${IMG_NAME}" ]; then
error_msg "No update file found."
else
echo "Start update from [ ${IMG_NAME} ]"
fi
# Check the necessary dependencies
DEPENDS="lsblk uuidgen grep awk btrfs mkfs.fat mkfs.btrfs md5sum fatlabel"
echo "Check the necessary dependencies..."
for dep in ${DEPENDS}; do
WITCH=$(busybox which ${dep})
if [ "${WITCH}" == "" ]; then
error_msg "Dependent command: ${dep} does not exist, upgrade cannot be performed, only flash through U disk/TF card!"
else
echo "${dep} path: ${WITCH}"
fi
done
echo "Check passed"
# find boot partition
BOOT_PART_MSG=$(lsblk -l -o NAME,PATH,TYPE,UUID,MOUNTPOINT | awk '$3~/^part$/ && $5 ~ /^\/boot$/ {print $0}')
if [ "${BOOT_PART_MSG}" == "" ]; then
error_msg "Boot The partition does not exist, so the update cannot be continued!"
fi
BOOT_NAME=$(echo ${BOOT_PART_MSG} | awk '{print $1}')
BOOT_PATH=$(echo ${BOOT_PART_MSG} | awk '{print $2}')
BOOT_UUID=$(echo ${BOOT_PART_MSG} | awk '{print $4}')
BR_FLAG=1
echo -ne "Whether to backup and restore the current config files? y/n [y]\b\b"
if [[ ${BACKUP_RESTORE_CONFIG} == "restore" ]]; then
yn="y"
elif [[ ${BACKUP_RESTORE_CONFIG} == "no-restore" ]]; then
yn="n"
else
read yn
fi
case $yn in
n* | N*)
BR_FLAG=0
;;
esac
# find root partition
ROOT_PART_MSG="$(get_root_partition_msg)"
ROOT_NAME=$(echo ${ROOT_PART_MSG} | awk '{print $1}')
ROOT_PATH=$(echo ${ROOT_PART_MSG} | awk '{print $2}')
ROOT_UUID=$(echo ${ROOT_PART_MSG} | awk '{print $4}')
case ${ROOT_NAME} in
${EMMC_NAME}${PARTITION_NAME}2)
NEW_ROOT_NAME="${EMMC_NAME}${PARTITION_NAME}3"
NEW_ROOT_LABEL="${LB_PRE}ROOTFS2"
;;
${EMMC_NAME}${PARTITION_NAME}3)
NEW_ROOT_NAME="${EMMC_NAME}${PARTITION_NAME}2"
NEW_ROOT_LABEL="${LB_PRE}ROOTFS1"
;;
*)
error_msg "ROOTFS The partition location is incorrect, so the update cannot continue!"
;;
esac
echo "NEW_ROOT_NAME: [ ${NEW_ROOT_NAME} ]"
# find new root partition
NEW_ROOT_PART_MSG=$(lsblk -l -o NAME,PATH,TYPE,UUID,MOUNTPOINT | grep "${NEW_ROOT_NAME}" | awk '$3 ~ /^part$/ && $5 !~ /^\/$/ && $5 !~ /^\/boot$/ {print $0}')
if [ "${NEW_ROOT_PART_MSG}" == "" ]; then
error_msg "The new ROOTFS partition does not exist, so the update cannot continue!"
fi
NEW_ROOT_NAME=$(echo ${NEW_ROOT_PART_MSG} | awk '{print $1}')
NEW_ROOT_PATH=$(echo ${NEW_ROOT_PART_MSG} | awk '{print $2}')
NEW_ROOT_UUID=$(echo ${NEW_ROOT_PART_MSG} | awk '{print $4}')
NEW_ROOT_MP=$(echo ${NEW_ROOT_PART_MSG} | awk '{print $5}')
echo "NEW_ROOT_MP: [ ${NEW_ROOT_MP} ]"
# backup old bootloader
if [ ! -f /root/BackupOldBootloader.img ]; then
echo "Backup bootloader -> [ BackupOldBootloader.img ] ... "
dd if=/dev/${EMMC_NAME} of=/root/BackupOldBootloader.img bs=1M count=4 conv=fsync
echo "Backup bootloader complete."
echo
fi
# losetup
losetup -f -P ${IMG_NAME}
if [ ${?} -eq 0 ]; then
LOOP_DEV=$(losetup | grep "${IMG_NAME}" | awk '{print $1}')
if [ "${LOOP_DEV}" == "" ]; then
error_msg "loop device not found!"
fi
else
error_msg "losetup [ ${IMG_FILE} ] failed!"
fi
# fix loopdev issue in kernel 5.19
function fix_loopdev() {
local parentdev=${1##*/}
if [ ! -d /sys/block/${parentdev} ]; then
return
fi
subdevs=$(lsblk -l -o NAME | grep -E "^${parentdev}.+\$")
for subdev in ${subdevs}; do
if [ ! -d /sys/block/${parentdev}/${subdev} ]; then
return
elif [ -b /dev/${sub_dev} ]; then
continue
fi
source /sys/block/${parentdev}/${subdev}/uevent
mknod /dev/${subdev} b ${MAJOR} ${MINOR}
unset MAJOR MINOR DEVNAME DEVTYPE DISKSEQ PARTN PARTNAME
done
}
fix_loopdev ${LOOP_DEV}
WAIT=3
echo "The loopdev is [ $LOOP_DEV ], wait [ ${WAIT} ] seconds. "
while [[ "${WAIT}" -ge "1" ]]; do
sleep 1
WAIT=$((WAIT - 1))
done
# umount loop devices (openwrt will auto mount some partition)
MOUNTED_DEVS=$(lsblk -l -o NAME,PATH,MOUNTPOINT | grep "${LOOP_DEV}" | awk '$3 !~ /^$/ {print $2}')
for dev in ${MOUNTED_DEVS}; do
while :; do
echo "umount [ ${dev} ] ... "
umount -f ${dev}
sleep 1
mnt=$(lsblk -l -o NAME,PATH,MOUNTPOINT | grep "${dev}" | awk '$3 !~ /^$/ {print $2}')
if [ "${mnt}" == "" ]; then
break
else
echo "Retry ..."
fi
done
done
# mount src part
WORK_DIR=${PWD}
P1=${WORK_DIR}/boot
P2=${WORK_DIR}/root
mkdir -p $P1 $P2
echo "Mount [ ${LOOP_DEV}p1 ] -> [ ${P1} ] ... "
mount -t vfat -o ro ${LOOP_DEV}p1 ${P1}
if [ $? -ne 0 ]; then
echo "Mount p1 [ ${LOOP_DEV}p1 ] failed!"
losetup -D
exit 1
fi
echo "Mount [ ${LOOP_DEV}p2 ] -> [ ${P2} ] ... "
ZSTD_LEVEL=6
mount -t btrfs -o ro,compress=zstd:${ZSTD_LEVEL} ${LOOP_DEV}p2 ${P2}
if [ $? -ne 0 ]; then
echo "Mount p2 [ ${LOOP_DEV}p2 ] failed!"
umount -f ${P1}
losetup -D
exit 1
fi
# Prepare the dockerman config file
if [ -f ${P2}/etc/init.d/dockerman ] && [ -f ${P2}/etc/config/dockerd ]; then
flg=0
# get current docker data root
data_root=$(uci get dockerd.globals.data_root 2>/dev/null)
if [ "${data_root}" == "" ]; then
flg=1
# get current config from /etc/docker/daemon.json
if [ -f "/etc/docker/daemon.json" ] && [ -x "/usr/bin/jq" ]; then
data_root=$(jq -r '."data-root"' /etc/docker/daemon.json)
bip=$(jq -r '."bip"' /etc/docker/daemon.json)
[ "${bip}" == "null" ] && bip="172.31.0.1/24"
log_level=$(jq -r '."log-level"' /etc/docker/daemon.json)
[ "${log_level}" == "null" ] && log_level="warn"
_iptables=$(jq -r '."iptables"' /etc/docker/daemon.json)
[ "${_iptables}" == "null" ] && _iptables="true"
registry_mirrors=$(jq -r '."registry-mirrors"[]' /etc/docker/daemon.json 2>/dev/null)
fi
fi
if [ "${data_root}" == "" ]; then
data_root="/opt/docker/" # the default data root
fi
if ! uci get dockerd.globals >/dev/null 2>&1; then
uci set dockerd.globals='globals'
uci commit
fi
# delete alter config , use inner config
if uci get dockerd.globals.alt_config_file >/dev/null 2>&1; then
uci delete dockerd.globals.alt_config_file
uci commit
fi
if [ ${flg} -eq 1 ]; then
uci set dockerd.globals.data_root=${data_root}
[ "${bip}" != "" ] && uci set dockerd.globals.bip=${bip}
[ "${log_level}" != "" ] && uci set dockerd.globals.log_level=${log_level}
[ "${_iptables}" != "" ] && uci set dockerd.globals.iptables=${_iptables}
if [ "${registry_mirrors}" != "" ]; then
for reg in ${registry_mirrors}; do
uci add_list dockerd.globals.registry_mirrors=${reg}
done
fi
uci set dockerd.globals.auto_start='1'
uci commit
fi
fi
#update version prompt
source /boot/uEnv.txt 2>/dev/null
CUR_FDTFILE=${FDT}
echo -e "FDT Value [ ${CUR_FDTFILE} ]"
cp /boot/uEnv.txt /tmp/uEnv.txt && sync
K510="1"
[[ "$(hexdump -n 15 -x "${P1}/zImage" 2>/dev/null | head -n 1 | awk '{print $7}')" == "0108" ]] && K510="0"
echo -e "K510 [ ${K510} ]"
# flippy-openwrt-release info
UBOOT_OVERLOAD=""
MAINLINE_UBOOT=""
ANDROID_UBOOT=""
env_openwrt_file=""
if [ -f "${P2}/etc/flippy-openwrt-release" ]; then
env_openwrt_file="${P2}/etc/flippy-openwrt-release"
elif [ -f "/etc/flippy-openwrt-release" ]; then
env_openwrt_file="/etc/flippy-openwrt-release"
else
env_openwrt_file=""
fi
if [ -n "${env_openwrt_file}" ]; then
source "${env_openwrt_file}" 2>/dev/null
# Update the parameters used
UBOOT_OVERLOAD=${UBOOT_OVERLOAD}
MAINLINE_UBOOT=${MAINLINE_UBOOT}
ANDROID_UBOOT=${ANDROID_UBOOT}
# Unused parameters
FDTFILE=${FDTFILE}
U_BOOT_EXT=${U_BOOT_EXT}
KERNEL_VERSION=${KERNEL_VERSION}
SOC=${SOC}
fi
#format NEW_ROOT
echo "umount [ ${NEW_ROOT_MP} ]"
umount -f "${NEW_ROOT_MP}"
if [[ "${?}" -ne "0" ]]; then
echo "Umount [ ${NEW_ROOT_MP} ] failed, Please restart and try again!"
umount -f ${P1}
umount -f ${P2}
losetup -D
exit 1
fi
# check and fix partition
function check_and_fix_partition() {
local target_dev_name=${1} # mmcblk2
local target_pt_name=${2} # p2
local target_pt_idx=${3} # 2
local safe_pt_begin_mb=${4} # 800
local safe_pt_begin_byte=$((${safe_pt_begin_mb} * 1024 * 1024))
local cur_pt_begin_sector=$(fdisk -l /dev/${target_dev_name} | grep ${target_dev_name}${target_pt_name} | awk '{printf $2}')
local cur_pt_begin_mb=$((${cur_pt_begin_sector} * 512 / 1024 / 1024))
if [ ${cur_pt_begin_mb} -ge ${safe_pt_begin_mb} ]; then
# check pass
return
fi
local cur_pt_end_sector=$(fdisk -l /dev/${target_dev_name} | grep ${target_dev_name}${target_pt_name} | awk '{printf $3}')
local cur_pt_end_byte=$(((${cur_pt_end_sector} + 1) * 512 - 1))
echo "Unsafe partition found, repairing ... "
parted /dev/${target_dev_name} rm ${target_pt_idx} ||
(
error_msg "rm partion ${target_pt_idx} failed"
)
parted /dev/${target_dev_name} mkpart primary btrfs "${safe_pt_begin_byte}b" "${cur_pt_end_byte}b" ||
(
error_msg "create new partion ${target_pt_idx} failed"
)
echo "Partition repaired"
}
# check if need fix partition
if [ "${NEW_ROOT_NAME}" == "mmcblk2p2" ]; then
if [ "${MYDEVICE_NAME}" == "Phicomm N1" ] || [ "${MYDEVICE_NAME}" == "Octopus Planet" ]; then
# 最新研究结果:
# Phicomm N1当采用官方 "天天链" 固件底包时,
# 796MB开始的 12 字节在每次重启后会被 bootloader 覆写,
# 因此把安全位置设定在800MB之后
# The latest research results:
# When Phicomm N1 uses the official "tian tian lian" firmware bottom package,
# the 12 bytes starting from 796MB will be overwritten by bootloader after each reboot,
# so the safe location is set after 800MB
SAFE_PT_BEGIN_MB=800
check_and_fix_partition "${EMMC_NAME}" "p2" 2 ${SAFE_PT_BEGIN_MB}
fi
fi
echo "Format [ ${NEW_ROOT_PATH} ]"
NEW_ROOT_UUID=$(uuidgen)
mkfs.btrfs -f -U ${NEW_ROOT_UUID} -L ${NEW_ROOT_LABEL} -m single ${NEW_ROOT_PATH}
if [ $? -ne 0 ]; then
echo "Format [ ${NEW_ROOT_PATH} ] failed!"
umount -f ${P1}
umount -f ${P2}
losetup -D
exit 1
fi
echo "Mount [ ${NEW_ROOT_PATH} ] -> [ ${NEW_ROOT_MP} ]"
mount -t btrfs -o compress=zstd:${ZSTD_LEVEL} ${NEW_ROOT_PATH} ${NEW_ROOT_MP}
if [ $? -ne 0 ]; then
echo "Mount [ ${NEW_ROOT_PATH} ] -> [ ${NEW_ROOT_MP} ] failed!"
umount -f ${P1}
umount -f ${P2}
losetup -D
exit 1
fi
# begin copy rootfs
cd ${NEW_ROOT_MP}
echo "Start copying data, From [ ${P2} ] TO [ ${NEW_ROOT_MP} ] ..."
ENTRYS=$(ls)
for entry in ${ENTRYS}; do
if [[ "${entry}" == "lost+found" ]]; then
continue
fi
echo "Remove old [ ${entry} ] ... "
rm -rf ${entry}
if [[ "${?}" -ne "0" ]]; then
error_msg "failed."
fi
done
echo "Create folder ... "
btrfs subvolume create etc
mkdir -p .snapshots .reserved bin boot dev lib opt mnt overlay proc rom root run sbin sys tmp usr www
ln -sf lib/ lib64
ln -sf tmp/ var
sync
COPY_SRC="root etc bin sbin lib opt usr www"
echo "Copy data begin ... "
for src in ${COPY_SRC}; do
echo "Copy [ ${src} ] ... "
(cd ${P2} && tar cf - ${src}) | tar xf -
sync
done
# if not backup, then force rewrite the etc/docker/daemon.json
if [ "${BR_FLAG}" -eq 0 ]; then
cat >./etc/docker/daemon.json <<EOF
{
"bip": "172.31.0.1/24",
"data-root": "${DOCKER_ROOT}",
"log-level": "warn",
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "5"
},
"registry-mirrors": [
"https://mirror.baidubce.com/",
"https://hub-mirror.c.163.com"
]
}
EOF
fi
cat >./etc/fstab <<EOF
UUID=${NEW_ROOT_UUID} / btrfs compress=zstd:${ZSTD_LEVEL} 0 1
LABEL=${LB_PRE}BOOT /boot vfat defaults 0 2
#tmpfs /tmp tmpfs defaults,nosuid 0 0
EOF
cat >./etc/config/fstab <<EOF
config global
option anon_swap '0'
option anon_mount '1'
option auto_swap '0'
option auto_mount '1'
option delay_root '5'
option check_fs '0'
config mount
option target '/rom'
option uuid '${NEW_ROOT_UUID}'
option enabled '1'
option enabled_fsck '1'
option fstype 'btrfs'
option options 'compress=zstd:${ZSTD_LEVEL}'
config mount
option target '/boot'
option label '${LB_PRE}BOOT'
option enabled '1'
option enabled_fsck '1'
option fstype 'vfat'
EOF
(
cd etc/rc.d
rm -f S??shortcut-fe
if grep "sfe_flow '1'" ../config/turboacc >/dev/null; then
if find ../../lib/modules -name 'shortcut-fe-cm.ko'; then
ln -sf ../init.d/shortcut-fe S99shortcut-fe
fi
fi
)
# move /etc/config/balance_irq to /etc/balance_irq
[ -f "./etc/config/balance_irq" ] && mv ./etc/config/balance_irq ./etc/
sync
echo "Create initial etc snapshot -> .snapshots/etc-000"
btrfs subvolume snapshot -r etc .snapshots/etc-000
sync
[ -d /mnt/${EMMC_NAME}${PARTITION_NAME}4/docker ] || mkdir -p /mnt/${EMMC_NAME}${PARTITION_NAME}4/docker
rm -rf opt/docker && ln -sf /mnt/${EMMC_NAME}${PARTITION_NAME}4/docker/ opt/docker
if [ -f /mnt/${NEW_ROOT_NAME}/etc/config/AdGuardHome ]; then
[ -d /mnt/${EMMC_NAME}${PARTITION_NAME}4/AdGuardHome/data ] || mkdir -p /mnt/${EMMC_NAME}${PARTITION_NAME}4/AdGuardHome/data
if [ ! -L /usr/bin/AdGuardHome ]; then
[ -d /usr/bin/AdGuardHome ] &&
cp -a /usr/bin/AdGuardHome/* /mnt/${EMMC_NAME}${PARTITION_NAME}4/AdGuardHome/
fi
ln -sf /mnt/${EMMC_NAME}${PARTITION_NAME}4/AdGuardHome /mnt/${NEW_ROOT_NAME}/usr/bin/AdGuardHome
fi
#rm -f /mnt/${NEW_ROOT_NAME}/usr/sbin/openwrt-install-amlogic
#rm -f /mnt/${NEW_ROOT_NAME}/usr/sbin/openwrt-update-amlogic
rm -f /mnt/${NEW_ROOT_NAME}/root/install-to-emmc.sh
sync
echo "Copy data complete ..."
BACKUP_LIST=$(${P2}/usr/sbin/openwrt-backup -p)
if [[ "${BR_FLAG}" -eq "1" && -n "${BACKUP_LIST}" ]]; then
echo -n "Start restoring configuration files ... "
(
cd /
eval tar czf ${NEW_ROOT_MP}/.reserved/openwrt_config.tar.gz "${BACKUP_LIST}" 2>/dev/null
)
tar xzf ${NEW_ROOT_MP}/.reserved/openwrt_config.tar.gz
[ -f ./etc/config/dockerman ] && sed -e "s/option wan_mode 'false'/option wan_mode 'true'/" -i ./etc/config/dockerman 2>/dev/null
[ -f ./etc/config/dockerd ] && sed -e "s/option wan_mode '0'/option wan_mode '1'/" -i ./etc/config/dockerd 2>/dev/null
[ -f ./etc/config/verysync ] && sed -e 's/config setting/config verysync/' -i ./etc/config/verysync 2>/dev/null
# Restore fstab
cp -f .snapshots/etc-000/fstab ./etc/fstab
cp -f .snapshots/etc-000/config/fstab ./etc/config/fstab
# 还原 luci
cp -f .snapshots/etc-000/config/luci ./etc/config/luci
# 还原/etc/config/rpcd
cp -f .snapshots/etc-000/config/rpcd ./etc/config/rpcd
sync
echo "Restore configuration information complete."
fi
echo "Modify the configuration file ... "
rm -f "./etc/rc.local.orig" "./etc/first_run.sh" "./etc/part_size"
rm -rf "./opt/docker" && ln -sf "/mnt/${EMMC_NAME}${PARTITION_NAME}4/docker" "./opt/docker"
rm -f ./etc/bench.log
cat >>./etc/crontabs/root <<EOF
37 5 * * * /etc/coremark.sh
EOF
sed -e 's/ttyAMA0/ttyAML0/' -i ./etc/inittab
sed -e 's/ttyS0/tty0/' -i ./etc/inittab
sss=$(date +%s)
ddd=$((sss / 86400))
sed -e "s/:0:0:99999:7:::/:${ddd}:0:99999:7:::/" -i ./etc/shadow
# Fix the problem of repeatedly adding amule entries after each upgrade
sed -e "/amule:x:/d" -i ./etc/shadow
# Fix the problem of repeatedly adding sshd entries after each upgrade of dropbear
sed -e "/sshd:x:/d" -i ./etc/shadow
if ! grep "sshd:x:22:sshd" ./etc/group >/dev/null; then
echo "sshd:x:22:sshd" >>./etc/group
fi
if ! grep "sshd:x:22:22:sshd:" ./etc/passwd >/dev/null; then
echo "sshd:x:22:22:sshd:/var/run/sshd:/bin/false" >>./etc/passwd
fi
if ! grep "sshd:x:" ./etc/shadow >/dev/null; then
echo "sshd:x:${ddd}:0:99999:7:::" >>./etc/shadow
fi
if [ "${BR_FLAG}" -eq "1" ]; then
if [ -x ./bin/bash ] && [ -f ./etc/profile.d/30-sysinfo.sh ]; then
sed -e 's/\/bin\/ash/\/bin\/bash/' -i ./etc/passwd
fi
sync
fi
sed -e "s/option hw_flow '1'/option hw_flow '0'/" -i ./etc/config/turboacc
(
cd etc/rc.d
rm -f S??shortcut-fe
if grep "sfe_flow '1'" ../config/turboacc >/dev/null; then
if find ../../lib/modules -name 'shortcut-fe-cm.ko'; then
ln -sf ../init.d/shortcut-fe S99shortcut-fe
fi
fi
)
eval tar czf .reserved/openwrt_config.tar.gz "${BACKUP_LIST}" 2>/dev/null
rm -f ./etc/part_size ./etc/first_run.sh
if [ -x ./usr/sbin/balethirq.pl ]; then
if grep "balethirq.pl" "./etc/rc.local"; then
echo "balance irq is enabled"
else
echo "enable balance irq"
sed -e "/exit/i\/usr/sbin/balethirq.pl" -i ./etc/rc.local
fi
fi
mv ./etc/rc.local ./etc/rc.local.orig
cat >"./etc/rc.local" <<EOF
if ! ls /etc/rc.d/S??dockerd >/dev/null 2>&1;then
/etc/init.d/dockerd enable
/etc/init.d/dockerd start
fi
if ! ls /etc/rc.d/S??dockerman >/dev/null 2>&1 && [ -f /etc/init.d/dockerman ];then
/etc/init.d/dockerman enable
/etc/init.d/dockerman start
fi
mv /etc/rc.local.orig /etc/rc.local
chmod 755 /etc/rc.local
exec /etc/rc.local
exit
EOF
chmod 755 ./etc/rc.local*
#Mainline U-BOOT detection
FLASH_MAINLINE_UBOOT=0
if [[ -n "${MAINLINE_UBOOT}" && -f "${P2}${MAINLINE_UBOOT}" ]]; then
cat <<EOF
----------------------------------------------------------------------------------
Found an available mainline bootloader (Mainline u-boot), you can flash into EMMC.
----------------------------------------------------------------------------------
EOF
while :; do
if [[ "${AUTO_MAINLINE_UBOOT}" == "yes" ]]; then
if [[ "${K510}" -eq "1" ]]; then
yn="y"
else
yn="n"
fi
elif [[ "${AUTO_MAINLINE_UBOOT}" == "no" ]]; then
yn="n"
else
read -p "Please choose whether to write the mainline bootloader to EMMC? y/n " yn
fi
case ${yn} in
y | Y)
FLASH_MAINLINE_UBOOT=1
break
;;
n | N)
FLASH_MAINLINE_UBOOT=0
break
;;
esac
done
fi
if [[ "${FLASH_MAINLINE_UBOOT}" -eq "1" ]]; then
echo -e "Write Mainline bootloader: [ ${MAINLINE_UBOOT} ]"
dd if=${P2}${MAINLINE_UBOOT} of=/dev/${EMMC_NAME} bs=1 count=444 conv=fsync
dd if=${P2}${MAINLINE_UBOOT} of=/dev/${EMMC_NAME} bs=512 skip=1 seek=1 conv=fsync
elif [[ -n "${ANDROID_UBOOT}" && -f "${P2}${ANDROID_UBOOT}" ]]; then
echo -e "Write Android bootloader: [ ${ANDROID_UBOOT} ]"
dd if=${P2}${ANDROID_UBOOT} of=/dev/${EMMC_NAME} bs=1 count=444 conv=fsync
dd if=${P2}${ANDROID_UBOOT} of=/dev/${EMMC_NAME} bs=512 skip=1 seek=1 conv=fsync
else
echo "Did not change the original bootloader."
fi
# move /etc/config/balance_irq to /etc/balance_irq
[ -f "./etc/config/balance_irq" ] && mv ./etc/config/balance_irq ./etc/
echo "Create etc snapshot -> .snapshots/etc-001"
btrfs subvolume snapshot -r etc .snapshots/etc-001
cd ${WORK_DIR}
echo "Change the label of ${BOOT_PATH} ... "
fatlabel ${BOOT_PATH} "${LB_PRE}BOOT"
echo "Start copying data, from [ ${P1} ] to [ /boot ] ..."
cd /boot
echo "Delete the old boot file ..."
rm -rf * && sync
echo "Copy the new boot file ... "
(cd ${P1} && tar cf - .) | tar xf - 2>/dev/null
sync
if [ -f ${P1}/uInitrd ]; then
i=1
max_try=10
while [ "${i}" -le "${max_try}" ]; do
uInitrd_original=$(md5sum ${P1}/uInitrd | awk '{print $1}')
uInitrd_new=$(md5sum uInitrd | awk '{print $1}')
if [ "${uInitrd_original}" = "${uInitrd_new}" ]; then
break
else
rm -f uInitrd && sync
cp -f ${P1}/uInitrd uInitrd 2>/dev/null && sync
let i++
continue
fi
done
[ "${i}" -eq "10" ] && error_msg "uInitrd file copy failed."
else
echo "uInitrd file is missing."
fi
if [ -f ${P1}/zImage ]; then
i=1
max_try=10
while [ "${i}" -le "${max_try}" ]; do
zImage_original=$(md5sum ${P1}/zImage | awk '{print $1}')
zImage_new=$(md5sum zImage | awk '{print $1}')
if [ "${zImage_original}" = "${zImage_new}" ]; then
break
else
rm -f zImage && sync
cp -f ${P1}/zImage zImage 2>/dev/null && sync
let i++
continue
fi
done
[ "${i}" -eq "10" ] && error_msg "zImage file copy failed."
else
error_msg "zImage file is missing."
fi
if [ ${ROOT_DISK_TYPE} == "EMMC" ]; then
rm -f s905_autoscript* aml_autoscript*
mv -f boot-emmc.ini boot.ini
mv -f boot-emmc.cmd boot.cmd
mv -f boot-emmc.scr boot.scr
fi
if [ "${K510}" -eq "1" ]; then
if [ -f "u-boot.ext" ]; then
cp -vf u-boot.ext u-boot.emmc
elif [ -f ${P1}/${UBOOT_OVERLOAD} ]; then
cp -vf ${P1}/${UBOOT_OVERLOAD} ${UBOOT_OVERLOAD}
cp -vf ${P1}/${UBOOT_OVERLOAD} u-boot.ext
cp -vf ${P1}/${UBOOT_OVERLOAD} u-boot.emmc
chmod +x u-boot*
fi
else
rm -f u-boot.ext 2>/dev/null
rm -f u-boot.emmc 2>/dev/null
fi
sync
echo "Update boot parameters ... "
if [ -f /tmp/uEnv.txt ]; then
lines=$(wc -l </tmp/uEnv.txt)
lines=$((lines - 1))
head -n $lines /tmp/uEnv.txt >uEnv.txt
cat >>uEnv.txt <<EOF
APPEND=root=UUID=${NEW_ROOT_UUID} rootfstype=btrfs rootflags=compress=zstd:${ZSTD_LEVEL} console=ttyAML0,115200n8 console=tty0 no_console_suspend consoleblank=0 fsck.fix=yes fsck.repair=yes net.ifnames=0 cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory swapaccount=1
EOF
else
cat >uEnv.txt <<EOF
LINUX=/zImage
INITRD=/uInitrd
FDT=${CUR_FDTFILE}
APPEND=root=UUID=${NEW_ROOT_UUID} rootfstype=btrfs rootflags=compress=zstd:${ZSTD_LEVEL} console=ttyAML0,115200n8 console=tty0 no_console_suspend consoleblank=0 fsck.fix=yes fsck.repair=yes net.ifnames=0 cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory swapaccount=1
EOF
fi
sync
# Replace the UUID for extlinux/extlinux.conf if it exists
[[ -f "extlinux/extlinux.conf" ]] && {
sed -i -E "s|UUID=[^ ]*|UUID=${NEW_ROOT_UUID}|" extlinux/extlinux.conf 2>/dev/null
}
cd $WORK_DIR
umount -f ${P1} ${P2} 2>/dev/null
losetup -D 2>/dev/null
rm -rf ${P1} ${P2} 2>/dev/null
rm -f ${IMG_NAME} 2>/dev/null
rm -f sha256sums 2>/dev/null
sync
wait
echo "Successfully updated, automatic restarting..."
sleep 3
reboot
exit 0
+674
View File
@@ -0,0 +1,674 @@
#!/bin/bash
#======================================================================================
# Function: Update the QEMU AARCH64 KVM vitual machine openwrt firmware
# Copyright (C) 2022-- https://github.com/unifreq/openwrt_packit
# Copyright (C) 2022-- https://github.com/ophub
#======================================================================================
#
# The script supports directly setting parameters for update, skipping interactive selection
# openwrt-update-amlogic ${OPENWRT_FILE} ${AUTO_MAINLINE_UBOOT} ${RESTORE_CONFIG} ${WORK_DIR}
# E.g: openwrt-update-kvm openwrt_qemu-aarch64.img.gz no restore /mnt/vda4
# E.g: openwrt-update-kvm openwrt_qemu-aarch64.img.gz no no-restore /mnt/data
# You can also execute the script directly, and interactively select related functions
# E.g: openwrt-update-kvm
#
#======================================================================================
# Encountered a serious error, abort the script execution
error_msg() {
echo -e "[ERROR] ${1}"
exit 1
}
# Get the partition name of the /boot file system
get_boot_partition_name() {
local paths="/boot"
local partition_name
partition_name=$(df "${paths}" | awk 'NR==2 {print $1}' | awk -F '/' '{print $3}')
echo "${partition_name}"
}
# Get the partition name of the root file system
get_root_partition_name() {
local paths=("/" "/overlay" "/rom")
local partition_name
for path in "${paths[@]}"; do
partition_name=$(df "${path}" | awk 'NR==2 {print $1}' | awk -F '/' '{print $3}')
[[ -n "${partition_name}" ]] && break
done
echo "${partition_name}"
}
# Get the partition message of the root file system
get_root_partition_msg() {
local paths=("/" "/overlay" "/rom")
local partition_name
for path in "${paths[@]}"; do
partition_msg=$(lsblk -l -o NAME,PATH,TYPE,UUID,MOUNTPOINT | awk '$3~/^part$/ && $5 ~ "^" "'"${path}"'" "$" {print $0}')
[[ -n "${partition_msg}" ]] && break
done
[[ -z "${partition_msg}" ]] && error_msg "Cannot find the root partition message!"
echo "${partition_msg}"
}
# Receive one-key command related parameters
IMG_NAME="${1}"
AUTO_MAINLINE_UBOOT="${2}"
BACKUP_RESTORE_CONFIG="${3}"
WORK_DIR="${4}"
# Check the necessary dependencies
DEPENDS="lsblk uuidgen grep awk btrfs mkfs.fat mkfs.btrfs md5sum fatlabel jq"
echo "Check the necessary dependencies..."
for dep in ${DEPENDS}; do
WITCH=$(busybox which ${dep})
if [ "${WITCH}" == "" ]; then
error_msg "Dependent command: ${dep} does not exist, upgrade cannot be performed!"
else
echo "${dep} path: ${WITCH}"
fi
done
echo "Check passed"
# Current device model
source /etc/flippy-openwrt-release
if [[ -z "${PLATFORM}" ]]; then
error_msg "The platform is empty."
elif [[ "${PLATFORM}" != "qemu-aarch64" ]]; then
error_msg "The platform is missing, only support qemu-aarch64."
else
echo -e "Current platform: [ ${PLATFORM} ]"
sleep 3
fi
# Check and repair partition mount points
[[ -z "$(get_boot_partition_name)" || -z "$(get_root_partition_name)" ]] && {
echo -e "Partition mount point error, start repairing..."
openwrt-backup -g
}
# Find the partition where root is located
# vda2 or vda3
ROOT_PTNAME="$(get_root_partition_name)"
# Find the disk where the partition is located, only supports sd?? hd?? vd??
case ${ROOT_PTNAME} in
[hsv]d[a-z][1-4])
DISK_NAME=$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-1)}')
PART_PRESTR=""
LABEL_PRESTR=""
;;
*)
error_msg "Unable to recognize the disk type of ${ROOT_PTNAME}!"
;;
esac
function get_docker_root {
local data_root
if [[ -f /etc/config/dockerd ]]; then
data_root=$(uci get dockerd.globals.data_root)
fi
if [[ -z "${data_root}" ]] && [[ -f /etc/docker/daemon.json ]]; then
data_root=$(jq -r '."data-root"' /etc/docker/daemon.json)
fi
echo "$data_root"
}
DOCKER_ROOT=$(get_docker_root)
if [[ -z "${WORK_DIR}" ]]; then
WORK_DIR="/mnt/${DISK_NAME}${PART_PRESTR}4/"
fi
if [[ ! -d "${WORK_DIR}" ]]; then
error_msg "the work directory is not exists. [ ${WORK_DIR} ]"
fi
cd "${WORK_DIR}"
if [[ -d "/tmp/upload" ]] && [[ -f "/tmp/upload/*img*" ]]; then
mv -f /tmp/upload/*img* .
if [[ $? -ne 0 ]]; then
error_msg "move file failed."
fi
fi
sync
if [[ "${IMG_NAME}" == *.img ]]; then
echo -e "Update using [ ${IMG_NAME} ] file. Please wait a moment ..."
elif [ $(ls *.img -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
IMG_NAME=$(ls *.img | head -n 1)
echo -e "Update using [ ${IMG_NAME} ] ] file. Please wait a moment ..."
elif [ $(ls *.img.xz -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
xz_file=$(ls *.img.xz | head -n 1)
echo -e "Update using [ ${xz_file} ] file. Please wait a moment ..."
xz -d ${xz_file} 2>/dev/null
IMG_NAME=$(ls *.img | head -n 1)
elif [ $(ls *.img.gz -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
gz_file=$(ls *.img.gz | head -n 1)
echo -e "Update using [ ${gz_file} ] file. Please wait a moment ..."
gzip -df ${gz_file} 2>/dev/null
IMG_NAME=$(ls *.img | head -n 1)
elif [ $(ls *.7z -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
gz_file=$(ls *.7z | head -n 1)
echo -e "Update using [ ${gz_file} ] file. Please wait a moment ..."
bsdtar -xmf ${gz_file} 2>/dev/null
[ $? -eq 0 ] || 7z x ${gz_file} -aoa -y 2>/dev/null
IMG_NAME=$(ls *.img | head -n 1)
elif [ $(ls *.zip -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
zip_file=$(ls *.zip | head -n 1)
echo -e "Update using [ ${zip_file} ] file. Please wait a moment ..."
unzip -o ${zip_file} 2>/dev/null
IMG_NAME=$(ls *.img | head -n 1)
else
echo -e "Please upload or specify the update openwrt firmware file."
#echo -e "Upload method: system menu → Amlogic Service → Manually Upload Update"
echo -e "Specify method: Place the openwrt firmware file in [ ${WORK_DIR} ]"
echo -e "The supported file suffixes are: *.img, *.img.xz, *.img.gz, *.7z, *.zip"
echo -e "After upload the openwrt firmware file, run again."
exit 1
fi
sync
# check file
if [ ! -f "${IMG_NAME}" ]; then
error_msg "No update file found."
else
echo "Start update from [ ${IMG_NAME} ]"
fi
# find efi partition
EFI_PART_MSG=$(lsblk -l -o NAME,PATH,TYPE,UUID,MOUNTPOINT | awk '$3~/^part$/ && $5 ~ /^\/boot\/efi$/ {print $0}')
if [ "${EFI_PART_MSG}" == "" ]; then
error_msg "The EFI partition does not exist, so the update cannot be continued!"
fi
EFI_NAME=$(echo $EFI_PART_MSG | awk '{print $1}')
EFI_DEV=$(echo $EFI_PART_MSG | awk '{print $2}')
EFI_UUID=$(echo $EFI_PART_MSG | awk '{print $4}')
BR_FLAG=1
if [[ ${BACKUP_RESTORE_CONFIG} == "restore" ]]; then
BR_FLAG=1
elif [[ ${BACKUP_RESTORE_CONFIG} == "no-restore" ]]; then
BR_FLAG=0
else
echo -ne "Whether to backup and restore the current config files? y/n [y]\b\b"
read yn
case $yn in
n* | N*) BR_FLAG=0 ;;
esac
fi
# find root partition
ROOT_PART_MSG="$(get_root_partition_msg)"
ROOT_NAME=$(echo ${ROOT_PART_MSG} | awk '{print $1}')
ROOT_DEV=$(echo ${ROOT_PART_MSG} | awk '{print $2}')
ROOT_UUID=$(echo ${ROOT_PART_MSG} | awk '{print $4}')
case ${ROOT_NAME} in
${DISK_NAME}${PART_PRESTR}2)
NEW_ROOT_NAME="${DISK_NAME}${PART_PRESTR}3"
NEW_ROOT_LABEL="${LABEL_PRESTR}ROOTFS2"
;;
${DISK_NAME}${PART_PRESTR}3)
NEW_ROOT_NAME="${DISK_NAME}${PART_PRESTR}2"
NEW_ROOT_LABEL="${LABEL_PRESTR}ROOTFS1"
;;
*)
error_msg "ROOTFS The partition location is incorrect, so the update cannot continue!"
;;
esac
echo "NEW_ROOT_NAME: [ ${NEW_ROOT_NAME} ]"
# find new root partition
NEW_ROOT_PART_MSG=$(lsblk -l -o NAME,PATH,TYPE,UUID,MOUNTPOINT | grep "${NEW_ROOT_NAME}" | awk '$3 ~ /^part$/ && $5 !~ /^\/$/ && $5 !~ /^\/boot$/ {print $0}')
if [ "${NEW_ROOT_PART_MSG}" == "" ]; then
error_msg "The new ROOTFS partition does not exist, so the update cannot continue!"
fi
NEW_ROOT_NAME=$(echo $NEW_ROOT_PART_MSG | awk '{print $1}')
NEW_ROOT_DEV=$(echo $NEW_ROOT_PART_MSG | awk '{print $2}')
NEW_ROOT_UUID=$(echo $NEW_ROOT_PART_MSG | awk '{print $4}')
NEW_ROOT_MOUNTPOINT=$(echo $NEW_ROOT_PART_MSG | awk '{print $5}')
echo "NEW_ROOT_MOUNTPOINT: [ ${NEW_ROOT_MOUNTPOINT} ]"
# losetup
losetup -f -P $IMG_NAME
if [ $? -eq 0 ]; then
LOOP_DEV=$(losetup | grep "$IMG_NAME" | awk '{print $1}')
if [ "$LOOP_DEV" == "" ]; then
error_msg "loop device not found!"
fi
else
error_msg "losetup [ $IMG_FILE ] failed!"
fi
# fix loopdev issue in kernel 5.19
function fix_loopdev() {
local parentdev=${1##*/}
if [ ! -d /sys/block/${parentdev} ]; then
return
fi
subdevs=$(lsblk -l -o NAME | grep -E "^${parentdev}.+\$")
for subdev in $subdevs; do
if [ ! -d /sys/block/${parentdev}/${subdev} ]; then
return
elif [ -b /dev/${sub_dev} ]; then
continue
fi
source /sys/block/${parentdev}/${subdev}/uevent
mknod /dev/${subdev} b ${MAJOR} ${MINOR}
unset MAJOR MINOR DEVNAME DEVTYPE DISKSEQ PARTN PARTNAME
done
}
fix_loopdev ${LOOP_DEV}
WAIT=3
echo "The loopdev is [ $LOOP_DEV ], wait [ ${WAIT} ] seconds. "
while [ $WAIT -ge 1 ]; do
sleep 1
WAIT=$((WAIT - 1))
done
# umount loop devices (openwrt will auto mount some partition)
MOUNTED_DEVS=$(lsblk -l -o NAME,PATH,MOUNTPOINT | grep "$LOOP_DEV" | awk '$3 !~ /^$/ {print $2}')
for dev in $MOUNTED_DEVS; do
while :; do
echo "umount [ $dev ] ... "
umount -f $dev
sleep 1
mnt=$(lsblk -l -o NAME,PATH,MOUNTPOINT | grep "$dev" | awk '$3 !~ /^$/ {print $2}')
if [ "$mnt" == "" ]; then
break
else
echo "Retry ..."
fi
done
done
# mount src part
P1=${WORK_DIR}/efi
P2=${WORK_DIR}/root
mkdir -p $P1 $P2
echo "Mount [ ${LOOP_DEV}p1 ] -> [ ${P1} ] ... "
mount -t vfat -o ro ${LOOP_DEV}p1 ${P1}
if [ $? -ne 0 ]; then
echo "Mount p1 [ ${LOOP_DEV}p1 ] failed!"
losetup -D
exit 1
fi
echo "Mount [ ${LOOP_DEV}p2 ] -> [ ${P2} ] ... "
ZSTD_LEVEL="6"
mount -t btrfs -o ro,compress=zstd:${ZSTD_LEVEL} ${LOOP_DEV}p2 ${P2}
if [ $? -ne 0 ]; then
echo "Mount p2 [ ${LOOP_DEV}p2 ] failed!"
umount -f ${P1}
losetup -D
exit 1
fi
# Prepare the dockerman config file
if [ -f ${P2}/etc/init.d/dockerman ] && [ -f ${P2}/etc/config/dockerd ]; then
flg=0
# get current docker data root
data_root=$(uci get dockerd.globals.data_root 2>/dev/null)
if [ "$data_root" == "" ]; then
flg=1
# get current config from /etc/docker/daemon.json
if [ -f "/etc/docker/daemon.json" ] && [ -x "/usr/bin/jq" ]; then
data_root=$(jq -r '."data-root"' /etc/docker/daemon.json)
bip=$(jq -r '."bip"' /etc/docker/daemon.json)
[ "$bip" == "null" ] && bip="172.31.0.1/24"
log_level=$(jq -r '."log-level"' /etc/docker/daemon.json)
[ "$log_level" == "null" ] && log_level="warn"
_iptables=$(jq -r '."iptables"' /etc/docker/daemon.json)
[ "$_iptables" == "null" ] && _iptables="true"
registry_mirrors=$(jq -r '."registry-mirrors"[]' /etc/docker/daemon.json 2>/dev/null)
fi
fi
if [ "$data_root" == "" ]; then
data_root="/opt/docker/" # the default data root
fi
if ! uci get dockerd.globals >/dev/null 2>&1; then
uci set dockerd.globals='globals'
uci commit
fi
# delete alter config , use inner config
if uci get dockerd.globals.alt_config_file >/dev/null 2>&1; then
uci delete dockerd.globals.alt_config_file
uci commit
fi
if [ $flg -eq 1 ]; then
uci set dockerd.globals.data_root=$data_root
[ "$bip" != "" ] && uci set dockerd.globals.bip=$bip
[ "$log_level" != "" ] && uci set dockerd.globals.log_level=$log_level
[ "$_iptables" != "" ] && uci set dockerd.globals.iptables=$_iptables
if [ "$registry_mirrors" != "" ]; then
for reg in $registry_mirrors; do
uci add_list dockerd.globals.registry_mirrors=$reg
done
fi
uci set dockerd.globals.auto_start='1'
uci commit
fi
fi
#format NEW_ROOT
echo "umount [ ${NEW_ROOT_MOUNTPOINT} ]"
umount -f "${NEW_ROOT_MOUNTPOINT}"
if [ $? -ne 0 ]; then
echo "Umount [ ${NEW_ROOT_MOUNTPOINT} ] failed, Please restart and try again!"
umount -f ${P1}
umount -f ${P2}
losetup -D
exit 1
fi
echo "Format [ ${NEW_ROOT_DEV} ]"
NEW_ROOT_UUID=$(uuidgen)
mkfs.btrfs -f -U ${NEW_ROOT_UUID} -L ${NEW_ROOT_LABEL} ${NEW_ROOT_DEV}
if [ $? -ne 0 ]; then
echo "Format [ ${NEW_ROOT_DEV} ] failed!"
umount -f ${P1}
umount -f ${P2}
losetup -D
exit 1
fi
echo "Mount [ ${NEW_ROOT_DEV} ] -> [ ${NEW_ROOT_MOUNTPOINT} ]"
mount -t btrfs -o compress=zstd:${ZSTD_LEVEL} ${NEW_ROOT_DEV} ${NEW_ROOT_MOUNTPOINT}
if [ $? -ne 0 ]; then
echo "Mount [ ${NEW_ROOT_DEV} ] -> [ ${NEW_ROOT_MOUNTPOINT} ] failed!"
umount -f ${P1}
umount -f ${P2}
losetup -D
exit 1
fi
# begin copy rootfs
cd ${NEW_ROOT_MOUNTPOINT}
echo "Start copying data, From [ ${P2} ] TO [ ${NEW_ROOT_MOUNTPOINT} ] ..."
ENTRYS=$(ls)
for entry in $ENTRYS; do
if [ "$entry" == "lost+found" ]; then
continue
fi
echo "Remove old [ $entry ] ... "
rm -rf $entry
if [ $? -ne 0 ]; then
error_msg "failed."
fi
done
echo "Create folder ... "
btrfs subvolume create etc
mkdir -p .snapshots .reserved bin boot dev lib opt mnt overlay proc rom root run sbin sys tmp usr www
ln -sf lib/ lib64
ln -sf tmp/ var
sync
COPY_SRC="boot root etc bin sbin lib opt usr www"
echo "Copy data begin ... "
for src in $COPY_SRC; do
echo "Copy [ $src ] ... "
(cd ${P2} && tar cf - $src) | tar xf -
sync
done
# if not backup, then force rewrite the etc/docker/daemon.json
if [ "${BR_FLAG}" -eq 0 ]; then
cat >./etc/docker/daemon.json <<EOF
{
"bip": "172.31.0.1/24",
"data-root": "${DOCKER_ROOT}",
"log-level": "warn",
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "5"
},
"registry-mirrors": [
"https://mirror.baidubce.com/",
"https://hub-mirror.c.163.com"
]
}
EOF
fi
cat >./etc/fstab <<EOF
UUID=${NEW_ROOT_UUID} / btrfs compress=zstd:${ZSTD_LEVEL} 0 1
LABEL=EFI /boot/efi vfat defaults 0 2
#tmpfs /tmp tmpfs defaults,nosuid 0 0
EOF
cat >./etc/config/fstab <<EOF
config global
option anon_swap '0'
option anon_mount '1'
option auto_swap '0'
option auto_mount '1'
option delay_root '5'
option check_fs '0'
config mount
option target '/rom'
option uuid '${NEW_ROOT_UUID}'
option enabled '1'
option enabled_fsck '1'
option fstype 'btrfs'
option options 'compress=zstd:${ZSTD_LEVEL}'
config mount
option target '/boot/efi'
option label 'EFI'
option enabled '1'
option enabled_fsck '1'
option fstype 'vfat'
EOF
(
cd etc/rc.d
rm -f S??shortcut-fe
if grep "sfe_flow '1'" ../config/turboacc >/dev/null; then
if find ../../lib/modules -name 'shortcut-fe-cm.ko'; then
ln -sf ../init.d/shortcut-fe S99shortcut-fe
fi
fi
)
# move /etc/config/balance_irq to /etc/balance_irq
[ -f "./etc/config/balance_irq" ] && mv ./etc/config/balance_irq ./etc/
sync
echo "Create initial etc snapshot -> .snapshots/etc-000"
btrfs subvolume snapshot -r etc .snapshots/etc-000
sync
[ -d /mnt/${DISK_NAME}${PART_PRESTR}4/docker ] || mkdir -p /mnt/${DISK_NAME}${PART_PRESTR}4/docker
rm -rf opt/docker && ln -sf /mnt/${DISK_NAME}${PART_PRESTR}4/docker/ opt/docker
if [ -f /mnt/${NEW_ROOT_NAME}/etc/config/AdGuardHome ]; then
[ -d /mnt/${DISK_NAME}${PART_PRESTR}4/AdGuardHome/data ] || mkdir -p /mnt/${DISK_NAME}${PART_PRESTR}4/AdGuardHome/data
if [ ! -L /usr/bin/AdGuardHome ]; then
[ -d /usr/bin/AdGuardHome ] &&
cp -a /usr/bin/AdGuardHome/* /mnt/${DISK_NAME}${PART_PRESTR}4/AdGuardHome/
fi
ln -sf /mnt/${DISK_NAME}${PART_PRESTR}4/AdGuardHome /mnt/${NEW_ROOT_NAME}/usr/bin/AdGuardHome
fi
sync
echo "Copy data complete ..."
BACKUP_LIST=$(${P2}/usr/sbin/openwrt-backup -p)
if [[ "${BR_FLAG}" -eq "1" && -n "${BACKUP_LIST}" ]]; then
echo -n "Start restoring configuration files ... "
(
cd /
eval tar czf ${NEW_ROOT_MOUNTPOINT}/.reserved/openwrt_config.tar.gz "${BACKUP_LIST}" 2>/dev/null
)
tar xzf ${NEW_ROOT_MOUNTPOINT}/.reserved/openwrt_config.tar.gz
[ -f ./etc/config/dockerman ] && sed -e "s/option wan_mode 'false'/option wan_mode 'true'/" -i ./etc/config/dockerman 2>/dev/null
[ -f ./etc/config/dockerd ] && sed -e "s/option wan_mode '0'/option wan_mode '1'/" -i ./etc/config/dockerd 2>/dev/null
[ -f ./etc/config/verysync ] && sed -e 's/config setting/config verysync/' -i ./etc/config/verysync 2>/dev/null
# Restore fstab
cp -f .snapshots/etc-000/fstab ./etc/fstab
cp -f .snapshots/etc-000/config/fstab ./etc/config/fstab
# 还原 luci
cp -f .snapshots/etc-000/config/luci ./etc/config/luci
# 还原/etc/config/rpcd
cp -f .snapshots/etc-000/config/rpcd ./etc/config/rpcd
sync
echo "Restore configuration information complete."
fi
echo "Modify the configuration file ... "
rm -f "./etc/rc.local.orig" "./etc/first_run.sh" "./etc/part_size"
rm -rf "./opt/docker" && ln -sf "/mnt/${DISK_NAME}${PART_PRESTR}4/docker" "./opt/docker"
rm -f ./etc/bench.log
cat >>./etc/crontabs/root <<EOF
37 5 * * * /etc/coremark.sh
EOF
sss=$(date +%s)
ddd=$((sss / 86400))
sed -e "s/:0:0:99999:7:::/:${ddd}:0:99999:7:::/" -i ./etc/shadow
# Fix the problem of repeatedly adding amule entries after each upgrade
sed -e "/amule:x:/d" -i ./etc/shadow
# Fix the problem of repeatedly adding sshd entries after each upgrade of dropbear
sed -e "/sshd:x:/d" -i ./etc/shadow
if ! grep "sshd:x:22:sshd" ./etc/group >/dev/null; then
echo "sshd:x:22:sshd" >>./etc/group
fi
if ! grep "sshd:x:22:22:sshd:" ./etc/passwd >/dev/null; then
echo "sshd:x:22:22:sshd:/var/run/sshd:/bin/false" >>./etc/passwd
fi
if ! grep "sshd:x:" ./etc/shadow >/dev/null; then
echo "sshd:x:${ddd}:0:99999:7:::" >>./etc/shadow
fi
if [ "${BR_FLAG}" -eq "1" ]; then
if [ -x ./bin/bash ] && [ -f ./etc/profile.d/30-sysinfo.sh ]; then
sed -e 's/\/bin\/ash/\/bin\/bash/' -i ./etc/passwd
fi
sync
fi
sed -e "s/option hw_flow '1'/option hw_flow '0'/" -i ./etc/config/turboacc
(
cd etc/rc.d
rm -f S??shortcut-fe
if grep "sfe_flow '1'" ../config/turboacc >/dev/null; then
if find ../../lib/modules -name 'shortcut-fe-cm.ko'; then
ln -sf ../init.d/shortcut-fe S99shortcut-fe
fi
fi
)
eval tar czf .reserved/openwrt_config.tar.gz "${BACKUP_LIST}" 2>/dev/null
rm -f ./etc/part_size ./etc/first_run.sh
if [ -x ./usr/sbin/balethirq.pl ]; then
if grep "balethirq.pl" "./etc/rc.local"; then
echo "balance irq is enabled"
else
echo "enable balance irq"
sed -e "/exit/i\/usr/sbin/balethirq.pl" -i ./etc/rc.local
fi
fi
mv ./etc/rc.local ./etc/rc.local.orig
cat >"./etc/rc.local" <<EOF
if ! ls /etc/rc.d/S??dockerd >/dev/null 2>&1;then
/etc/init.d/dockerd enable
/etc/init.d/dockerd start
fi
if ! ls /etc/rc.d/S??dockerman >/dev/null 2>&1 && [ -f /etc/init.d/dockerman ];then
/etc/init.d/dockerman enable
/etc/init.d/dockerman start
fi
mv /etc/rc.local.orig /etc/rc.local
chmod 755 /etc/rc.local
exec /etc/rc.local
exit
EOF
chmod 755 ./etc/rc.local*
# move /etc/config/balance_irq to /etc/balance_irq
[ -f "./etc/config/balance_irq" ] && mv ./etc/config/balance_irq ./etc/
echo "Create etc snapshot -> .snapshots/etc-001"
btrfs subvolume snapshot -r etc .snapshots/etc-001
cd ${WORK_DIR}
echo "Copy efi files ..."
fatlabel ${EFI_DEV} "EFI"
cd /boot/efi
mv ./EFI/BOOT/grub.cfg /tmp/grub.cfg.prev
rm -rf *
cp -a ${P1}/* .
# 如果想启动上一个版本的openwrt,可以把 /boot/efi/EFI/BOOT/grub.cfg.prev 复制成 /boot/efi/EFI/BOOT/grub.cfg
mv /tmp/grub.cfg.prev ./EFI/BOOT/
echo "Modify efi configuration ... "
cd /boot/efi/EFI/BOOT
cat >grub.cfg <<EOF
echo "search fs_uuid ${NEW_ROOT_UUID} ..."
search.fs_uuid ${NEW_ROOT_UUID} root
echo "root=\$root"
echo "set prefix ... "
set prefix=(\$root)'/boot/grub2'
echo "prefix=\$prefix"
source \${prefix}/grub.cfg
EOF
echo "Modify boot configuration ... "
cd ${NEW_ROOT_MOUNTPOINT}/boot/grub2
cat >grub.cfg <<EOF
insmod gzio
insmod part_gpt
insmod zstd
insmod btrfs
terminal_input console
terminal_output console
set default="0"
set timeout=3
menuentry "OpenWrt" {
echo 'Loading linux kernel ...'
linux /boot/vmlinuz root=UUID=${NEW_ROOT_UUID} rootfstype=btrfs rootflags=compress=zstd:${ZSTD_LEVEL} console=ttyAMA0,115200n8 no_console_suspend consoleblank=0 fsck.fix=yes fsck.repair=yes net.ifnames=0 cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory swapaccount=1
echo 'Loading initial ramdisk ...'
initrd /boot/initrd.img
}
EOF
sync
cd $WORK_DIR
umount -f ${P1} ${P2} 2>/dev/null
losetup -D 2>/dev/null
rm -rf ${P1} ${P2} 2>/dev/null
rm -f ${IMG_NAME} 2>/dev/null
rm -f sha256sums 2>/dev/null
sync
wait
echo "Successfully updated, automatic restarting..."
sleep 3
reboot
exit 0
+916
View File
@@ -0,0 +1,916 @@
#!/bin/bash
#======================================================================================
# Function: Update openwrt to emmc for Rockchip STB
# Copyright (C) 2020-- https://github.com/unifreq/openwrt_packit
# Copyright (C) 2021-- https://github.com/ophub/luci-app-amlogic
#======================================================================================
#
# The script supports directly setting parameters for update, skipping interactive selection
# openwrt-update-rockchip ${OPENWRT_FILE} ${AUTO_MAINLINE_UBOOT} ${RESTORE_CONFIG}
# E.g: openwrt-update-rockchip openwrt_s905d.img.gz yes restore
# E.g: openwrt-update-rockchip openwrt_s905d.img.gz no no-restore
# You can also execute the script directly, and interactively select related functions
# E.g: openwrt-update-rockchip
#
#======================================================================================
# Encountered a serious error, abort the script execution
error_msg() {
echo -e "[ERROR] ${1}"
exit 1
}
# Get the partition name of the /boot file system
get_boot_partition_name() {
local paths="/boot"
local partition_name
partition_name=$(df "${paths}" | awk 'NR==2 {print $1}' | awk -F '/' '{print $3}')
echo "${partition_name}"
}
# Get the partition name of the root file system
get_root_partition_name() {
local paths=("/" "/overlay" "/rom")
local partition_name
for path in "${paths[@]}"; do
partition_name=$(df "${path}" | awk 'NR==2 {print $1}' | awk -F '/' '{print $3}')
[[ -n "${partition_name}" ]] && break
done
echo "${partition_name}"
}
# Get the partition message of the root file system
get_root_partition_msg() {
local paths=("/" "/overlay" "/rom")
local partition_name
for path in "${paths[@]}"; do
partition_msg=$(lsblk -l -o NAME,PATH,TYPE,UUID,MOUNTPOINT | awk '$3~/^part$/ && $5 ~ "^" "'"${path}"'" "$" {print $0}')
[[ -n "${partition_msg}" ]] && break
done
[[ -z "${partition_msg}" ]] && error_msg "Cannot find the root partition message!"
echo "${partition_msg}"
}
# Receive one-key command related parameters
IMG_NAME="${1}"
AUTO_MAINLINE_UBOOT="${2}"
BACKUP_RESTORE_CONFIG="${3}"
# Current device model
if [ -f /boot/armbianEnv.txt ]; then
source /boot/armbianEnv.txt 2>/dev/null
CURRENT_FDTFILE=$(basename ${fdtfile})
fi
MYDEVICE_NAME=$(cat /proc/device-tree/model | tr -d '\000')
case $MYDEVICE_NAME in
"")
error_msg "The device name is empty and cannot be recognized."
;;
"Chainedbox L1 Pro")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3328-l1pro-1296mhz.dtb"
fi
SOC="l1pro"
;;
"BeikeYun")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3328-beikeyun-1296mhz.dtb"
fi
SOC="beikeyun"
;;
"ZCuble1 Max")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3399-zcube1-max.dtb"
fi
SOC="zcube1 max"
;;
"JP TVbox 3566")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3566-jp-tvbox.dtb"
fi
SOC="jp-tvbox"
;;
"Radxa CM3 RPI CM4 IO")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3566-radxa-cm3-rpi-cm4-io.dtb"
fi
SOC="radxa-cm3-rpi-cm4-io"
;;
"FastRhino R66S" | "Lunzn FastRhino R66S")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3568-fastrhino-r66s.dtb"
fi
SOC="r66s"
;;
"FastRhino R68S" | "Lunzn FastRhino R68S")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3568-fastrhino-r68s.dtb"
fi
SOC="r68s"
;;
"RK3568 EC-X")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3568-ec-x.dtb"
fi
SOC="ec-x"
;;
"HINLINK OPC-H66K Board" | "Hlink H66K")
if [ -n "${CURRENT_FDTFILE}" ] && [ "${CURRENT_FDTFILE}" != "rk3568-opc-h66k.dtb" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3568-hlink-h66k.dtb"
fi
SOC="h66k"
;;
"HINLINK OPC-H68K Board" | "Hlink H68K")
if [ -n "${CURRENT_FDTFILE}" ] && [ "${CURRENT_FDTFILE}" != "rk3568-opc-h68k.dtb" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3568-hlink-h68k.dtb"
fi
SOC="h68k"
;;
"HINLINK OPC-H69K Board" | "Hlink H69K")
if [ -n "${CURRENT_FDTFILE}" ] && [ "${CURRENT_FDTFILE}" != "rk3568-opc-h69k.dtb" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3568-hlink-h69k.dtb"
fi
SOC="h69k"
;;
"Radxa E25" | "Radxa E25 Carrier Board")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3568-radxa-e25.dtb"
fi
SOC="e25"
;;
"HINLINK OWL H88K-V3 Board" | "Hlink H88K-V3")
if [ -n "${CURRENT_FDTFILE}" ] && [ "${CURRENT_FDTFILE}" != "rk3568-hinlink-h88k-v3.dtb" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3588-hlink-h88k-v3.dtb"
fi
SOC="h88k-v3"
;;
"Hlink H88K V3.1")
if [ -n "${CURRENT_FDTFILE}" ] && [ "${CURRENT_FDTFILE}" != "rk3568-hinlink-h88k-v31.dtb" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3588-hlink-h88k-v31.dtb"
fi
SOC="h88k-v3"
;;
"HINLINK OWL H88K Board" | "Hlink H88K")
if [ -n "${CURRENT_FDTFILE}" ] && [ "${CURRENT_FDTFILE}" != "rk3568-hinlink-h88k.dtb" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3588-hlink-h88k.dtb"
fi
SOC="ak88/h88k"
;;
"Hlink H28K")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3528-hlink-h28k.dtb"
fi
SOC="h28k"
;;
"Hlink HT2")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3528-hlink-ht2.dtb"
fi
SOC="ht2"
;;
"Radxa E20C")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3528-radxa-e20c.dtb"
fi
SOC="e20c"
;;
"Radxa E24C")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3528-radxa-e24c.dtb"
fi
SOC="e24c"
;;
"YiXun Rs6Pro")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3528-yixun-rs6pro.dtb"
fi
SOC="rs6pro"
;;
"Ariaboard Photonicat")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3568-photonicat.dtb"
fi
SOC="photonicat"
;;
"NLnet Watermelon Pi V3")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3568-watermelon-pi-v3.dtb"
fi
SOC="watermelon-pi-v3"
;;
"NLnet Watermelon Pi")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3568-watermelon-pi.dtb"
fi
SOC="watermelon-pi"
;;
"Rockchip RK3576 DshanPi A1 Board")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3576-100ask-dshanpi-a1.dtb"
fi
SOC="100ask-dshanpi-a1"
;;
"Radxa ROCK 5B" | "Radxa ROCK 5 Model B")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3588-rock-5b.dtb"
fi
SOC="rock5b"
;;
"Radxa ROCK 5C" | "Radxa ROCK 5 Model C")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3588s-rock-5c.dtb"
fi
SOC="rock5c"
;;
"Radxa E52C")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3588s-radxa-e52c.dtb"
fi
SOC="e52c"
;;
"Radxa E54C")
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="rk3588s-radxa-e54c.dtb"
fi
SOC="e54c"
;;
*) #default
if [ -f "/etc/flippy-openwrt-release" ]; then
source /etc/flippy-openwrt-release 2>/dev/null
if [ -n "${CURRENT_FDTFILE}" ]; then
MYDTB_FDTFILE="${CURRENT_FDTFILE}"
else
MYDTB_FDTFILE="${FDTFILE}"
fi
SOC="${SOC}"
else
error_msg "Unknown device: [ ${MYDEVICE_NAME} ], Not supported."
fi
;;
esac
[[ -z "${MYDTB_FDTFILE}" || -z "${SOC}" ]] && {
error_msg "Invalid FDTFILE or SOC: [ ${MYDTB_FDTFILE} / ${SOC} ]"
}
echo -e "Current device: ${MYDEVICE_NAME} [ ${SOC} ]"
sleep 3
# Check and repair partition mount points
[[ -z "$(get_boot_partition_name)" || -z "$(get_root_partition_name)" ]] && {
echo -e "Partition mount point error, start repairing..."
openwrt-backup -g
}
# Find the partition where root is located
ROOT_PTNAME="$(get_root_partition_name)"
# Find the disk where the partition is located, only supports mmcblk?p? sd?? hd?? vd?? and other formats
case ${ROOT_PTNAME} in
mmcblk?p[1-4])
EMMC_NAME=$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-2)}')
PARTITION_NAME="p"
LB_PRE="EMMC_"
;;
nvme?n?p?)
EMMC_NAME=$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-2)}')
PARTITION_NAME="p"
LB_PRE="NVME_"
;;
[hsv]d[a-z][1-4])
EMMC_NAME=$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-1)}')
PARTITION_NAME=""
LB_PRE="USB_"
;;
*)
error_msg "Unable to recognize the disk type of ${ROOT_PTNAME}!"
;;
esac
cd /mnt/${EMMC_NAME}${PARTITION_NAME}4/
mv -f /tmp/upload/* . 2>/dev/null && sync
if [[ "${IMG_NAME}" == *.img ]]; then
echo -e "Update using [ ${IMG_NAME} ] file. Please wait a moment ..."
elif [ $(ls *.img -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
IMG_NAME=$(ls *.img | head -n 1)
echo -e "Update using [ ${IMG_NAME} ] ] file. Please wait a moment ..."
elif [ $(ls *.img.xz -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
xz_file=$(ls *.img.xz | head -n 1)
echo -e "Update using [ ${xz_file} ] file. Please wait a moment ..."
xz -d ${xz_file} 2>/dev/null
IMG_NAME=$(ls *.img | head -n 1)
elif [ $(ls *.img.gz -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
gz_file=$(ls *.img.gz | head -n 1)
echo -e "Update using [ ${gz_file} ] file. Please wait a moment ..."
gzip -df ${gz_file} 2>/dev/null
IMG_NAME=$(ls *.img | head -n 1)
elif [ $(ls *.7z -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
gz_file=$(ls *.7z | head -n 1)
echo -e "Update using [ ${gz_file} ] file. Please wait a moment ..."
bsdtar -xmf ${gz_file} 2>/dev/null
[ $? -eq 0 ] || 7z x ${gz_file} -aoa -y 2>/dev/null
IMG_NAME=$(ls *.img | head -n 1)
elif [ $(ls *.zip -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then
zip_file=$(ls *.zip | head -n 1)
echo -e "Update using [ ${zip_file} ] file. Please wait a moment ..."
unzip -o ${zip_file} 2>/dev/null
IMG_NAME=$(ls *.img | head -n 1)
else
echo -e "Please upload or specify the update openwrt firmware file."
echo -e "Upload method: system menu → Amlogic Service → Manually Upload Update"
echo -e "Specify method: Place the openwrt firmware file in [ /mnt/${EMMC_NAME}${PARTITION_NAME}4/ ]"
echo -e "The supported file suffixes are: *.img, *.img.xz, *.img.gz, *.7z, *.zip"
echo -e "After upload the openwrt firmware file, run again."
exit 1
fi
sync
# check file
if [ ! -f "${IMG_NAME}" ]; then
error_msg "No update file found."
else
echo "Start update from [ ${IMG_NAME} ]"
fi
# find boot partition
BOOT_PART_MSG=$(lsblk -l -o NAME,PATH,TYPE,UUID,MOUNTPOINT | awk '$3~/^part$/ && $5 ~ /^\/boot$/ {print $0}')
if [ "${BOOT_PART_MSG}" == "" ]; then
error_msg "The boot partition is not exists or not mounted, so it cannot be upgraded with this script!"
fi
BR_FLAG=1
echo -ne "Whether to backup and restore the current config files? y/n [y]\b\b"
if [[ ${BACKUP_RESTORE_CONFIG} == "restore" ]]; then
yn="y"
elif [[ ${BACKUP_RESTORE_CONFIG} == "no-restore" ]]; then
yn="n"
else
read yn
fi
case ${yn} in
n* | N*)
BR_FLAG=0
;;
esac
BOOT_NAME=$(echo ${BOOT_PART_MSG} | awk '{print $1}')
BOOT_PATH=$(echo ${BOOT_PART_MSG} | awk '{print $2}')
BOOT_UUID=$(echo ${BOOT_PART_MSG} | awk '{print $4}')
# find root partition
ROOT_PART_MSG="$(get_root_partition_msg)"
ROOT_NAME=$(echo ${ROOT_PART_MSG} | awk '{print $1}')
ROOT_PATH=$(echo ${ROOT_PART_MSG} | awk '{print $2}')
ROOT_UUID=$(echo ${ROOT_PART_MSG} | awk '{print $4}')
case ${ROOT_NAME} in
${EMMC_NAME}${PARTITION_NAME}2)
NEW_ROOT_NAME="${EMMC_NAME}${PARTITION_NAME}3"
NEW_ROOT_LABEL="${LB_PRE}ROOTFS2"
;;
${EMMC_NAME}${PARTITION_NAME}3)
NEW_ROOT_NAME="${EMMC_NAME}${PARTITION_NAME}2"
NEW_ROOT_LABEL="${LB_PRE}ROOTFS1"
;;
*)
error_msg "The root partition location is invalid, so it cannot be upgraded with this script!"
;;
esac
# find new root partition
NEW_ROOT_PART_MSG=$(lsblk -l -o NAME,PATH,TYPE,UUID,MOUNTPOINT | grep "${NEW_ROOT_NAME}" | awk '$3 ~ /^part$/ && $5 !~ /^\/$/ && $5 !~ /^\/boot$/ {print $0}')
if [ "${NEW_ROOT_PART_MSG}" == "" ]; then
error_msg "The new root partition is not exists, so it cannot be upgraded with this script!"
fi
NEW_ROOT_NAME=$(echo ${NEW_ROOT_PART_MSG} | awk '{print $1}')
NEW_ROOT_PATH=$(echo ${NEW_ROOT_PART_MSG} | awk '{print $2}')
NEW_ROOT_UUID=$(echo ${NEW_ROOT_PART_MSG} | awk '{print $4}')
NEW_ROOT_MP=$(echo ${NEW_ROOT_PART_MSG} | awk '{print $5}')
# losetup
losetup -f -P ${IMG_NAME}
if [[ "${?}" -eq "0" ]]; then
LOOP_DEV=$(losetup | grep "${IMG_NAME}" | awk '{print $1}')
if [ "$LOOP_DEV" == "" ]; then
error_msg "loop device not found!"
fi
else
error_msg "losetup ${IMG_FILE} failed!"
fi
# fix loopdev issue in kernel 5.19
function fix_loopdev() {
local parentdev=${1##*/}
if [ ! -d /sys/block/${parentdev} ]; then
return
fi
subdevs=$(lsblk -l -o NAME | grep -E "^${parentdev}.+\$")
for subdev in ${subdevs}; do
if [ ! -d /sys/block/${parentdev}/${subdev} ]; then
return
elif [ -b /dev/${sub_dev} ]; then
continue
fi
source /sys/block/${parentdev}/${subdev}/uevent
mknod /dev/${subdev} b ${MAJOR} ${MINOR}
unset MAJOR MINOR DEVNAME DEVTYPE DISKSEQ PARTN PARTNAME
done
}
fix_loopdev ${LOOP_DEV}
WAIT=3
echo -n "The loopdev is ${LOOP_DEV}, wait ${WAIT} seconds "
while [ ${WAIT} -ge 1 ]; do
echo -n "."
sleep 1
WAIT=$((WAIT - 1))
done
echo
# umount loop devices (openwrt will auto mount some partition)
MOUNTED_DEVS=$(lsblk -l -o NAME,PATH,MOUNTPOINT | grep "${LOOP_DEV}" | awk '$3 !~ /^$/ {print $2}')
for dev in ${MOUNTED_DEVS}; do
while :; do
echo -n "umount ${dev} ... "
umount -f ${dev}
sleep 1
mnt=$(lsblk -l -o NAME,PATH,MOUNTPOINT | grep "${dev}" | awk '$3 !~ /^$/ {print $2}')
if [ "${mnt}" == "" ]; then
echo "ok"
break
else
echo "try again ..."
fi
done
done
# mount src part
WORK_DIR=${PWD}
P1=${WORK_DIR}/boot
P2=${WORK_DIR}/root
mkdir -p $P1 $P2
echo -n "mount ${LOOP_DEV}p1 -> ${P1} ... "
mount -t ext4 -o ro ${LOOP_DEV}p1 ${P1}
if [[ "${?}" -ne "0" ]]; then
echo "mount failed"
losetup -D
exit 1
else
echo "ok"
fi
echo -n "mount ${LOOP_DEV}p2 -> ${P2} ... "
ZSTD_LEVEL=6
mount -t btrfs -o ro,compress=zstd:${ZSTD_LEVEL} ${LOOP_DEV}p2 ${P2}
if [[ "${?}" -ne "0" ]]; then
echo "mount failed"
umount -f ${P1}
losetup -D
exit 1
else
echo "ok"
fi
# Prepare the dockerman config file
if [ -f ${P2}/etc/init.d/dockerman ] && [ -f ${P2}/etc/config/dockerd ]; then
flg=0
# get current docker data root
data_root=$(uci get dockerd.globals.data_root 2>/dev/null)
if [ "${data_root}" == "" ]; then
flg=1
# get current config from /etc/docker/daemon.json
if [ -f "/etc/docker/daemon.json" ] && [ -x "/usr/bin/jq" ]; then
data_root=$(jq -r '."data-root"' /etc/docker/daemon.json)
bip=$(jq -r '."bip"' /etc/docker/daemon.json)
[ "${bip}" == "null" ] && bip="172.31.0.1/24"
log_level=$(jq -r '."log-level"' /etc/docker/daemon.json)
[ "${log_level}" == "null" ] && log_level="warn"
_iptables=$(jq -r '."iptables"' /etc/docker/daemon.json)
[ "${_iptables}" == "null" ] && _iptables="true"
registry_mirrors=$(jq -r '."registry-mirrors"[]' /etc/docker/daemon.json 2>/dev/null)
fi
fi
if [ "${data_root}" == "" ]; then
data_root="/opt/docker/" # the default data root
fi
if ! uci get dockerd.globals >/dev/null 2>&1; then
uci set dockerd.globals='globals'
uci commit
fi
# delete alter config , use inner config
if uci get dockerd.globals.alt_config_file >/dev/null 2>&1; then
uci delete dockerd.globals.alt_config_file
uci commit
fi
if [[ "${flg}" -eq "1" ]]; then
uci set dockerd.globals.data_root=${data_root}
[ "${bip}" != "" ] && uci set dockerd.globals.bip=${bip}
[ "${log_level}" != "" ] && uci set dockerd.globals.log_level=${log_level}
[ "${_iptables}" != "" ] && uci set dockerd.globals.iptables=${_iptables}
if [ "${registry_mirrors}" != "" ]; then
for reg in ${registry_mirrors}; do
uci add_list dockerd.globals.registry_mirrors=${reg}
done
fi
uci set dockerd.globals.auto_start='1'
uci commit
fi
fi
#format NEW_ROOT
echo "umount ${NEW_ROOT_MP}"
umount -f "${NEW_ROOT_MP}"
if [[ "${?}" -ne "0" ]]; then
echo "umount failed, please reboot and try again!"
umount -f ${P1}
umount -f ${P2}
losetup -D
exit 1
fi
echo "format ${NEW_ROOT_PATH}"
NEW_ROOT_UUID=$(uuidgen)
mkfs.btrfs -f -U ${NEW_ROOT_UUID} -L ${NEW_ROOT_LABEL} -m single ${NEW_ROOT_PATH}
if [[ "${?}" -ne "0" ]]; then
echo "format ${NEW_ROOT_PATH} failed!"
umount -f ${P1}
umount -f ${P2}
losetup -D
exit 1
fi
echo "mount ${NEW_ROOT_PATH} to ${NEW_ROOT_MP}"
mount -t btrfs -o compress=zstd:${ZSTD_LEVEL} ${NEW_ROOT_PATH} ${NEW_ROOT_MP}
if [[ "${?}" -ne "0" ]]; then
echo "mount ${NEW_ROOT_PATH} to ${NEW_ROOT_MP} failed!"
umount -f ${P1}
umount -f ${P2}
losetup -D
exit 1
fi
# begin copy rootfs
cd ${NEW_ROOT_MP}
echo "Start copy data from ${P2} to ${NEW_ROOT_MP} ..."
ENTRYS=$(ls)
for entry in ${ENTRYS}; do
if [ "${entry}" == "lost+found" ]; then
continue
fi
echo -n "remove old ${entry} ... "
rm -rf ${entry}
if [ $? -eq 0 ]; then
echo "ok"
else
echo "failed"
exit 1
fi
done
echo
echo "create etc subvolume ..."
btrfs subvolume create etc
echo -n "make dirs ... "
mkdir -p .snapshots .reserved bin boot dev lib opt mnt overlay proc rom root run sbin sys tmp usr www
ln -sf lib/ lib64
ln -sf tmp/ var
echo "done"
echo
COPY_SRC="root etc bin sbin lib opt usr www"
echo "copy data ... "
for src in ${COPY_SRC}; do
echo -n "copy ${src} ... "
(cd ${P2} && tar cf - ${src}) | tar xf -
sync
echo "done"
done
SHFS="/mnt/${EMMC_NAME}${PARTITION_NAME}4"
echo "Modify config files ... "
if [ -x ./usr/sbin/balethirq.pl ]; then
if grep "balethirq.pl" "./etc/rc.local"; then
echo "balance irq is enabled"
else
echo "enable balance irq"
sed -e "/exit/i\/usr/sbin/balethirq.pl" -i ./etc/rc.local
fi
fi
rm -f ./etc/bench.log
cat >./etc/fstab <<EOF
UUID=${NEW_ROOT_UUID} / btrfs compress=zstd:${ZSTD_LEVEL} 0 1
UUID=${BOOT_UUID} /boot ext4 defaults 0 2
#tmpfs /tmp tmpfs defaults,nosuid 0 0
EOF
cat >./etc/config/fstab <<EOF
config global
option anon_swap '0'
option anon_mount '1'
option auto_swap '0'
option auto_mount '1'
option delay_root '5'
option check_fs '0'
config mount
option target '/rom'
option uuid '${NEW_ROOT_UUID}'
option enabled '1'
option enabled_fsck '1'
option fstype 'btrfs'
option options 'compress=zstd:${ZSTD_LEVEL}'
config mount
option target '/boot'
option uuid '${BOOT_UUID}'
option enabled '1'
option enabled_fsck '0'
option fstype 'ext4'
EOF
(
cd etc/rc.d
rm -f S??shortcut-fe
if grep "sfe_flow '1'" ../config/turboacc >/dev/null; then
if find ../../lib/modules -name 'shortcut-fe-cm.ko'; then
ln -sf ../init.d/shortcut-fe S99shortcut-fe
fi
fi
)
# move /etc/config/balance_irq to /etc/balance_irq
[ -f "./etc/config/balance_irq" ] && mv ./etc/config/balance_irq ./etc/
sync
echo "create the first etc snapshot -> .snapshots/etc-000"
btrfs subvolume snapshot -r etc .snapshots/etc-000
[ -d ${SHFS}/docker ] || mkdir -p ${SHFS}/docker
rm -rf opt/docker && ln -sf ${SHFS}/docker/ opt/docker
if [ -f /mnt/${NEW_ROOT_NAME}/etc/config/AdGuardHome ]; then
[ -d ${SHFS}/AdGuardHome/data ] || mkdir -p ${SHFS}/AdGuardHome/data
if [ ! -L /usr/bin/AdGuardHome ]; then
[ -d /usr/bin/AdGuardHome ] &&
cp -a /usr/bin/AdGuardHome/* ${SHFS}/AdGuardHome/
fi
ln -sf ${SHFS}/AdGuardHome /mnt/${NEW_ROOT_NAME}/usr/bin/AdGuardHome
fi
sync
echo "copy done"
echo
BACKUP_LIST=$(${P2}/usr/sbin/openwrt-backup -p)
if [ $BR_FLAG -eq 1 ]; then
echo -n "Restore your old config files ... "
(
cd /
eval tar czf ${NEW_ROOT_MP}/.reserved/openwrt_config.tar.gz "${BACKUP_LIST}" 2>/dev/null
)
tar xzf ${NEW_ROOT_MP}/.reserved/openwrt_config.tar.gz
[ -f ./etc/config/dockerman ] && sed -e "s/option wan_mode 'false'/option wan_mode 'true'/" -i ./etc/config/dockerman 2>/dev/null
[ -f ./etc/config/dockerd ] && sed -e "s/option wan_mode '0'/option wan_mode '1'/" -i ./etc/config/dockerd 2>/dev/null
[ -f ./etc/config/verysync ] && sed -e 's/config setting/config verysync/' -i ./etc/config/verysync
# 还原 fstab
cp -f .snapshots/etc-000/fstab ./etc/fstab
cp -f .snapshots/etc-000/config/fstab ./etc/config/fstab
# 还原 luci
cp -f .snapshots/etc-000/config/luci ./etc/config/luci
# 还原/etc/config/rpcd
cp -f .snapshots/etc-000/config/rpcd ./etc/config/rpcd
sync
echo "done"
echo
fi
cat >>./etc/crontabs/root <<EOF
17 3 * * * /etc/coremark.sh
EOF
sed -e 's/ttyAMA0/ttyS2/' -i ./etc/inittab
[ "${SOC}" != "h28k" ] && \
[ "${SOC}" != "h29k" ] && \
[ "${SOC}" != "ht2" ] && \
[ "${SOC}" != "e20c" ] && \
[ "${SOC}" != "e24c" ] && \
sed -e 's/ttyS0/tty1/' -i ./etc/inittab
sss=$(date +%s)
ddd=$((sss / 86400))
sed -e "s/:0:0:99999:7:::/:${ddd}:0:99999:7:::/" -i ./etc/shadow
# 修复amule每次升级后重复添加条目的问题
sed -e "/amule:x:/d" -i ./etc/shadow
# 修复dropbear每次升级后重复添加sshd条目的问题
sed -e "/sshd:x:/d" -i ./etc/shadow
if ! grep "sshd:x:22:sshd" ./etc/group >/dev/null; then
echo "sshd:x:22:sshd" >>./etc/group
fi
if ! grep "sshd:x:22:22:sshd:" ./etc/passwd >/dev/null; then
echo "sshd:x:22:22:sshd:/var/run/sshd:/bin/false" >>./etc/passwd
fi
if ! grep "sshd:x:" ./etc/shadow >/dev/null; then
echo "sshd:x:${ddd}:0:99999:7:::" >>./etc/shadow
fi
if [ $BR_FLAG -eq 1 ]; then
if [ -x ./bin/bash ] && [ -f ./etc/profile.d/30-sysinfo.sh ]; then
sed -e 's/\/bin\/ash/\/bin\/bash/' -i ./etc/passwd
fi
sync
echo "done"
echo
fi
sed -e "s/option hw_flow '1'/option hw_flow '0'/" -i ./etc/config/turboacc
(
cd etc/rc.d
rm -f S??shortcut-fe
if grep "sfe_flow '1'" ../config/turboacc >/dev/null; then
if find ../../lib/modules -name 'shortcut-fe-cm.ko'; then
ln -sf ../init.d/shortcut-fe S99shortcut-fe
fi
fi
)
# move /etc/config/balance_irq to /etc/balance_irq
[ -f "./etc/config/balance_irq" ] && mv ./etc/config/balance_irq ./etc/
rm -f "./etc/rc.local.orig" "./etc/first_run.sh" "./etc/part_size"
eval tar czf .reserved/openwrt_config.tar.gz "${BACKUP_LIST}" 2>/dev/null
sync
mv ./etc/rc.local ./etc/rc.local.orig
cat >"./etc/rc.local" <<EOF
if ! ls /etc/rc.d/S??dockerd >/dev/null 2>&1;then
/etc/init.d/dockerd enable
/etc/init.d/dockerd start
fi
if ! ls /etc/rc.d/S??dockerman >/dev/null 2>&1 && [ -f /etc/init.d/dockerman ];then
/etc/init.d/dockerman enable
/etc/init.d/dockerman start
fi
mv /etc/rc.local.orig /etc/rc.local
chmod 755 /etc/rc.local
exec /etc/rc.local
exit
EOF
chmod 755 ./etc/rc.local*
echo "create the second etc snapshot -> .snapshots/etc-001"
btrfs subvolume snapshot -r etc .snapshots/etc-001
# 2021.04.01添加
# 强制锁定fstab,防止用户擅自修改挂载点
# 开启了快照功能之后,不再需要锁定fstab
#chattr +ia ./etc/config/fstab
cd ${WORK_DIR}
echo "Start copy data from ${P2} to /boot ..."
cd /boot
echo -n "backup armbianEnv.txt ..."
cp armbianEnv.txt /tmp/
echo -n "backup current dtb file ..."
cp -v dtb/rockchip/${CURRENT_FDTFILE} /tmp/
echo -n "remove old boot files ..."
rm -rf *
echo "done"
echo -n "copy new boot files ... "
(cd ${P1} && tar cf - .) | tar xf -
sync
echo "done"
echo
echo -n "Update boot args ... "
if [ -f /tmp/armbianEnv.txt ]; then
ORIG_OVERLAYS=$(grep '^overlays=' /tmp/armbianEnv.txt)
ORIG_USER_OVERLAYS=$(grep '^user_overlays=' /tmp/armbianEnv.txt)
sed -e '/user_overlays=/d' -i armbianEnv.txt
sed -e '/overlays=/d' -i armbianEnv.txt
echo "$ORIG_OVERLAYS" >>armbianEnv.txt
echo "$ORIG_USER_OVERLAYS" >>armbianEnv.txt
fi
sed -e '/fdtfile=/d' -i armbianEnv.txt
sed -e '/rootdev=/d' -i armbianEnv.txt
sed -e '/rootfstype=/d' -i armbianEnv.txt
sed -e '/rootflags=/d' -i armbianEnv.txt
case $SOC in
l1pro | beikeyun)
echo "fdtfile=/dtb/rockchip/${MYDTB_FDTFILE}" >>armbianEnv.txt
;;
*)
echo "fdtfile=rockchip/${MYDTB_FDTFILE}" >>armbianEnv.txt
;;
esac
cat >>armbianEnv.txt <<EOF
rootdev=UUID=${NEW_ROOT_UUID}
rootfstype=btrfs
rootflags=compress=zstd:${ZSTD_LEVEL}
EOF
# Replace the UUID for extlinux/extlinux.conf if it exists
[[ -f "extlinux/extlinux.conf" ]] && {
sed -i -E "s|UUID=[^ ]*|UUID=${NEW_ROOT_UUID}|" extlinux/extlinux.conf 2>/dev/null
}
# 如果新的dtb文件不存在,则用旧的代替
if [ ! -f "dtb/rockchip/${MYDTB_FDTFILE}" ]; then
echo "The new dtb file does not exist, replace it with the old one."
cp -v /tmp/${CURRENT_FDTFILE} dtb/rockchip/${MYDTB_FDTFILE}
fi
sync
echo "done"
echo
cd $WORK_DIR
umount -f ${P1} ${P2} 2>/dev/null
losetup -D 2>/dev/null
rmdir ${P1} ${P2} 2>/dev/null
rm -f ${IMG_NAME} 2>/dev/null
rm -f sha256sums 2>/dev/null
sync
echo "Successfully updated, automatic restarting..."
sleep 3
reboot
exit 0
@@ -0,0 +1,299 @@
#!/bin/bash
#==================================================================
# This file is licensed under the terms of the GNU General Public
# License version 2. This program is licensed "as is" without any
# warranty of any kind, whether express or implied.
#
# This file is a part of the luci-app-amlogic plugin
# https://github.com/ophub/luci-app-amlogic
#
# Description: Check and update OpenWrt firmware
# Copyright (C) 2021- https://github.com/unifreq/openwrt_packit
# Copyright (C) 2021- https://github.com/ophub/luci-app-amlogic
#==================================================================
# Set a fixed value
check_option="${1}"
download_version="${2}"
TMP_CHECK_DIR="/tmp/amlogic"
AMLOGIC_SOC_FILE="/etc/flippy-openwrt-release"
START_LOG="${TMP_CHECK_DIR}/amlogic_check_firmware.log"
RUNNING_LOG="${TMP_CHECK_DIR}/amlogic_running_script.log"
LOG_FILE="${TMP_CHECK_DIR}/amlogic.log"
support_platform=("allwinner" "rockchip" "amlogic" "qemu-aarch64")
LOGTIME="$(date "+%Y-%m-%d %H:%M:%S")"
[[ -d ${TMP_CHECK_DIR} ]] || mkdir -p ${TMP_CHECK_DIR}
# Clean the running log
clean_running() {
echo -e '' >${RUNNING_LOG} 2>/dev/null && sync
}
# Add log
tolog() {
echo -e "${1}" >${START_LOG}
echo -e "${LOGTIME} ${1}" >>${LOG_FILE}
[[ -n "${2}" && "${2}" -eq "1" ]] && clean_running && exit 1
}
# Get the partition name of the root file system
get_root_partition_name() {
local paths=("/" "/overlay" "/rom")
local partition_name
for path in "${paths[@]}"; do
partition_name=$(df "${path}" | awk 'NR==2 {print $1}' | awk -F '/' '{print $3}')
[[ -n "${partition_name}" ]] && break
done
[[ -z "${partition_name}" ]] && tolog "Cannot find the root partition!" "1"
echo "${partition_name}"
}
# Check running scripts, prohibit running concurrently
this_running_log="3@OpenWrt update in progress, try again later!"
running_script="$(cat ${RUNNING_LOG} 2>/dev/null | xargs)"
if [[ -n "${running_script}" ]]; then
run_num="$(echo "${running_script}" | awk -F "@" '{print $1}')"
run_log="$(echo "${running_script}" | awk -F "@" '{print $2}')"
fi
if [[ -n "${run_log}" && "${run_num}" -ne "3" ]]; then
echo -e "${run_log}" >${START_LOG} 2>/dev/null && sync && exit 1
else
echo -e "${this_running_log}" >${RUNNING_LOG} 2>/dev/null && sync
fi
# Find the partition where root is located
ROOT_PTNAME="$(get_root_partition_name)"
# Find the disk where the partition is located, only supports mmcblk?p? sd?? hd?? vd?? and other formats
case "${ROOT_PTNAME}" in
mmcblk?p[1-4])
EMMC_NAME="$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-2)}')"
PARTITION_NAME="p"
;;
[hsv]d[a-z][1-4])
EMMC_NAME="$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-1)}')"
PARTITION_NAME=""
;;
nvme?n?p[1-4])
EMMC_NAME="$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-2)}')"
PARTITION_NAME="p"
;;
*)
tolog "Unable to recognize the disk type of ${ROOT_PTNAME}!" "1"
;;
esac
# Set the default download path
FIRMWARE_DOWNLOAD_PATH="/mnt/${EMMC_NAME}${PARTITION_NAME}4"
[ -d "${FIRMWARE_DOWNLOAD_PATH}/.luci-app-amlogic" ] || mkdir -p "${FIRMWARE_DOWNLOAD_PATH}/.luci-app-amlogic"
# Check release file
if [[ -s "${AMLOGIC_SOC_FILE}" ]]; then
source "${AMLOGIC_SOC_FILE}" 2>/dev/null
PLATFORM="${PLATFORM}"
BOARD="${BOARD}"
else
tolog "${AMLOGIC_SOC_FILE} file is missing!" "1"
fi
if [[ -z "${PLATFORM}" || -z "$(echo "${support_platform[@]}" | grep -w "${PLATFORM}")" || -z "${BOARD}" ]]; then
tolog "Missing [ PLATFORM / BOARD ] value in ${AMLOGIC_SOC_FILE} file." "1"
fi
tolog "PLATFORM: [ ${PLATFORM} ], BOARD: [ ${BOARD} ], Use in [ ${EMMC_NAME} ]"
sleep 2
# 01. Query local version information
tolog "01. Query version information..."
# 01.01 Query the current version
current_kernel_v="$(uname -r 2>/dev/null | grep -oE '^[1-9].[0-9]{1,3}.[0-9]+')"
tolog "01.01 current version: ${current_kernel_v}"
sleep 2
# 01.01 Version comparison
main_line_version="$(echo ${current_kernel_v} | awk -F '.' '{print $1"."$2}')"
# 01.02. Query the selected branch in the settings
server_kernel_branch="$(uci get amlogic.config.amlogic_kernel_branch 2>/dev/null | grep -oE '^[1-9].[0-9]{1,3}')"
if [[ -z "${server_kernel_branch}" ]]; then
server_kernel_branch="${main_line_version}"
uci set amlogic.config.amlogic_kernel_branch="${main_line_version}" 2>/dev/null
uci commit amlogic 2>/dev/null
fi
if [[ "${server_kernel_branch}" != "${main_line_version}" ]]; then
main_line_version="${server_kernel_branch}"
tolog "01.02 Select branch: ${main_line_version}"
sleep 2
fi
# 01.03. Download server version documentation
server_firmware_url="$(uci get amlogic.config.amlogic_firmware_repo 2>/dev/null)"
[[ ! -z "${server_firmware_url}" ]] || tolog "01.03 The custom firmware download repo is invalid." "1"
releases_tag_keywords="$(uci get amlogic.config.amlogic_firmware_tag 2>/dev/null)"
[[ ! -z "${releases_tag_keywords}" ]] || tolog "01.04 The custom firmware tag keywords is invalid." "1"
firmware_suffix="$(uci get amlogic.config.amlogic_firmware_suffix 2>/dev/null)"
[[ ! -z "${firmware_suffix}" ]] || tolog "01.05 The custom firmware suffix is invalid." "1"
if [[ "${server_firmware_url}" == http* ]]; then
server_firmware_url="${server_firmware_url#*com\/}"
fi
# 02. Check Updated
check_updated() {
tolog "02.01 Search for tags in the first 5 pages of releases..."
# Get the tags list
firmware_tags_array=()
for i in {1..5}; do
while IFS= read -r firmware_tags_name; do
firmware_tags_name="$(echo "${firmware_tags_name}" | sed 's/releases\/tag\///g')"
if [[ -n "${firmware_tags_name}" ]]; then
firmware_tags_array+=("${firmware_tags_name}")
fi
done < <(
curl -fsSL -m 10 \
https://github.com/${server_firmware_url}/releases?page=${i} |
grep -oE 'releases/tag/([^" ]+)'
)
done
if [[ "${#firmware_tags_array[*]}" -eq "0" ]]; then
tolog "02.01.01 Unable to retrieve a list of firmware tags." "1"
fi
tolog "02.02 Search for tags containing the keyword..."
# Search for tags containing the keyword
for i in "${firmware_tags_array[@]}"; do
if [[ "${i}" == *"${releases_tag_keywords}"* ]]; then
firmware_releases_tag="${i}"
break
fi
done
if [[ -n "${firmware_releases_tag}" ]]; then
tolog "02.02.01 Tags: ${firmware_releases_tag}"
sleep 2
else
tolog "02.02.01 No matching tags found." "1"
fi
tolog "02.03 Start searching for firmware download links..."
# Retrieve the HTML code of the tags list page
html_code="$(
curl -fsSL -m 10 \
https://github.com/${server_firmware_url}/releases/expanded_assets/${firmware_releases_tag}
)"
# Set the regular expression for the OpenWrt filename
op_file_pattern=".*_${BOARD}_.*k${main_line_version}\.[0-9]+.*${firmware_suffix}"
# Find the <li> list item where the OpenWrt file is located
li_block=$(awk -v pattern="${op_file_pattern}" -v RS='</li>' '$0 ~ pattern { print $0 "</li>"; exit }' <<<"${html_code}")
[[ -z "${li_block}" ]] && tolog "02.03.01 No matching download links found." "1"
# Find the OpenWrt filename
latest_url=$(echo "${li_block}" | grep -oE "/[^\"]*_${BOARD}_.*k${main_line_version}\.[0-9]+[^\"]*${firmware_suffix}" | sort -urV | head -n 1 | xargs basename 2>/dev/null)
tolog "02.03.02 OpenWrt file: ${latest_url}"
# Find the date of the latest update
latest_updated_at=$(echo "${li_block}" | grep -o 'datetime="[^"]*"' | sed 's/datetime="//; s/"//')
tolog "02.03.03 Latest updated at: ${latest_updated_at}"
# Format the date for display
date_display_format="$(echo ${latest_updated_at} | tr 'T' '(' | tr 'Z' ')')"
[[ -z "${latest_url}" || -z "${latest_updated_at}" ]] && tolog "02.03.04 The download URL or date is invalid." "1"
# Find the firmware sha256 value
latest_firmware_sha256="$(echo "${li_block}" | grep -o 'value="sha256:[^"]*' | sed 's/value="sha256://')"
tolog "02.03.05 OpenWrt sha256: ${latest_firmware_sha256}"
# Check the firmware update code
down_check_code="${latest_updated_at}.${main_line_version}"
op_release_code="${FIRMWARE_DOWNLOAD_PATH}/.luci-app-amlogic/op_release_code"
if [[ -s "${op_release_code}" ]]; then
update_check_code="$(cat ${op_release_code} | xargs)"
if [[ -n "${update_check_code}" && "${update_check_code}" == "${down_check_code}" ]]; then
tolog "02.04 Already the latest version, no need to update." "1"
fi
fi
# Prompt to update
if [[ -n "${latest_url}" ]]; then
tolog '<input type="button" class="cbi-button cbi-button-reload" value="Download" onclick="return b_check_firmware(this, '"'download_${latest_updated_at}@${firmware_releases_tag}/${latest_url}@${latest_firmware_sha256}'"')"/> Latest updated: '${date_display_format}'' "1"
else
tolog "02.05 No OpenWrt available, please use another kernel branch." "1"
fi
exit 0
}
# 03. Download Openwrt
download_firmware() {
tolog "03. Start download the Openwrt..."
# Get the openwrt firmware download path
if [[ "${download_version}" == "download_"* ]]; then
tolog "03.01 Start downloading..."
else
tolog "03.01 Invalid parameter." "1"
fi
# Delete other residual firmware files
rm -f ${FIRMWARE_DOWNLOAD_PATH}/*${firmware_suffix} 2>/dev/null && sync
rm -f ${FIRMWARE_DOWNLOAD_PATH}/*.img 2>/dev/null && sync
rm -f ${FIRMWARE_DOWNLOAD_PATH}/sha256sums 2>/dev/null && sync
# OpenWrt make data
latest_updated_at="$(echo ${download_version} | awk -F'@' '{print $1}' | sed -e s'|download_||'g)"
down_check_code="${latest_updated_at}.${main_line_version}"
# Download firmware
opfile_path="$(echo ${download_version} | awk -F'@' '{print $2}')"
# Restore converted characters in file names(%2B to +)
firmware_download_oldname="${opfile_path//%2B/+}"
latest_url="https://github.com/${server_firmware_url}/releases/download/${firmware_download_oldname}"
# Find the firmware sha256 value
releases_firmware_sha256sums="$(echo ${download_version} | awk -F'@' '{print $3}')"
# Download to OpenWrt file
firmware_download_name="openwrt_${BOARD}_k${main_line_version}_github${firmware_suffix}"
curl -fsSL "${latest_url}" -o "${FIRMWARE_DOWNLOAD_PATH}/${firmware_download_name}"
if [[ "$?" -eq "0" && -s "${FIRMWARE_DOWNLOAD_PATH}/${firmware_download_name}" ]]; then
tolog "03.02 OpenWrt downloaded successfully."
else
tolog "03.02 OpenWrt download failed." "1"
fi
# Verify sha256sums if available
if [[ -n "${releases_firmware_sha256sums}" ]]; then
tolog "03.03 Perform sha256 checksum verification."
# If there is a sha256sum file, compare it
download_firmware_sha256sums="$(sha256sum ${FIRMWARE_DOWNLOAD_PATH}/${firmware_download_name} | awk '{print $1}')"
if [[ "${releases_firmware_sha256sums}" != "${download_firmware_sha256sums}" ]]; then
tolog "03.03.01 sha256sum verification mismatched." "1"
else
tolog "03.03.02 sha256sum verification succeeded."
fi
fi
sync && sleep 3
tolog "You can update."
tolog '<input type="button" class="cbi-button cbi-button-reload" value="Update" onclick="return amlogic_update(this, '"'${firmware_download_name}@${down_check_code}@${FIRMWARE_DOWNLOAD_PATH}'"')"/>' "1"
exit 0
}
getopts 'cd' opts
case "${opts}" in
c | check)
check_updated
;;
* | download)
download_firmware
;;
esac
@@ -0,0 +1,275 @@
#!/bin/bash
#==================================================================
# This file is licensed under the terms of the GNU General Public
# License version 2. This program is licensed "as is" without any
# warranty of any kind, whether express or implied.
#
# This file is a part of the luci-app-amlogic plugin
# https://github.com/ophub/luci-app-amlogic
#
# Description: Check and update OpenWrt Kernel
# Copyright (C) 2021- https://github.com/unifreq/openwrt_packit
# Copyright (C) 2021- https://github.com/ophub/luci-app-amlogic
#==================================================================
# Set a fixed value
check_option="${1}"
download_version="${2}"
TMP_CHECK_DIR="/tmp/amlogic"
AMLOGIC_SOC_FILE="/etc/flippy-openwrt-release"
START_LOG="${TMP_CHECK_DIR}/amlogic_check_kernel.log"
RUNNING_LOG="${TMP_CHECK_DIR}/amlogic_running_script.log"
LOG_FILE="${TMP_CHECK_DIR}/amlogic.log"
support_platform=("allwinner" "rockchip" "amlogic" "qemu-aarch64")
LOGTIME="$(date "+%Y-%m-%d %H:%M:%S")"
[[ -d ${TMP_CHECK_DIR} ]] || mkdir -p ${TMP_CHECK_DIR}
# Clean the running log
clean_running() {
echo -e '' >${RUNNING_LOG} 2>/dev/null && sync
}
# Add log
tolog() {
echo -e "${1}" >${START_LOG}
echo -e "${LOGTIME} ${1}" >>${LOG_FILE}
[[ -n "${2}" && "${2}" -eq "1" ]] && clean_running && exit 1
}
# Get the partition name of the root file system
get_root_partition_name() {
local paths=("/" "/overlay" "/rom")
local partition_name
for path in "${paths[@]}"; do
partition_name=$(df "${path}" | awk 'NR==2 {print $1}' | awk -F '/' '{print $3}')
[[ -n "${partition_name}" ]] && break
done
[[ -z "${partition_name}" ]] && tolog "Cannot find the root partition!" "1"
echo "${partition_name}"
}
# Check running scripts, prohibit running concurrently
this_running_log="2@Kernel update in progress, try again later!"
running_script="$(cat ${RUNNING_LOG} 2>/dev/null | xargs)"
if [[ -n "${running_script}" ]]; then
run_num="$(echo "${running_script}" | awk -F "@" '{print $1}')"
run_log="$(echo "${running_script}" | awk -F "@" '{print $2}')"
fi
if [[ -n "${run_log}" && "${run_num}" -ne "2" ]]; then
echo -e "${run_log}" >${START_LOG} 2>/dev/null && sync && exit 1
else
echo -e "${this_running_log}" >${RUNNING_LOG} 2>/dev/null && sync
fi
# Find the partition where root is located
ROOT_PTNAME="$(get_root_partition_name)"
# Find the disk where the partition is located, only supports mmcblk?p? sd?? hd?? vd?? and other formats
case "${ROOT_PTNAME}" in
mmcblk?p[1-4])
EMMC_NAME="$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-2)}')"
PARTITION_NAME="p"
;;
[hsv]d[a-z][1-4])
EMMC_NAME="$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-1)}')"
PARTITION_NAME=""
;;
nvme?n?p[1-4])
EMMC_NAME="$(echo ${ROOT_PTNAME} | awk '{print substr($1, 1, length($1)-2)}')"
PARTITION_NAME="p"
;;
*)
tolog "Unable to recognize the disk type of ${ROOT_PTNAME}!" "1"
;;
esac
# Set the default download path
KERNEL_DOWNLOAD_PATH="/mnt/${EMMC_NAME}${PARTITION_NAME}4"
# Check release file
if [[ -s "${AMLOGIC_SOC_FILE}" ]]; then
source "${AMLOGIC_SOC_FILE}" 2>/dev/null
PLATFORM="${PLATFORM}"
else
tolog "${AMLOGIC_SOC_FILE} file is missing!" "1"
fi
if [[ -z "${PLATFORM}" || -z "$(echo "${support_platform[@]}" | grep -w "${PLATFORM}")" ]]; then
tolog "Missing [ PLATFORM ] value in ${AMLOGIC_SOC_FILE} file." "1"
fi
tolog "PLATFORM: [ ${PLATFORM} ], Use in [ ${EMMC_NAME} ]"
sleep 2
# Step 1. Set the kernel query api
tolog "01. Start checking the kernel repository."
firmware_repo="$(uci get amlogic.config.amlogic_firmware_repo 2>/dev/null)"
[[ -n "${firmware_repo}" ]] || tolog "01.01 The custom kernel download repo is invalid." "1"
kernel_repo="$(uci get amlogic.config.amlogic_kernel_path 2>/dev/null)"
[[ -n "${kernel_repo}" ]] || tolog "01.02 The custom kernel download repo is invalid." "1"
if [[ "${kernel_repo}" == "opt/kernel" ]]; then
uci set amlogic.config.amlogic_kernel_path="${firmware_repo}" 2>/dev/null
uci commit amlogic 2>/dev/null
kernel_repo="${firmware_repo}"
fi
# Convert kernel repo to api format
[[ "${kernel_repo}" =~ ^https: ]] && kernel_repo="$(echo ${kernel_repo} | awk -F'/' '{print $4"/"$5}')"
kernel_api="https://github.com/${kernel_repo}"
tolog "01.03 Kernel repo: ${kernel_repo}"
# Get the current kernel uname
kernel_uname="$(uname -r 2>/dev/null)"
tolog "01.04 Current kernel uname: ${kernel_uname}"
# Get the kernel tag from uci config
op_kernel_tags="$(uci get amlogic.config.amlogic_kernel_tags 2>/dev/null)"
# Determine the kernel tag
if [[ -n "${op_kernel_tags}" ]]; then
kernel_tag="${op_kernel_tags/kernel_/}"
else
# Determine the kernel tag based on the current kernel uname
if [[ "${kernel_uname}" =~ -rk3588 ]]; then
kernel_tag="rk3588"
elif [[ "${kernel_uname}" =~ -rk35xx ]]; then
kernel_tag="rk35xx"
elif [[ "${kernel_uname}" =~ -h6|-zicai ]]; then
kernel_tag="h6"
else
kernel_tag="stable"
fi
# Save the kernel tag to uci config
uci set amlogic.config.amlogic_kernel_tags="kernel_${kernel_tag}" 2>/dev/null
uci commit amlogic 2>/dev/null
fi
tolog "01.05 Kernel tag: kernel_${kernel_tag}"
sleep 2
# Step 2: Check if there is the latest kernel version
check_kernel() {
# 02. Query local version information
tolog "02. Start checking the kernel version."
# 02.01 Get current kernel version
[[ ! "${kernel_tag}" =~ ^(rk3588|rk35xx)$ ]] && kernel_uname="$(echo "${kernel_uname}" | cut -d'-' -f1)"
[[ -n "${kernel_uname}" ]] || tolog "02.01 The current kernel version is not detected." "1"
tolog "02.01 current version: ${kernel_uname}"
sleep 2
# 02.02 Version comparison
main_line_version="$(echo ${kernel_uname} | awk -F '.' '{print $1"."$2}')"
# 02.03 Query the selected branch in the settings
server_kernel_branch="$(uci get amlogic.config.amlogic_kernel_branch 2>/dev/null | grep -oE '^[1-9].[0-9]{1,3}')"
if [[ -z "${server_kernel_branch}" ]]; then
server_kernel_branch="${main_line_version}"
uci set amlogic.config.amlogic_kernel_branch="${main_line_version}" 2>/dev/null
uci commit amlogic 2>/dev/null
fi
if [[ "${server_kernel_branch}" != "${main_line_version}" ]]; then
main_line_version="${server_kernel_branch}"
main_line_now="0"
tolog "02.02 Select branch: ${main_line_version}"
sleep 2
fi
# Check the version on the server
latest_version="$(
curl -fsSL -m 10 \
${kernel_api}/releases/expanded_assets/kernel_${kernel_tag} |
grep -oE "${main_line_version}\.[0-9]+[^\"]*\.tar\.gz" | sed 's/.tar.gz//' |
sort -urV | head -n 1
)"
[[ -n "${latest_version}" ]] || tolog "02.03 No kernel available, please use another kernel branch." "1"
tolog "02.04 current version: ${kernel_uname}, Latest version: ${latest_version}"
sleep 2
# Get the sha256 value of the latest version
latest_kernel_sha256="$(
curl -fsSL -m 10 \
${kernel_api}/releases/expanded_assets/kernel_${kernel_tag} |
awk -v pattern="${latest_version}\.tar\.gz" -v RS='</li>' '$0 ~ pattern { print $0 "</li>"; exit }' |
grep -o 'value="sha256:[^"]*' | sed 's/value="sha256://'
)"
[[ -n "${latest_kernel_sha256}" ]] && tolog "02.05 Kernel sha256: ${latest_kernel_sha256}"
if [[ "${latest_version}" == "${kernel_uname}" ]]; then
tolog "02.06 Already the latest version, no need to update." "1"
sleep 2
else
tolog '<input type="button" class="cbi-button cbi-button-reload" value="Download" onclick="return b_check_kernel(this, '"'download_${latest_version}_${latest_kernel_sha256}'"')"/> Latest version: '${latest_version}'' "1"
fi
exit 0
}
# Step 3: Download the latest kernel version
download_kernel() {
tolog "03. Start download the kernel file."
if [[ "${download_version}" == "download_"* ]]; then
tolog "03.01 Start downloading..."
else
tolog "03.01 Invalid parameter" "1"
fi
# Get the kernel file name
kernel_file_name="$(echo "${download_version}" | cut -d '_' -f2)"
# Restore converted characters in file names(%2B to +)
kernel_file_name="${kernel_file_name//%2B/+}"
# Get the sha256 value
kernel_file_sha256="$(echo "${download_version}" | cut -d '_' -f3)"
# Delete other residual kernel files
rm -f ${KERNEL_DOWNLOAD_PATH}/*.tar.gz
rm -f ${KERNEL_DOWNLOAD_PATH}/sha256sums
rm -rf ${KERNEL_DOWNLOAD_PATH}/${kernel_file_name}*
kernel_down_from="https://github.com/${kernel_repo}/releases/download/kernel_${kernel_tag}/${kernel_file_name}.tar.gz"
curl -fsSL "${kernel_down_from}" -o ${KERNEL_DOWNLOAD_PATH}/${kernel_file_name}.tar.gz
[[ "${?}" -ne "0" ]] && tolog "03.02 The kernel download failed." "1"
# Verify sha256
if [[ -n "${kernel_file_sha256}" ]]; then
tolog "03.03 Perform sha256 checksum verification."
download_kernel_sha256sums="$(sha256sum ${KERNEL_DOWNLOAD_PATH}/${kernel_file_name}.tar.gz | awk '{print $1}')"
if [[ "${kernel_file_sha256}" != "${download_kernel_sha256sums}" ]]; then
tolog "03.03.01 sha256sum verification mismatched." "1"
else
tolog "03.03.02 sha256sum verification succeeded."
fi
fi
# Decompress the kernel package
tolog "03.04 Start decompressing the kernel package..."
tar -xf ${KERNEL_DOWNLOAD_PATH}/${kernel_file_name}.tar.gz -C ${KERNEL_DOWNLOAD_PATH}
[[ "${?}" -ne "0" ]] && tolog "03.05 Kernel decompression failed." "1"
mv -f ${KERNEL_DOWNLOAD_PATH}/${kernel_file_name}/* ${KERNEL_DOWNLOAD_PATH}/
sync && sleep 3
# Delete the downloaded kernel file
rm -f ${KERNEL_DOWNLOAD_PATH}/${kernel_file_name}.tar.gz
rm -rf ${KERNEL_DOWNLOAD_PATH}/${kernel_file_name}
tolog "03.06 The kernel is ready, you can update."
sleep 2
#echo '<a href="javascript:;" onclick="return amlogic_kernel(this)">Update</a>' >$START_LOG
tolog '<input type="button" class="cbi-button cbi-button-reload" value="Update" onclick="return amlogic_kernel(this)"/>' "1"
exit 0
}
getopts 'cd' opts
case "${opts}" in
c | check)
check_kernel
;;
* | download)
download_kernel
;;
esac
@@ -0,0 +1,170 @@
#!/bin/bash
#==================================================================
# This file is licensed under the terms of the GNU General Public
# License version 2. This program is licensed "as is" without any
# warranty of any kind, whether express or implied.
#
# This file is a part of the luci-app-amlogic plugin
# https://github.com/ophub/luci-app-amlogic
#
# Description: Check and update luci-app-amlogic plugin
# Copyright (C) 2021- https://github.com/unifreq/openwrt_packit
# Copyright (C) 2021- https://github.com/ophub/luci-app-amlogic
#==================================================================
# Set a fixed value
TMP_CHECK_DIR="/tmp/amlogic"
AMLOGIC_SOC_FILE="/etc/flippy-openwrt-release"
START_LOG="${TMP_CHECK_DIR}/amlogic_check_plugin.log"
RUNNING_LOG="${TMP_CHECK_DIR}/amlogic_running_script.log"
LOG_FILE="${TMP_CHECK_DIR}/amlogic.log"
support_platform=("allwinner" "rockchip" "amlogic" "qemu-aarch64")
LOGTIME="$(date "+%Y-%m-%d %H:%M:%S")"
[[ -d ${TMP_CHECK_DIR} ]] || mkdir -p ${TMP_CHECK_DIR}
rm -f ${TMP_CHECK_DIR}/*.ipk 2>/dev/null && sync
rm -f ${TMP_CHECK_DIR}/sha256sums 2>/dev/null && sync
# Clean the running log
clean_running() {
echo -e '' >${RUNNING_LOG} 2>/dev/null && sync
}
# Add log
tolog() {
echo -e "${1}" >${START_LOG}
echo -e "${LOGTIME} ${1}" >>${LOG_FILE}
[[ -n "${2}" && "${2}" -eq "1" ]] && clean_running && exit 1
}
# Check running scripts, prohibit running concurrently
this_running_log="1@Plugin update in progress, try again later!"
running_script="$(cat ${RUNNING_LOG} 2>/dev/null | xargs)"
if [[ -n "${running_script}" ]]; then
run_num="$(echo "${running_script}" | awk -F "@" '{print $1}')"
run_log="$(echo "${running_script}" | awk -F "@" '{print $2}')"
fi
if [[ -n "${run_log}" && "${run_num}" -ne "1" ]]; then
echo -e "${run_log}" >${START_LOG} 2>/dev/null && sync && exit 1
else
echo -e "${this_running_log}" >${RUNNING_LOG} 2>/dev/null && sync
fi
# Check release file
if [[ -s "${AMLOGIC_SOC_FILE}" ]]; then
source "${AMLOGIC_SOC_FILE}" 2>/dev/null
PLATFORM="${PLATFORM}"
else
tolog "${AMLOGIC_SOC_FILE} file is missing!" "1"
fi
if [[ -z "${PLATFORM}" || -z "$(echo "${support_platform[@]}" | grep -w "${PLATFORM}")" ]]; then
tolog "Missing [ PLATFORM ] value in ${AMLOGIC_SOC_FILE} file." "1"
fi
tolog "PLATFORM: [ ${PLATFORM} ]"
sleep 2
# 01. Query local version information
tolog "01. Query current version information."
# If neither opkg nor apk found, set package_manager to empty
package_manager=""
current_plugin_v=""
if command -v opkg >/dev/null 2>&1; then
# System has opkg
package_manager="ipk"
# Important: Add cut to handle versions like X.Y.Z-r1, ensuring consistent output
current_plugin_v="$(opkg list-installed | grep '^luci-app-amlogic' | awk '{print $3}' | cut -d'-' -f1)"
elif command -v apk >/dev/null 2>&1; then
# System has apk
package_manager="apk"
current_plugin_v="$(apk list --installed | grep '^luci-app-amlogic' | awk '{print $1}' | cut -d'-' -f4)"
fi
# Check if we successfully found the plugin
if [[ -z "${package_manager}" || -z "${current_plugin_v}" ]]; then
tolog "01.01 Plugin 'luci-app-amlogic' not found or package manager unknown." "1"
else
tolog "01.01 Using [${package_manager}]. Current version: ${current_plugin_v}"
fi
sleep 2
# 02. Check the version on the server
tolog "02. Start querying plugin version..."
# Get the latest version
latest_version="$(
curl -fsSL -m 10 \
https://github.com/ophub/luci-app-amlogic/releases |
grep -oE 'expanded_assets/[0-9]+.[0-9]+.[0-9]+(-[0-9]+)?' | sed 's|expanded_assets/||g' |
sort -urV | head -n 1
)"
if [[ -z "${latest_version}" ]]; then
tolog "02.01 Query failed, please try again." "1"
else
tolog "02.01 current version: ${current_plugin_v}, Latest version: ${latest_version}"
sleep 2
fi
# Compare the version and download the latest version
if [[ "${current_plugin_v}" == "${latest_version}" ]]; then
tolog "02.02 Already the latest version, no need to update." "1"
else
tolog "02.03 New version found. Preparing to download for [${package_manager}]..."
download_repo="https://github.com/ophub/luci-app-amlogic/releases/download"
# Intelligent File Discovery
plugin_file_name=""
lang_file_list=""
# Method 1: Use GitHub API if 'jq' is installed (Preferred Method)
if command -v jq >/dev/null 2>&1; then
tolog "Using GitHub API with jq to find package files."
api_url="https://api.github.com/repos/ophub/luci-app-amlogic/releases/tags/${latest_version}"
# Fetch all asset names from the API
asset_list="$(curl -fsSL -m 15 "${api_url}" | jq -r '.assets[].name' | xargs)"
if [[ -n "${asset_list}" ]]; then
# Discover exact filenames using regular expressions from the asset list
plugin_file_name="$(echo "${asset_list}" | tr ' ' '\n' | grep -oE "^luci-app-amlogic.*${package_manager}$" | head -n 1)"
lang_file_list=($(echo "${asset_list}" | tr ' ' '\n' | grep -oE "^luci-i18n-amlogic.*${package_manager}$"))
else
tolog "Warning: Failed to fetch data from GitHub API." "1"
fi
else
tolog "jq not found, Aborting." "1"
fi
# Validation and Download
if [[ -z "${plugin_file_name}" || "${#lang_file_list[@]}" -eq "0" ]]; then
tolog "02.03.2 Could not discover plugin(.${package_manager}) in the release. Aborting." "1"
fi
tolog "Found plugin file: ${plugin_file_name}"
tolog "Found language file: $(echo ${lang_file_list[@]} | xargs)"
# Download the main plugin file
plugin_full_url="${download_repo}/${latest_version}/${plugin_file_name}"
tolog "02.04 Downloading main plugin..."
curl -fsSL "${plugin_full_url}" -o "${TMP_CHECK_DIR}/${plugin_file_name}"
[[ "${?}" -ne "0" ]] && tolog "02.04 Plugin [ ${plugin_file_name} ] download failed." "1"
# Download language packs
for langfile in "${lang_file_list[@]}"; do
lang_full_url="${download_repo}/${latest_version}/${langfile}"
tolog "02.05 Downloading language pack [ ${langfile} ]..."
curl -fsSL "${lang_full_url}" -o "${TMP_CHECK_DIR}/${langfile}"
[[ "${?}" -ne "0" ]] && tolog "02.05 Language pack [ ${langfile} ] download failed." "1"
done
sync && sleep 2
fi
tolog "03. The plug is ready, you can update."
sleep 2
tolog '<input type="button" class="cbi-button cbi-button-reload" value="Update" onclick="return amlogic_plugin(this)"/> Latest version: '${latest_version}'' "1"
exit 0
@@ -0,0 +1,11 @@
{
"luci-app-amlogic": {
"description": "Grant UCI access for luci-app-amlogic",
"read": {
"uci": [ "amlogic" ]
},
"write": {
"uci": [ "amlogic" ]
}
}
}
@@ -0,0 +1,4 @@
{
"config": "amlogic",
"init": "amlogic"
}