diff --git a/brook/Makefile b/brook/Makefile index 59df75cfc..9cc51366e 100644 --- a/brook/Makefile +++ b/brook/Makefile @@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=brook -PKG_VERSION:=20220404 +PKG_VERSION:=20220406 PKG_RELEASE:=$(AUTORELEASE) PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz diff --git a/luci-app-amlogic/Makefile b/luci-app-amlogic/Makefile new file mode 100644 index 000000000..153b074da --- /dev/null +++ b/luci-app-amlogic/Makefile @@ -0,0 +1,39 @@ +#=================================================================================================== +# 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: Support install/update/backup/restore/snapshot etc for OpenWrt on amlogic s9xxx boxs +# Copyright (C) 2021- The Upload file functions by luci-app-filetransfer +# Copyright (C) 2021- The CPU Settings functions by luci-app-cpufreq +# Copyright (C) 2021- The Log viewing and version query functions by Vernesong +# Copyright (C) 2021- The Kernel and scripts etc by unifreq +# Copyright (C) 2021- https://github.com/unifreq/openwrt_packit +# Copyright (C) 2021- https://github.com/ophub/luci-app-amlogic +#=================================================================================================== + +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-amlogic +PKG_VERSION:=3.1.75 +PKG_RELEASE:=1 + +PKG_LICENSE:=GPL-2.0 License +PKG_MAINTAINER:=ophub + +LUCI_TITLE:=LuCI support for Amlogic, Allwinner and Rockchip related boxs +LUCI_PKGARCH:=all +LUCI_DEPENDS:= \ + @(aarch64||arm) +luci-lib-fs +block-mount +blkid +parted \ + +dosfstools +e2fsprogs +lsblk +pv +resize2fs +losetup +uuidgen + +define Package/$(PKG_NAME)/conffiles +/etc/config/amlogic +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-amlogic/htdocs/luci-static/resources/amlogic/author.svg b/luci-app-amlogic/htdocs/luci-static/resources/amlogic/author.svg new file mode 100644 index 000000000..80b3a5e3f --- /dev/null +++ b/luci-app-amlogic/htdocs/luci-static/resources/amlogic/author.svg @@ -0,0 +1 @@ +OpenWrt: Compiler authorOpenWrtCompiler author \ No newline at end of file diff --git a/luci-app-amlogic/htdocs/luci-static/resources/amlogic/loading.gif b/luci-app-amlogic/htdocs/luci-static/resources/amlogic/loading.gif new file mode 100644 index 000000000..715431483 Binary files /dev/null and b/luci-app-amlogic/htdocs/luci-static/resources/amlogic/loading.gif differ diff --git a/luci-app-amlogic/htdocs/luci-static/resources/amlogic/logo.png b/luci-app-amlogic/htdocs/luci-static/resources/amlogic/logo.png new file mode 100644 index 000000000..fe2f2f4a2 Binary files /dev/null and b/luci-app-amlogic/htdocs/luci-static/resources/amlogic/logo.png differ diff --git a/luci-app-amlogic/htdocs/luci-static/resources/amlogic/packit.svg b/luci-app-amlogic/htdocs/luci-static/resources/amlogic/packit.svg new file mode 100644 index 000000000..f632efd69 --- /dev/null +++ b/luci-app-amlogic/htdocs/luci-static/resources/amlogic/packit.svg @@ -0,0 +1 @@ +OpenWrt: flippy's homepageOpenWrtflippy's homepage \ No newline at end of file diff --git a/luci-app-amlogic/htdocs/luci-static/resources/amlogic/plugin.svg b/luci-app-amlogic/htdocs/luci-static/resources/amlogic/plugin.svg new file mode 100644 index 000000000..e4352606f --- /dev/null +++ b/luci-app-amlogic/htdocs/luci-static/resources/amlogic/plugin.svg @@ -0,0 +1 @@ +Plugin: luci-app-amlogicPluginluci-app-amlogic \ No newline at end of file diff --git a/luci-app-amlogic/htdocs/luci-static/resources/amlogic/poweroff.png b/luci-app-amlogic/htdocs/luci-static/resources/amlogic/poweroff.png new file mode 100644 index 000000000..5f82cf4de Binary files /dev/null and b/luci-app-amlogic/htdocs/luci-static/resources/amlogic/poweroff.png differ diff --git a/luci-app-amlogic/luasrc/controller/amlogic.lua b/luci-app-amlogic/luasrc/controller/amlogic.lua new file mode 100644 index 000000000..6633b3bc8 --- /dev/null +++ b/luci-app-amlogic/luasrc/controller/amlogic.lua @@ -0,0 +1,450 @@ +module("luci.controller.amlogic", package.seeall) + +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 = { "luci-app-amlogic" } + + entry({"admin", "system", "amlogic", "info"}, cbi("amlogic/amlogic_info"), _("Amlogic Service"), 1).leaf = true + entry({"admin", "system", "amlogic", "install"}, cbi("amlogic/amlogic_install"), _("Install OpenWrt"), 2).leaf = true + entry({"admin", "system", "amlogic", "upload"}, cbi("amlogic/amlogic_upload"), _("Manually Upload Update"), 3).leaf = true + entry({"admin", "system", "amlogic", "check"}, cbi("amlogic/amlogic_check"), _("Online Download Update"), 4).leaf = true + entry({"admin", "system", "amlogic", "backup"}, cbi("amlogic/amlogic_backup"), _("Backup Firmware Config"), 5).leaf = true + entry({"admin", "system", "amlogic", "armcpu"}, cbi("amlogic/amlogic_armcpu"), _("CPU Settings"), 6).leaf = true + entry({"admin", "system", "amlogic", "config"}, cbi("amlogic/amlogic_config"), _("Plugin Settings"), 7).leaf = true + entry({"admin", "system", "amlogic", "log"}, cbi("amlogic/amlogic_log"), _("Server Logs"), 8).leaf = true + entry({"admin", "system", "amlogic", "poweroff"}, cbi("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_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_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 +end + +local fs = require "luci.fs" + +--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 +mydevice_logs = luci.sys.exec("cat /proc/device-tree/model | tr -d \'\\000\' > /tmp/amlogic/amlogic_mydevice_name.log && sync") +mydevice_name = luci.sys.exec("cat /proc/device-tree/model | tr -d \'\\000\'") or "Unknown device" +if string.find(mydevice_name, "Chainedbox L1 Pro") ~= nil then + device_install_script = "" + device_update_script = "openwrt-update-rockchip" + device_kernel_script = "openwrt-kernel" +elseif string.find(mydevice_name, "BeikeYun") ~= nil then + device_install_script = "" + device_update_script = "openwrt-update-rockchip" + device_kernel_script = "openwrt-kernel" +elseif string.find(mydevice_name, "V-Plus Cloud") ~= nil then + device_install_script = "" + device_update_script = "openwrt-update-allwinner" + 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 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_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_running_script.log") +end + +--Upgrade luci-app-amlogic plugin +function start_amlogic_plugin() + luci.sys.call("echo '1@Plugin update in progress, try again later!' > /tmp/amlogic/amlogic_running_script.log && sync >/dev/null 2>&1") + local ipk_state = luci.sys.call("[ -f /etc/config/amlogic ] && cp -vf /etc/config/amlogic /etc/config/amlogic_bak > /tmp/amlogic/amlogic_check_plugin.log && sync >/dev/null 2>&1") + local ipk_state = luci.sys.call("opkg --force-reinstall install /tmp/amlogic/*.ipk > /tmp/amlogic/amlogic_check_plugin.log && sync >/dev/null 2>&1") + local ipk_state = luci.sys.call("[ -f /etc/config/amlogic_bak ] && cp -vf /etc/config/amlogic_bak /etc/config/amlogic > /tmp/amlogic/amlogic_check_plugin.log && sync >/dev/null 2>&1") + local ipk_state = luci.sys.call("rm -rf /tmp/luci-indexcache /tmp/luci-modulecache/* /etc/config/amlogic_bak >/dev/null 2>&1") + luci.sys.call("echo '' > /tmp/amlogic/amlogic_running_script.log && sync >/dev/null 2>&1") + local state = luci.sys.call("echo 'Successful Update' > /tmp/amlogic/amlogic_check_plugin.log && sync >/dev/null 2>&1") + return state +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 + +--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 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 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 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("ls /lib/modules/ 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() + return luci.sys.exec("opkg list-installed | grep 'luci-app-amlogic' | awk '{print $3}'") or "Invalid value." +end + +--Return the current kernel version +local function current_kernel_version() + return luci.sys.exec("ls /lib/modules/ 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("ls /lib/modules/ 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() + local state = luci.sys.exec("cat /etc/model_database.txt | grep -E '^[0-9]{1,9}:' | awk -F ':' '{print $1,$2}' OFS='###' ORS='@@@' | tr ' ' '~' 2>&1") + return state +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 diff --git a/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_armcpu.lua b/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_armcpu.lua new file mode 100644 index 000000000..444684cf5 --- /dev/null +++ b/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_armcpu.lua @@ -0,0 +1,94 @@ +--Copyright: https://github.com/coolsnowwolf/lede/tree/master/package/lean/luci-app-cpufreq +--Planner: https://github.com/unifreq/openwrt_packit +--Extended support: https://github.com/ophub/luci-app-amlogic +--Function: Support multi-core + +local fs = require "luci.fs" +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 = 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 = 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 + +return mp diff --git a/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_backup.lua b/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_backup.lua new file mode 100644 index 000000000..81a8298d7 --- /dev/null +++ b/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_backup.lua @@ -0,0 +1,90 @@ +local fs = require "luci.fs" +local http = require "luci.http" +local DISP = require "luci.dispatcher" +local b, c + +--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, "", "") + +o = s:option(Button, "", 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 = nixio.fs.basename(sPath) + if luci.fs.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 + + http.header('Content-Disposition', 'attachment; filename="%s"' % {sFile}) + http.prepare_content("application/octet-stream") + while true do + block = fd:read(nixio.const.buffersize) + if (not block) or (#block ==0) then + break + else + http.write(block) + end + end + fd:close() + http.close() +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, "", "") +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") + http.redirect(DISP.build_url("admin", "system", "amlogic", "backup")) +end +w = d:option(TextValue, "snapshot_list", nil) +w.template = "amlogic/other_snapshot" + +return b, c diff --git a/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_check.lua b/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_check.lua new file mode 100644 index 000000000..2d642a315 --- /dev/null +++ b/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_check.lua @@ -0,0 +1,14 @@ +local fs = require "luci.fs" +local http = require "luci.http" +local DISP = require "luci.dispatcher" +local b + +--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" + +return b diff --git a/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_config.lua b/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_config.lua new file mode 100644 index 000000000..a2cc7af6d --- /dev/null +++ b/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_config.lua @@ -0,0 +1,92 @@ +--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 .. "
" .. translate("Tips: The amlogic SoC (E.g: s905d) and mainline version of the kernel (E.g: 5.10) will automatically match the current openwrt firmware.") +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("If the current device shows (Unknown device), please report to github.") +mydevice.default = luci.sys.exec("cat /proc/device-tree/model | tr -d \'\\000\'") or "Unknown device" +mydevice.rmempty = false + +--2.Set OpenWrt Firmware Repository +firmware_repo = o:option(Value, "amlogic_firmware_repo", translate("Download repository of OpenWrt:")) +firmware_repo.description = translate("Set the download repository of the OpenWrt files on github.com in [Online Download Update].") +firmware_repo.default = "https://github.com/breakings/OpenWrt" +firmware_repo.rmempty = false + +--3.Set OpenWrt Releases's Tag Keywords +firmware_tag = o:option(Value, "amlogic_firmware_tag", translate("Keywords of Tags in Releases:")) +firmware_tag.description = translate("Set the keywords of Tags in Releases of 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("Suffix of OpenWrt files:")) +firmware_suffix.description = translate("Set the suffix of the OpenWrt in Releases of 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("Download path of OpenWrt kernel:")) +kernel_path.description = translate("Set the download path of the kernel in the github.com repository in [Online Download Update].") +kernel_path.default = "opt/kernel" +kernel_path.rmempty = false + +--6.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 firmware 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("5.16", translate("5.16")) +kernel_branch:value("5.17", translate("5.17")) +local default_kernel_branch = luci.sys.exec("ls /lib/modules/ 2>/dev/null | grep -oE '^[1-9].[0-9]{1,3}'") +kernel_branch.default = trim(default_kernel_branch) +kernel_branch.rmempty = false + +--7.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 + +--8.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 + +--9.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 diff --git a/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_info.lua b/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_info.lua new file mode 100644 index 000000000..ea41fc132 --- /dev/null +++ b/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_info.lua @@ -0,0 +1,14 @@ +local fs = require "luci.fs" +local http = require "luci.http" +local DISP = require "luci.dispatcher" +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 diff --git a/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_install.lua b/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_install.lua new file mode 100644 index 000000000..0fbef3b43 --- /dev/null +++ b/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_install.lua @@ -0,0 +1,14 @@ +local fs = require "luci.fs" +local http = require "luci.http" +local DISP = require "luci.dispatcher" +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 diff --git a/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_log.lua b/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_log.lua new file mode 100644 index 000000000..94cef1f47 --- /dev/null +++ b/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_log.lua @@ -0,0 +1,18 @@ +local fs = require "luci.fs" +local http = require "luci.http" +local DISP = require "luci.dispatcher" +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 diff --git a/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_poweroff.lua b/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_poweroff.lua new file mode 100644 index 000000000..ff7c04082 --- /dev/null +++ b/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_poweroff.lua @@ -0,0 +1,14 @@ +local fs = require "luci.fs" +local http = require "luci.http" +local DISP = require "luci.dispatcher" +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 diff --git a/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_upload.lua b/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_upload.lua new file mode 100644 index 000000000..b748de762 --- /dev/null +++ b/luci-app-amlogic/luasrc/model/cbi/amlogic/amlogic_upload.lua @@ -0,0 +1,228 @@ +local fs = require "luci.fs" +local http = require "luci.http" +local DISP = require "luci.dispatcher" +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 + +--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") +b.description = translate("After uploading [Firmware], [Kernel], [IPK] or [Backup Config], the operation buttons will be displayed.") +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 +nixio.fs.mkdir(dir) +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(fs.glob(trim(upload_path .. "*"))) do + attr = fs.stat(f) + itisfile = fs.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 = ' Tip: ' .. description_info .. ' ' +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 = luci.fs.unlink(trim(upload_path .. luci.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 + +function IsIpkFile(name) + name = name or "" + local ext = string.lower(string.sub(name, -4, -1)) + return ext == ".ipk" +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 IsIpkFile(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) + if IsIpkFile(inits[section].name) then + local r = luci.sys.exec(string.format('opkg --force-reinstall install ' .. upload_path .. '%s', inits[section].name)) + local x = luci.sys.exec("rm -rf /tmp/luci-indexcache /tmp/luci-modulecache/* 2>/dev/null") + form.description = string.format('%s', r) + elseif IsConfigFile(inits[section].name) then + form.description = ' ' .. translate("Tip: The config is being restored, and it will automatically restart after completion.") .. ' ' + local x = luci.sys.exec("chmod +x /usr/sbin/openwrt-backup 2>/dev/null") + local r = 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 diff --git a/luci-app-amlogic/luasrc/view/amlogic/other_button.htm b/luci-app-amlogic/luasrc/view/amlogic/other_button.htm new file mode 100644 index 000000000..e0eb3fd1a --- /dev/null +++ b/luci-app-amlogic/luasrc/view/amlogic/other_button.htm @@ -0,0 +1,7 @@ +<%+cbi/valueheader%> + <% if self:cfgvalue(section) ~= false then %> + " style="display: <%= display %>" type="submit" <%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.inputtitle or self.title)%> /> + <% else %> + - + <% end %> +<%+cbi/valuefooter%> diff --git a/luci-app-amlogic/luasrc/view/amlogic/other_check.htm b/luci-app-amlogic/luasrc/view/amlogic/other_check.htm new file mode 100644 index 000000000..50176b7a4 --- /dev/null +++ b/luci-app-amlogic/luasrc/view/amlogic/other_check.htm @@ -0,0 +1,222 @@ + +
+ + + + + +
+

+ <%:The OpenWrt and kernel will be downloaded and updated according to the options filled in [Plugin Settings].%> +

+
<%:Collecting data...%> 
<%:Collecting data...%> 
<%:Collecting data...%> 
+
+ diff --git a/luci-app-amlogic/luasrc/view/amlogic/other_dvalue.htm b/luci-app-amlogic/luasrc/view/amlogic/other_dvalue.htm new file mode 100644 index 000000000..296c61e4d --- /dev/null +++ b/luci-app-amlogic/luasrc/view/amlogic/other_dvalue.htm @@ -0,0 +1,8 @@ +<%+cbi/valueheader%> + +<% + local val = self:cfgvalue(section) or self.default or "" + write(pcdata(val)) +%> + +<%+cbi/valuefooter%> diff --git a/luci-app-amlogic/luasrc/view/amlogic/other_info.htm b/luci-app-amlogic/luasrc/view/amlogic/other_info.htm new file mode 100644 index 000000000..44360a843 --- /dev/null +++ b/luci-app-amlogic/luasrc/view/amlogic/other_info.htm @@ -0,0 +1,64 @@ + +
+ + + + + +
+ Logo +
+ Packit +    + Author +    + luci-app-amlogic +
<%:Supported functions:%> + <%:Provide services such as install to EMMC, Update Firmware and Kernel, Backup and Recovery Config, Snapshot management, etc.%> +
<%:Supported Boxes:%> + <%:Amlogic s922x --- [ Belink, Belink-Pro, Ugoos-AM6-Plus, ODROID-N2, Khadas VIM3(a311d) ]%>
+ <%:Amlogic s905x3 -- [ X96-Max+, HK1-Box, H96-Max-X3, Ugoos-X3, TX3, X96-Air, A95XF3-Air ]%>
+ <%:Amlogic s905x2 -- [ X96Max-4G, X96Max-2G ]%>
+ <%:Amlogic s905x --- [ HG680P, B860H ]%>
+ <%:Amlogic s905w --- [ X96-Mini, TX3-Mini ]%>
+ <%:Amlogic s912 ---- [ H96-Pro-Plus, Octopus-Planet ]%>
+ <%:Amlogic s905d --- [ Phicomm-N1 ]%>
+ <%:Amlogic Other --- [ Optional DTB ]%>
+ <%:Allwinner H6 ---- [ V-Plus Cloud ]%>
+ <%:Rockchip 3328 --- [ BeikeYun, Chainedbox L1 Pro ]%> +
+
+ diff --git a/luci-app-amlogic/luasrc/view/amlogic/other_install.htm b/luci-app-amlogic/luasrc/view/amlogic/other_install.htm new file mode 100644 index 000000000..4d069d64c --- /dev/null +++ b/luci-app-amlogic/luasrc/view/amlogic/other_install.htm @@ -0,0 +1,143 @@ + +
+ + + + + + + + + +
<%:Select the device model:%> + +
<%:Install OpenWrt:%> +   +
+
+ diff --git a/luci-app-amlogic/luasrc/view/amlogic/other_log.htm b/luci-app-amlogic/luasrc/view/amlogic/other_log.htm new file mode 100644 index 000000000..f58da6e4b --- /dev/null +++ b/luci-app-amlogic/luasrc/view/amlogic/other_log.htm @@ -0,0 +1,117 @@ +<%+cbi/valueheader%> + +
+ + + + + + + +
+
+ + + +<%+cbi/valuefooter%> \ No newline at end of file diff --git a/luci-app-amlogic/luasrc/view/amlogic/other_poweroff.htm b/luci-app-amlogic/luasrc/view/amlogic/other_poweroff.htm new file mode 100644 index 000000000..3b485fdf7 --- /dev/null +++ b/luci-app-amlogic/luasrc/view/amlogic/other_poweroff.htm @@ -0,0 +1,48 @@ + +
+ + +
+ +

+ <%:Loading%> + + <%:Device is shutting down...%> +

+
+
+ + diff --git a/luci-app-amlogic/luasrc/view/amlogic/other_snapshot.htm b/luci-app-amlogic/luasrc/view/amlogic/other_snapshot.htm new file mode 100644 index 000000000..9293e626c --- /dev/null +++ b/luci-app-amlogic/luasrc/view/amlogic/other_snapshot.htm @@ -0,0 +1,152 @@ + + +
+ <%:Collecting data...%> +
+ + + diff --git a/luci-app-amlogic/luasrc/view/amlogic/other_upfiles.htm b/luci-app-amlogic/luasrc/view/amlogic/other_upfiles.htm new file mode 100644 index 000000000..d8e438d84 --- /dev/null +++ b/luci-app-amlogic/luasrc/view/amlogic/other_upfiles.htm @@ -0,0 +1,130 @@ + + +
+ + + +
+

+ <%:After uploading firmware (.img/.img.gz/.img.xz/.7z suffix) or kernel files (3 kernel files), the update button will be displayed.%> +

+
+ + + + <%:Collecting data...%>  + +
+
+ + diff --git a/luci-app-amlogic/luasrc/view/amlogic/other_upload.htm b/luci-app-amlogic/luasrc/view/amlogic/other_upload.htm new file mode 100644 index 000000000..1ff1a9b01 --- /dev/null +++ b/luci-app-amlogic/luasrc/view/amlogic/other_upload.htm @@ -0,0 +1,5 @@ +<%+cbi/valueheader%> + + + +<%+cbi/valuefooter%> diff --git a/luci-app-amlogic/po/zh-cn/amlogic.po b/luci-app-amlogic/po/zh-cn/amlogic.po new file mode 100644 index 000000000..c096115f0 --- /dev/null +++ b/luci-app-amlogic/po/zh-cn/amlogic.po @@ -0,0 +1,575 @@ +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 "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 "[s905d] Phicomm N1" +msgstr "[s905d] 斐讯-N1" + +msgid "[s905d] Phicomm N1 (DMA thresh)" +msgstr "[s905d] 斐讯-N1 (流控)" + +msgid "[s905x] HG680P & B860H" +msgstr "[s905x] 烽火HG680 & 中兴B860H" + +msgid "[s905w] X96-Mini & TX3-Mini" +msgstr "[s905w] X96-Mini & TX3-Mini" + +msgid "[s912] Octopus Planet" +msgstr "[s912] 章鱼星球" + +msgid "[s905x2] X96 Max 4G" +msgstr "[s905x2] X96 Max 4G" + +msgid "[s905x2] X96 Max 2G" +msgstr "[s905x2] X96 Max 2G" + +msgid "[s922x] Belink GT-King" +msgstr "[s922x] Belink GT-King" + +msgid "[s922x] Belink GT-King Pro" +msgstr "[s922x] Belink GT-King Pro" + +msgid "[s922x] Belink GT-King Pro H" +msgstr "[s922x] Belink GT-King Pro H" + +msgid "[s922x] Belink GT-King Pro Rev_A" +msgstr "[s922x] Belink GT-King Pro Rev_A" + +msgid "[s922x] Hardkernel ODROID N2" +msgstr "[s922x] Hardkernel ODROID N2" + +msgid "[s922x] UGOOS AM6 Plus" +msgstr "[s922x] UGOOS AM6 Plus" + +msgid "[a311d] Khadas VIM3" +msgstr "[a311d] Khadas VIM3" + +msgid "[s905x3] X96 Max+" +msgstr "[s905x3] X96 Max+" + +msgid "[s905x3] X96 Max+ (OverClock@2208Mhz)" +msgstr "[s905x3] X96 Max+ (超频@2208Mhz)" + +msgid "[s905x3] HK1 Box" +msgstr "[s905x3] HK1 Box" + +msgid "[s905x3] HK1 Box (OverClock@2208Mhz)" +msgstr "[s905x3] HK1 Box (超频@2208Mhz)" + +msgid "[s905x3] H96 Max X3" +msgstr "[s905x3] H96 Max X3" + +msgid "[s905x3] H96 Max X3 (OverClock@2208Mhz)" +msgstr "[s905x3] H96 Max X3 (超频@2208Mhz)" + +msgid "[s905x3] Ugoos X3" +msgstr "[s905x3] Ugoos X3" + +msgid "[s905x3] Ugoos X3 (OverClock@2208Mhz)" +msgstr "[s905x3] Ugoos X3 (超频@2208Mhz)" + +msgid "[s905x3] TX3 BZ" +msgstr "[s905x3] TX3 百兆" + +msgid "[s905x3] TX3 BZ (OverClock@2208Mhz)" +msgstr "[s905x3] TX3 百兆 (超频@2208Mhz)" + +msgid "[s905x3] TX3 QZ" +msgstr "[s905x3] TX3 千兆" + +msgid "[s905x3] TX3 QZ (OverClock@2208Mhz)" +msgstr "[s905x3] TX3 千兆 (超频@2208Mhz)" + +msgid "Or enter the dtb file name:" +msgstr "或者输入自定义 dtb 文件名:" + +msgid "Enter the dtb file name" +msgstr "输入自定义 dtb 文件名" + +msgid "Use custom dtb file:" +msgstr "使用自定义 dtb 文件:" + +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 --- [ Belink, Belink-Pro, Ugoos-AM6-Plus, ODROID-N2, Khadas VIM3(a311d) ]" +msgstr "晶晨 s922x --- [ Belink, Belink-Pro, Ugoos-AM6-Plus, ODROID-N2, Khadas VIM3(a311d) ]" + +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 ]" +msgstr "晶晨 s905x2 -- [ X96Max-4G, X96Max-2G ]" + +msgid "Amlogic s905x --- [ HG680P, B860H ]" +msgstr "晶晨 s905x --- [ 烽火HG680 & 中兴B860H ]" + +msgid "Amlogic s905w --- [ X96-Mini, TX3-Mini ]" +msgstr "晶晨 s905w --- [ X96-Mini, TX3-Mini ]" + +msgid "Amlogic s912 ---- [ H96-Pro-Plus, Octopus-Planet ]" +msgstr "晶晨 s912 ---- [ H96-Pro-Plus, 章鱼星球 ]" + +msgid "Amlogic s905d --- [ Phicomm-N1 ]" +msgstr "晶晨 s905d --- [ 斐讯-N1 ]" + +msgid "Amlogic Other --- [ Optional DTB ]" +msgstr "晶晨其他 ----- [ 自定义 DTB 文件 ]" + +msgid "Allwinner H6 ---- [ V-Plus Cloud ]" +msgstr "全志 H6 ------ [ 微加云 ]" + +msgid "Rockchip 3328 --- [ BeikeYun, Chainedbox L1 Pro ]" +msgstr "瑞芯微 3328 -- [ 贝壳云、我家云 ]" + +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 "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 "Tips: The amlogic SoC (E.g: s905d) and mainline version of the kernel (E.g: 5.10) will automatically match the current openwrt firmware." +msgstr "提示:OpenWrt 固件的型号(如:s905d)和内核的主线版本(如:5.10)将根据当前固件自动适配。" + +msgid "Download repository of OpenWrt:" +msgstr "OpenWrt 固件的下载仓库:" + +msgid "Set the download repository of the OpenWrt files on github.com in [Online Download Update]." +msgstr "设置 [在线下载更新] 中 github.com 的 OpenWrt 固件的下载仓库。" + +msgid "Keywords of Tags in Releases:" +msgstr "Releases 里 Tags 的关键字:" + +msgid "Set the keywords of Tags in Releases of github.com in [Online Download Update]." +msgstr "设置 [在线下载更新] 中 github.com 的 Releases 里 Tags 的关键字。" + +msgid "Suffix of OpenWrt files:" +msgstr "OpenWrt 固件的后缀:" + +msgid "Set the suffix of the OpenWrt in Releases of github.com in [Online Download Update]." +msgstr "设置 [在线下载更新] 中 github.com 的 Releases 里 OpenWrt 固件的后缀。" + +msgid "Download path of OpenWrt kernel:" +msgstr "OpenWrt 内核的下载路径:" + +msgid "Set the download path of the kernel in the github.com repository in [Online Download Update]." +msgstr "设置 [在线下载更新] 中 github.com 仓库里内核的下载路径。" + +msgid "Set version branch:" +msgstr "设置版本分支:" + +msgid "Set the version branch of the openwrt firmware 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 "Current Device:" +msgstr "当前设备:" + +msgid "If the current device shows (Unknown device), please report to github." +msgstr "如果当前设备显示无法识别(Unknown device),请到 github 反馈。" + +msgid "The OpenWrt and kernel will be downloaded and updated according to the options filled in [Plugin Settings]." +msgstr "将根据在 [插件设置] 里面填写的选项进行 OpenWrt 固件和内核的下载与更新。" + +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 "设备已经关机" + + diff --git a/luci-app-amlogic/po/zh_Hans b/luci-app-amlogic/po/zh_Hans new file mode 120000 index 000000000..41451e4a1 --- /dev/null +++ b/luci-app-amlogic/po/zh_Hans @@ -0,0 +1 @@ +zh-cn \ No newline at end of file diff --git a/luci-app-amlogic/root/etc/config/amlogic b/luci-app-amlogic/root/etc/config/amlogic new file mode 100644 index 000000000..d7fceb57f --- /dev/null +++ b/luci-app-amlogic/root/etc/config/amlogic @@ -0,0 +1,16 @@ + +config amlogic 'config' + option enable '1' + option amlogic_firmware_repo 'https://github.com/breakings/OpenWrt' + option amlogic_firmware_tag 'ARMv8' + option amlogic_firmware_suffix '.img.gz' + option amlogic_kernel_path 'opt/kernel' + 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' diff --git a/luci-app-amlogic/root/etc/init.d/amlogic b/luci-app-amlogic/root/etc/init.d/amlogic new file mode 100755 index 000000000..4447ede14 --- /dev/null +++ b/luci-app-amlogic/root/etc/init.d/amlogic @@ -0,0 +1,42 @@ +#!/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 + done +} diff --git a/luci-app-amlogic/root/etc/uci-defaults/luci-amlogic b/luci-app-amlogic/root/etc/uci-defaults/luci-amlogic new file mode 100755 index 000000000..dd0973033 --- /dev/null +++ b/luci-app-amlogic/root/etc/uci-defaults/luci-amlogic @@ -0,0 +1,13 @@ +#!/bin/sh + +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 diff --git a/luci-app-amlogic/root/usr/sbin/fixcpufreq.pl b/luci-app-amlogic/root/usr/sbin/fixcpufreq.pl new file mode 100755 index 000000000..3bb2622cd --- /dev/null +++ b/luci-app-amlogic/root/usr/sbin/fixcpufreq.pl @@ -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 = ; +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; +} diff --git a/luci-app-amlogic/root/usr/sbin/openwrt-backup b/luci-app-amlogic/root/usr/sbin/openwrt-backup new file mode 100755 index 000000000..d1cf8d25f --- /dev/null +++ b/luci-app-amlogic/root/usr/sbin/openwrt-backup @@ -0,0 +1,571 @@ +#!/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.2" +ZSTD_LEVEL=6 +SNAPSHOT_PRESTR=".snapshots/" +BACKUP_DIR="/.reserved" +BACKUP_NAME="openwrt_config.tar.gz" +BACKUP_FILE="${BACKUP_DIR}/${BACKUP_NAME}" +BACKUP_LIST='./etc/AdGuardHome.yaml \ +./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/ \ +./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/transmission/ \ +./etc/uhttpd.crt \ +./etc/uhttpd.key \ +./etc/urandom.seed \ +./etc/verysync/ \ +./root/.ssh/' + +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 + echo "Unknown platform, only support amlogic or rockchip or allwinner h6!" + exit 1 +fi + +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 + echo "Backup failed!" + exit 1 + fi +} + +restore() { + # Find the partition where root is located + ROOT_PTNAME=$(df / | tail -n1 | awk '{print $1}' | awk -F '/' '{print $3}') + if [ "${ROOT_PTNAME}" == "" ]; then + echo "Cannot find the partition corresponding to the root file system!" + exit 1 + fi + + # 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="" + ;; + *) + echo "Unable to recognize the disk type of ${ROOT_PTNAME}!" + exit 1 + ;; + 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 + echo "The backup file [ ${BACKUP_FILE} ] not found!" + exit 1 + fi +} + +gen_fstab() { + # Find the partition where root is located + ROOT_PTNAME=$(df / | tail -n1 | awk '{print $1}' | awk -F '/' '{print $3}') + if [ "${ROOT_PTNAME}" == "" ]; then + echo "Cannot find the partition corresponding to the root file system!" + exit 1 + fi + + # 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="" + ;; + *) + echo "Unable to recognize the disk type of ${ROOT_PTNAME}!" + exit 1 + ;; + esac + + ROOT_MSG=$(lsblk -l -o NAME,PATH,MOUNTPOINT,UUID,FSTYPE,LABEL | awk '$3 ~ /^\/$/ {print $0}') + if [ "$ROOT_MSG" == "" ]; then + echo "Get rootfs message failed!" + exit 1 + fi + + 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 <>/etc/config/fstab + fi + + cat >>/etc/config/fstab <>/etc/config/fstab + else + echo " option uuid '${BOOT_UUID}'" >>/etc/config/fstab + fi + + cat >>/etc/config/fstab </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=$(lsblk -l -o NAME,MOUNTPOINT | awk '$2~/^\/$/ {print $1}') + if [ "${cur_rootdev}" == "" ]; then + echo "The disk device corresponding to the current rootfs cannot be found!" + read -p "Press [ enter ] to return." q + return + fi + 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 </dev/null; then + echo -e "${ERROR} The current system is running on emmc. Please perform backup/restore operation in [ SD/TF/USB ]!" + exit 1 + 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="" + ;; +*) + echo -e "${ERROR} Unable to recognize the disk type of ${root_ptname}!" + exit 1 + ;; +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")" ] && echo -e "${ERROR} Unable to get EMMC size." && exit 1 + +# Check if the output directory exists +if [ ! -d "${out_path}" ]; then + echo -e "${ERROR} The backup path [ ${out_path} ] is invalid!" + echo -e " Please use the [ openwrt-tf ] command to create an extended partition first." + exit 1 +fi + +# Check the remaining space +do_checkspace() { + remaining_space="$(df -hT ${out_path} | grep '/dev/' | awk '{print $5}' | sed 's/.$//' | awk -F "." '{print $1}')" + if [ -z "$(echo "${remaining_space}" | sed -n "/^[0-9]\+$/p")" ]; then + echo -e "${ERROR} The path is not available, the remaining space cannot be obtained." + exit 1 + fi + if [[ "${remaining_space}" -lt "${need_space}" ]]; then + echo -e "${ERROR} The remaining space is [ ${remaining_space} ] GB." + echo -e "It is recommended that the remaining space should not be less than [ ${need_space} ] GB." + exit 1 + 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} ] && echo -e "${ERROR} The [ ${out_path}/${ddbr_image} ] File not found." && exit 1 + 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." +} + +# Output device information +echo -e "${STEPS} Welcome to use the EMMC system backup/restore service." +echo -e "${INFO} The device name: [ ${mydevice_name} ]" +echo -e "${INFO} The device EMMC name: [ /dev/${emmc} ]" +echo -e "${INFO} The device EMMC size: [ $(($dev_intsize / 1024 / 1024))GB ]" +echo -e "${INFO} The ddbr file path: [ ${out_path}/${ddbr_image} ]\n" + +# 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 diff --git a/luci-app-amlogic/root/usr/sbin/openwrt-install-amlogic b/luci-app-amlogic/root/usr/sbin/openwrt-install-amlogic new file mode 100755 index 000000000..e8dcedf03 --- /dev/null +++ b/luci-app-amlogic/root/usr/sbin/openwrt-install-amlogic @@ -0,0 +1,707 @@ +#!/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} ${SOC_ID} ${DTB_FILENAME} ${SHARED_FSTYPE} +# E.g: openwrt-install-amlogic yes 1 auto_dtb ext4 +# E.g: openwrt-install-amlogic no 99 meson-gxl-s905x-p212.dtb ext4 +# Tip: When custom dtb file, set ${SOC_ID} to 99, and parameter ${DTB_FILENAME} must be set +# Tip: ${SHARED_FSTYPE}: Shared partition can be ext4, xfs, btrfs, f2fs +# return 0 + +# You can also execute the script directly, and interactively select related functions +# E.g: openwrt-install-amlogic + +# Receive one-key command related parameters +AUTO_MAINLINE_UBOOT=${1} +ZSTD_LEVEL=6 + +# For [luci-app-amlogic] input parameter: SOC & DTB +# When there is no input parameter, select manually +SPECIFY_SOC="" +SPECIFY_DTB="" +if [[ -n "$(echo ${2} | sed -n "/^[0-9]\+$/p")" ]]; then + SPECIFY_SOC=${2} + if [[ "${2}" -eq "99" ]]; then + if [[ -n "${3}" ]]; then + SPECIFY_DTB=${3} + else + echo "Please enter the DTB file name!" + exit 1 + fi + else + SPECIFY_DTB="auto_dtb" + fi +fi + +# shared partition can be ext4, xfs, btrfs, f2fs +SHARED_FSTYPE=${4} + +echo "AUTO_MAINLINE_UBOOT: ${AUTO_MAINLINE_UBOOT}" +echo "SPECIFY_SOC: ${SPECIFY_SOC}" +echo "SPECIFY_DTB: ${SPECIFY_DTB}" +echo "SHARED_FSTYPE: ${SHARED_FSTYPE}" + +# Current device model +MYDEVICE_NAME=$(cat /proc/device-tree/model | tr -d '\000') +if [[ -z "${MYDEVICE_NAME}" ]]; then + echo "The device name is empty and cannot be recognized." + exit 1 +elif [[ ! -f "/etc/flippy-openwrt-release" ]]; then + echo "The [ /etc/flippy-openwrt-release ] file is missing." + exit 1 +else + echo -e "Current device: ${MYDEVICE_NAME} [ amlogic ]" + sleep 3 +fi + +# Find the device name of / +root_devname=$(df / | tail -n1 | awk '{print $1}' | awk -F '\/' '{print substr($3, 1, length($3)-2)}') +if lsblk -l | grep -E "^${root_devname}boot0" >/dev/null; then + echo "you are running in emmc mode, please boot system with usb or tf card!" + exit 1 +fi + +install_emmc="$(lsblk -l -o NAME | grep -oE '(mmcblk[0-9]?boot0)' | sed "s/boot0//g")" +if [[ "${install_emmc}" == "" ]]; then + echo "No emmc can be found to install the openwrt system!" + exit 1 +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}" + +#Choose the type of installation box +DEFAULT_FDTFILE="meson-sm1-x96-max-plus.dtb" +U_BOOT_EXT=0 + +# 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 + model_database=" +# Amlogic GXL Family +11:Phicomm N1:s905d:meson-gxl-s905d-phicomm-n1.dtb:u-boot-n1.bin:NA:/lib/u-boot/u-boot-2015-phicomm-n1.bin:4C@1512Mhz,2GB Mem,1Gb Nic,brcm43455 wifi +12:Phicomm N1 (DMA thresh):s905d:meson-gxl-s905d-phicomm-n1-thresh.dtb:u-boot-n1.bin:NA:/lib/u-boot/u-boot-2015-phicomm-n1.bin:Same as above, when ethmac flow control is off +13:hg680p & b860h:s905x:meson-gxl-s905x-p212.dtb:u-boot-p212.bin:NA:NA:4C@1512Mhz,1Gb Nic +14:X96-Mini & TX3-Mini:s905w:meson-gxl-s905w-tx3-mini.dtb:u-boot-s905x-s912.bin:NA:NA:4C@1512Mhz,100M Nic + +# Amlogic GXM Family +21:Octopus Planet:s912:meson-gxm-octopus-planet.dtb:u-boot-zyxq.bin:NA:NA:4C@1512Mhz+4C@1000Mhz,2GB Mem,1Gb Nic + +# Amlogic G12A Family +31:X96 Max 4GB:s905x2:meson-g12a-x96-max.dtb:u-boot-x96max.bin:/lib/u-boot/x96max-u-boot.bin.sd.bin:NA:4C@1908Mhz,4GB Mem,1Gb Nic +32:X96 Max 2GB:s905x2:meson-g12a-x96-max-rmii.dtb:u-boot-x96max.bin:/lib/u-boot/x96max-u-boot.bin.sd.bin:NA:4C@1908Mhz,2GB Mem,100M Nic + +# Amlogic G12B Family +41:Beelink GT-King:s922x:meson-g12b-gtking.dtb:u-boot-gtking.bin:/lib/u-boot/gtking-u-boot.bin.sd.bin:NA:2C@1800Mhz(A53)+4C@1908Mhz(A73),4GB Mem,1Gb Nic,brcm4356 wifi +42:Beelink GT-King Pro:s922x:meson-g12b-gtking-pro.dtb:u-boot-gtkingpro.bin:/lib/u-boot/gtkingpro-u-boot.bin.sd.bin:NA:2C@1800Mhz(A53)+4C@1908Mhz(A73),4GB Mem,1Gb Nic,brcm4356 wifi +43:Beelink GT-King Pro H:s922x:meson-g12b-gtking-pro-h.dtb:u-boot-gtkingpro.bin:/lib/u-boot/gtkingpro-u-boot.bin.sd.bin:NA:S922X-H,2C@1800Mhz(A53)+4C@2208Mhz(A73),4GB Mem,1Gb Nic,brcm4356 wifi +44:Beelink GT-King Pro Rev_A:s922x:meson-g12b-gtking-pro-rev_a.dtb:u-boot-gtkingpro-rev-a.bin::NA:2C@1800Mhz(A53)+4C@1908Mhz(A73),4GB Mem,1Gb Nic,brcm4356 wifi +45:Hardkernel ODroid N2:s922x:meson-g12b-odroid-n2.dtb:u-boot-gtkingpro.bin:/lib/u-boot/odroid-n2-u-boot.bin.sd.bin:NA:2C@1800Mhz(A53)+4C@1908Mhz(A73),4GB Mem,1Gb Nic +46:UGOOS AM6 Plus:s922x:meson-g12b-ugoos-am6.dtb:u-boot-gtkingpro.bin:/lib/u-boot/gtkingpro-u-boot.bin.sd.bin:NA:2C@1800Mhz(A53)+4C@1908Mhz(A73),4GB Mem,1Gb Nic,brcm4398 wifi +47:Khadas VIM3:a311d:meson-g12b-a311d-khadas-vim3.dtb:u-boot-gtkingpro.bin:/lib/u-boot/khadas-vim3-u-boot.sd.bin:NA:4C@2.2Ghz+2C@1.8Ghz,PCIe+USB 3.0,1Gb Nic,brcm4398 wifi + +# Amlogic SM1 Family +51:X96 Max+:s905x3:meson-sm1-x96-max-plus.dtb:u-boot-x96maxplus.bin:/lib/u-boot/x96maxplus-u-boot.bin.sd.bin:/lib/u-boot/hk1box-bootloader.img:4C@2100Mhz,4GB Mem,1Gb Nic,rtl8822cs wifi(no work) +52:X96 Max+ (OverClock):s905x3:meson-sm1-x96-max-plus-oc.dtb:u-boot-x96maxplus.bin:/lib/u-boot/x96maxplus-u-boot.bin.sd.bin:/lib/u-boot/hk1box-bootloader.img:4C@2208Mhz,4GB Mem,1Gb Nic,rtl8822cs wifi(no work) +53:HK1 Box:s905x3:meson-sm1-hk1box-vontar-x3.dtb:u-boot-x96maxplus.bin:/lib/u-boot/hk1box-u-boot.bin.sd.bin:NA:4C@2100Mhz,4GB Mem,1Gb Nic,brcm4339 wifi +54:HK1 Box (OverClock):s905x3:meson-sm1-hk1box-vontar-x3-oc.dtb:u-boot-x96maxplus.bin:/lib/u-boot/hk1box-u-boot.bin.sd.bin:NA:4C@2208Mhz,4GB Mem,1Gb Nic,brcm4339 wifi +55:H96 Max X3:s905x3:meson-sm1-h96-max-x3.dtb:u-boot-x96maxplus.bin:/lib/u-boot/h96maxx3-u-boot.bin.sd.bin:NA:4C@2100Mhz,4GB Mem,1Gb Nic,brcm4339 wifi +56:H96 Max X3 (OverClock):s905x3:meson-sm1-h96-max-x3-oc.dtb:u-boot-x96maxplus.bin:/lib/u-boot/h96maxx3-u-boot.bin.sd.bin:NA:4C@2208Mhz,4GB Mem,1Gb Nic,brcm4339 wifi +57:Ugoos X3:s905x3:meson-sm1-ugoos-x3.dtb:u-boot-ugoos-x3.bin:NA:NA:4C@2100Mhz,2(Cube)/4(Pro,Plus)GB Mem,1Gb Nic,brcm43455/43456 wifi +58:Ugoos X3 (OverClock):s905x3:meson-sm1-ugoos-x3-oc.dtb:u-boot-ugoos-x3.bin:NA:NA:4C@2208Mhz,2(Cube)/4(Pro,Plus)GB Mem,1Gb Nic,brcm43455/43456 wifi +59:TX3 BZ:s905x3:meson-sm1-tx3-bz.dtb:u-boot-tx3-bz.bin:/lib/u-boot/x96maxplus-u-boot.bin.sd.bin::4C@2100Mhz,4GB Mem,100Mb Nic,bcm4330 wifi +5a:TX3 BZ (OverClock):s905x3:meson-sm1-tx3-bz-oc.dtb:u-boot-tx3-bz.bin:/lib/u-boot/x96maxplus-u-boot.bin.sd.bin::4C@2208Mhz,4GB Mem,100Mb Nic,bcm4330 wifi +5b:TX3 QZ:s905x3:meson-sm1-tx3-qz.dtb:u-boot-tx3-qz.bin:/lib/u-boot/x96maxplus-u-boot.bin.sd.bin::4C@2100Mhz,4GB Mem,1Gb Nic,bcm4330 wifi +5c:TX3 QZ (OverClock):s905x3:meson-sm1-tx3-qz-oc.dtb:u-boot-tx3-qz.bin:/lib/u-boot/x96maxplus-u-boot.bin.sd.bin::4C@2208Mhz,4GB Mem,1Gb Nic,bcm4330 wifi + +# Other +0:Other::NA:NA:NA:NA:Enter the dtb file name of your box +" +fi + +function display_database() { + echo "${model_database}" | perl -ne 'chomp;if(m/^#/){s/#+\s+//;print "$_ >>>\n";}elsif($_){@f=split/:/;printf("%4s. %-30s%-8s%-s\n",$f[0],$f[1],$f[2],$f[7])}' +} + +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}" + 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_SOC}" ]]; then + boxtype=${SPECIFY_SOC} +else + echo -n "Please choose: " + read boxtype +fi + +if [ "$boxtype" == "99" ]; then + FDTFILE=${SPECIFY_DTB} + UBOOT_OVERLOAD="" + MAINLINE_UBOOT="" + ANDROID_UBOOT="" + AMLOGIC_SOC="" +else + ret=$(search_model $boxtype) + if [ "$ret" == "" ]; then + echo "Input error, exit!" + exit 1 + fi + # 3. soc + # 4. FDTFILE + # 5. UBOOT_OVERLOAD + # 6. MAINLINE_UBOOT + # 7. ANDROID_UBOOT + AMLOGIC_SOC=$(echo "$ret" | awk -F ':' '{print $3}' | perl -pe 's/NA//;s/NULL//;s/\s+//g;') + FDTFILE=$(echo "$ret" | awk -F ':' '{print $4}' | perl -pe 's/NA//;s/NULL//;s/\s+//g;') + UBOOT_OVERLOAD=$(echo "$ret" | awk -F ':' '{print $5}' | perl -pe 's/NA//;s/NULL//;s/\s+//g;') + MAINLINE_UBOOT=$(echo "$ret" | awk -F ':' '{print $6}' | perl -pe 's/NA//;s/NULL//;s/\s+//g;') + ANDROID_UBOOT=$(echo "$ret" | awk -F ':' '{print $7}' | perl -pe 's/NA//;s/NULL//;s/\s+//g;') +fi + +if [ "$FDTFILE" == "" ]; then + cat </dev/null) +VERSION_NOW=$(echo ${MODULES_NOW} | grep -oE '^[1-9].[0-9]{1,3}' 2>/dev/null) +echo -e "This Kernel [ ${MODULES_NOW} ]" + +k510_ver=${VERSION_NOW%%.*} +k510_maj=${VERSION_NOW##*.} +if [ "${k510_ver}" -eq "5" ]; then + if [ "${k510_maj}" -ge "10" ]; then + K510="1" + else + K510="0" + fi +elif [ "${k510_ver}" -gt "5" ]; then + K510="1" +else + K510="0" +fi + +# 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 + echo "$mnt Cannot be uninstalled, the installation process is aborted." + exit 1 + 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=960 +ROOT2=960 +if [[ "${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 +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 </dev/null +if [ $? -ne 0 ]; then + echo "The fdisk partition fails, Please try again." + dd if=/root/BackupOldBootloader.img of=/dev/${EMMC_NAME} conf=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 </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 + echo "Cannot mount the boot file system, give up!" + exit 1 + 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 ..." + cat >uEnv.txt </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 + echo "Cannot mount rootfs file system, give up!" + exit 1 + 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 + + echo "Update the relevant parameters of flippy-openwrt-release" + sed -i '/FDTFILE/d' etc/flippy-openwrt-release 2>/dev/null + echo "FDTFILE='${FDTFILE}'" >>etc/flippy-openwrt-release 2>/dev/null + + sed -i '/UBOOT_OVERLOAD/d' etc/flippy-openwrt-release 2>/dev/null + echo "UBOOT_OVERLOAD='${UBOOT_OVERLOAD}'" >>etc/flippy-openwrt-release 2>/dev/null + + sed -i '/MAINLINE_UBOOT/d' etc/flippy-openwrt-release 2>/dev/null + echo "MAINLINE_UBOOT='${MAINLINE_UBOOT}'" >>etc/flippy-openwrt-release 2>/dev/null + + sed -i '/ANDROID_UBOOT/d' etc/flippy-openwrt-release 2>/dev/null + echo "ANDROID_UBOOT='${ANDROID_UBOOT}'" >>etc/flippy-openwrt-release 2>/dev/null + + sed -i '/SOC/d' etc/flippy-openwrt-release 2>/dev/null + echo "SOC='${AMLOGIC_SOC}'" >>etc/flippy-openwrt-release 2>/dev/null + echo "Update complete." + sync + + cat >etc/docker/daemon.json <${tmp_dockerd} && mv ${tmp_dockerd} ./etc/config/dockerd + unset tmp_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 <fstab < .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 </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 diff --git a/luci-app-amlogic/root/usr/sbin/openwrt-kernel b/luci-app-amlogic/root/usr/sbin/openwrt-kernel new file mode 100755 index 000000000..ae42c7b31 --- /dev/null +++ b/luci-app-amlogic/root/usr/sbin/openwrt-kernel @@ -0,0 +1,289 @@ +#!/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 +# When the kernel version is upgraded from 5.10 or lower to 5.10 or higher, Can choose to install the MAINLINE_UBOOT. +# openwrt-kernel ${AUTO_MAINLINE_UBOOT} +# E.g: openwrt-kernel yes +# E.g: openwrt-kernel no + +# Receive one-key command related parameters +AUTO_MAINLINE_UBOOT="${1}" + +# Encountered a serious error, abort the script execution +error_msg() { + echo -e " [Error] ${1}" + exit 1 +} + +echo -e "Start update the openwrt kernel." +# Operation environment check +[ -x /usr/sbin/openwrt-kernel ] || error_msg "Please grant execution permission: chmod +x /usr/sbin/openwrt-kernel" + +# 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 "Chainedbox L1 Pro")" != "" ]]; then + MYDTB_FILE="rockchip" + MYBOOT_VMLINUZ="Image" +elif [[ "$(echo ${MYDEVICE_NAME} | grep "BeikeYun")" != "" ]]; then + MYDTB_FILE="rockchip" + MYBOOT_VMLINUZ="Image" +elif [[ "$(echo ${MYDEVICE_NAME} | grep "V-Plus Cloud")" != "" ]]; then + MYDTB_FILE="allwinner" + MYBOOT_VMLINUZ="zImage" +elif [[ -f "/etc/flippy-openwrt-release" ]]; then + MYDTB_FILE="amlogic" + MYBOOT_VMLINUZ="zImage" +else + error_msg "Unknown device: [ ${MYDEVICE_NAME} ], Not supported." +fi + +# Find the partition where root is located +ROOT_PTNAME=$(df / | tail -n1 | awk '{print $1}' | awk -F '/' '{print $3}') +if [ "${ROOT_PTNAME}" == "" ]; then + error_msg "Cannot find the partition corresponding to the root file system!" +fi + +# 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 + +echo -e "Current device: ${MYDEVICE_NAME} [ ${MYDTB_FILE} ], Use in [ ${EMMC_NAME} ]" +sleep 3 + +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 && sync + +if [ $(ls ${P4_PATH}/*.tar.gz -l 2>/dev/null | grep "^-" | wc -l) -ge 3 ]; then + + if [ $(ls ${P4_PATH}/boot-*.tar.gz -l 2>/dev/null | grep "^-" | wc -l) -ge 1 ]; then + build_boot=$(ls ${P4_PATH}/boot-*.tar.gz | head -n 1) && build_boot=${build_boot##*/} + echo -e "Update using [ ${build_boot} ] files. Please wait a moment ..." + flippy_version=${build_boot/boot-/} && flippy_version=${flippy_version/.tar.gz/} + kernel_version=$(echo ${flippy_version} | grep -oE '^[1-9].[0-9]{1,3}.[0-9]+') + kernel_vermaj=$(echo ${kernel_version} | grep -oE '^[1-9].[0-9]{1,3}') + k510_ver=${kernel_vermaj%%.*} + k510_maj=${kernel_vermaj##*.} + if [ ${k510_ver} -eq "5" ]; then + if [ "${k510_maj}" -ge "10" ]; then + K510=1 + else + K510=0 + fi + elif [ ${k510_ver} -gt "5" ]; then + K510=1 + else + K510=0 + fi + else + error_msg "Have no boot-*.tar.gz file found in the ${P4_PATH} directory." + fi + + if [[ -f ${P4_PATH}/dtb-${MYDTB_FILE}-${flippy_version}.tar.gz ]]; then + build_dtb="dtb-${MYDTB_FILE}-${flippy_version}.tar.gz" + else + error_msg "Have no dtb-${MYDTB_FILE}-${flippy_version}.tar.gz file." + fi + + if [ -f ${P4_PATH}/modules-${flippy_version}.tar.gz ]; then + build_modules="modules-${flippy_version}.tar.gz" + else + error_msg "Have no modules-*.tar.gz file found in the ${P4_PATH} directory." + fi + + echo -e " \ + Try to using this files to update the kernel: \n \ + build_boot: ${build_boot} \n \ + build_dtb: ${build_dtb} \n \ + build_modules: ${build_modules} \n \ + flippy_version: ${flippy_version} \n \ + kernel_version: ${kernel_version} \n \ + K510: ${K510}" + +else + error_msg "After upload the kernel files in [ /mnt/${EMMC_NAME}${PARTITION_NAME}4/ ], run again." +fi + +MODULES_OLD=$(ls /lib/modules/ 2>/dev/null) +VERSION_OLD=$(echo ${MODULES_OLD} | grep -oE '^[1-9].[0-9]{1,3}' 2>/dev/null) +VERSION_ver=${VERSION_OLD%%.*} +VERSION_maj=${VERSION_OLD##*.} +if [ ${VERSION_ver} -eq "5" ]; then + if [ "${VERSION_maj}" -ge "10" ]; then + V510=1 + else + V510=0 + fi +elif [ ${VERSION_ver} -gt "5" ]; then + V510=1 +else + V510=0 +fi + +# Check version consistency from amlogic s9xxx +if [[ "${V510}" -lt "${K510}" && "${MYDTB_FILE}" == "amlogic" ]]; then + echo -e "Update to kernel 5.10 or higher and install U-BOOT." + if [ -f "/etc/flippy-openwrt-release" ]; then + # U-BOOT adaptation + source /etc/flippy-openwrt-release 2>/dev/null + UBOOT_OVERLOAD="${UBOOT_OVERLOAD}" + MAINLINE_UBOOT="${MAINLINE_UBOOT//\/lib\/u-boot\//}" + + # Check ${UBOOT_OVERLOAD} + if [[ -n "${UBOOT_OVERLOAD}" ]]; then + if [[ ! -f "/boot/${UBOOT_OVERLOAD}" ]]; then + error_msg "The [ ${UBOOT_OVERLOAD} ] file is missing, please complete it first." + else + echo -e "The ${UBOOT_OVERLOAD} file has been found." + fi + else + error_msg "The 5.10 kernel cannot be used without UBOOT_OVERLOAD." + fi + + # Check ${MAINLINE_UBOOT} + if [[ -n "${MAINLINE_UBOOT}" && "${AUTO_MAINLINE_UBOOT}" == "yes" ]]; then + if [[ ! -f "/lib/u-boot/${MAINLINE_UBOOT}" ]]; then + error_msg "The [ ${MAINLINE_UBOOT} ] file is missing, please complete it first." + fi + fi + else + error_msg "The /etc/flippy-openwrt-release file is missing and cannot be update." + fi + + # Copy u-boot.ext and u-boot.emmc + if [ -f "/boot/${UBOOT_OVERLOAD}" ]; then + cp -f "/boot/${UBOOT_OVERLOAD}" /boot/u-boot.ext && sync && chmod +x /boot/u-boot.ext + cp -f "/boot/${UBOOT_OVERLOAD}" /boot/u-boot.emmc && sync && chmod +x /boot/u-boot.emmc + echo -e "The ${UBOOT_OVERLOAD} file copy is complete." + else + error_msg "The UBOOT_OVERLOAD file is missing and cannot be update." + fi + + # Write Mainline bootloader + if [[ -f "/lib/u-boot/${MAINLINE_UBOOT}" && "${AUTO_MAINLINE_UBOOT}" == "yes" ]]; then + echo -e "Write Mainline bootloader: [ ${MAINLINE_UBOOT} ] to [ /dev/${EMMC_NAME} ]" + dd if=/lib/u-boot/${MAINLINE_UBOOT} of=/dev/${EMMC_NAME} bs=1 count=442 conv=fsync + dd if=/lib/u-boot/${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 + +echo -e "Unpack [ ${flippy_version} ] related files ..." + +# 01. for /boot five files +rm -f /boot/config-* /boot/initrd.img-* /boot/System.map-* /boot/uInitrd-* /boot/vmlinuz-* 2>/dev/null && sync +rm -f /boot/uInitrd /boot/zImage /boot/Image 2>/dev/null && sync +tar -xzf ${P4_PATH}/${build_boot} -C /boot && sync + +if [[ -f "/boot/uInitrd-${flippy_version}" ]]; then + i=1 + max_try=10 + while [ "${i}" -le "${max_try}" ]; do + cp -f /boot/uInitrd-${flippy_version} /boot/uInitrd 2>/dev/null && sync + uInitrd_original=$(md5sum /boot/uInitrd-${flippy_version} | awk '{print $1}') + uInitrd_new=$(md5sum /boot/uInitrd | awk '{print $1}') + if [[ "${uInitrd_original}" == "${uInitrd_new}" ]]; then + echo -e "Unpack [ /boot/uInitrd ] complete." + break + else + rm -f /boot/uInitrd && sync + let i++ + continue + fi + done + [ "${i}" -eq "10" ] && error_msg "/boot/uInitrd-${flippy_version} file copy failed." +else + error_msg "/boot/uInitrd-${flippy_version} file is missing." +fi + +if [[ -f "/boot/vmlinuz-${flippy_version}" ]]; then + i=1 + max_try=10 + while [ "${i}" -le "${max_try}" ]; do + cp -f /boot/vmlinuz-${flippy_version} /boot/${MYBOOT_VMLINUZ} 2>/dev/null && sync + vmlinuz_original=$(md5sum /boot/vmlinuz-${flippy_version} | awk '{print $1}') + vmlinuz_new=$(md5sum /boot/${MYBOOT_VMLINUZ} | awk '{print $1}') + if [[ "${vmlinuz_original}" == "${vmlinuz_new}" ]]; then + echo -e "Unpack [ /boot/${MYBOOT_VMLINUZ} ] complete." + break + else + rm -f /boot/${MYBOOT_VMLINUZ} && sync + let i++ + continue + fi + done + [ "${i}" -eq "10" ] && error_msg "/boot/vmlinuz-${flippy_version} file copy failed." +else + error_msg "/boot/vmlinuz-${flippy_version} file is missing." +fi + +[ -f "/boot/config-${flippy_version}" ] || error_msg "/boot/config-${flippy_version} file is missing." +[ -f "/boot/System.map-${flippy_version}" ] || error_msg "/boot/System.map-${flippy_version} file is missing." + +echo -e "01. Unpack [ ${build_boot} ] complete." +sleep 3 + +# 02 for /boot/dtb/${MYDTB_FILE}/* +[ -d /boot/dtb/${MYDTB_FILE} ] || mkdir -p /boot/dtb/${MYDTB_FILE} +if [[ "${MYDTB_FILE}" == "rockchip" ]]; then + mkdir -p /boot/dtb-${flippy_version}/${MYDTB_FILE} + ln -sf /boot/dtb-${flippy_version} /boot/dtb +fi +tar -xzf ${P4_PATH}/${build_dtb} -C /boot/dtb/${MYDTB_FILE} && sync +[ "$(ls /boot/dtb/${MYDTB_FILE} -l 2>/dev/null | grep "^-" | wc -l)" -ge "1" ] || error_msg "/boot/dtb/${MYDTB_FILE} file is missing." +echo -e "02. Unpack [ ${build_dtb} ] complete." +sleep 3 + +# 03 for /lib/modules/* +rm -rf /lib/modules/* 2>/dev/null && sync +tar -xzf ${P4_PATH}/${build_modules} -C /lib/modules && sync +cd /lib/modules/${flippy_version}/ +rm -f *.ko 2>/dev/null +find ./ -type f -name '*.ko' -exec ln -s {} ./ \; +sync && sleep 3 +x=$(ls *.ko -l 2>/dev/null | grep "^l" | wc -l) +if [ "${x}" -eq "0" ]; then + error_msg "Error *.ko Files not found." +fi +echo -e "03. Unpack [ ${build_modules} ] complete." +sleep 3 + +rm -rf ${P4_PATH}/dtb-*.tar.gz ${P4_PATH}/boot-*.tar.gz ${P4_PATH}/modules-*.tar.gz 2>/dev/null +sync + +sed -i '/KERNEL_VERSION/d' /etc/flippy-openwrt-release 2>/dev/null +echo "KERNEL_VERSION='${kernel_version}'" >>/etc/flippy-openwrt-release 2>/dev/null + +sed -i '/K510/d' /etc/flippy-openwrt-release 2>/dev/null +echo "K510='${K510}'" >>/etc/flippy-openwrt-release 2>/dev/null + +sed -i "s/ Kernel.*/ Kernel: ${flippy_version}/g" /etc/banner 2>/dev/null + +sync +wait + +echo "Successfully updated, automatic restarting..." +sleep 3 +reboot +exit 0 diff --git a/luci-app-amlogic/root/usr/sbin/openwrt-update-allwinner b/luci-app-amlogic/root/usr/sbin/openwrt-update-allwinner new file mode 100755 index 000000000..7c2a34b0d --- /dev/null +++ b/luci-app-amlogic/root/usr/sbin/openwrt-update-allwinner @@ -0,0 +1,587 @@ +#!/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 + +# 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 + CURRENT_FDTFILE=$(basename $FDT) +fi +if [ -n "$CURRENT_FDTFILE" ];then + MYDTB_FDTFILE="$CURRENT_FDTFILE" +else + MYDTB_FDTFILE="sun50i-h6-vplus-cloud.dtb" +fi +# Current device model +MYDEVICE_NAME=$(cat /proc/device-tree/model | tr -d '\000') +if [[ -z "${MYDEVICE_NAME}" ]]; then + echo "The device name is empty and cannot be recognized." + exit 1 +elif [[ "$(echo ${MYDEVICE_NAME} | grep "V-Plus Cloud")" == "" ]]; then + echo "[ ${MYDEVICE_NAME} ] is not [ V-Plus Cloud ] device, please select the correct script." + exit 1 +else + echo -e "Current device: ${MYDEVICE_NAME} [ vplus ]" + sleep 3 +fi + +# Find the partition where root is located +ROOT_PTNAME=$(df / | tail -n1 | awk '{print $1}' | awk -F '/' '{print $3}') +if [ "${ROOT_PTNAME}" == "" ]; then + echo "Cannot find the partition corresponding to the root file system!" + exit 1 +fi + +# 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="" + ;; +*) + echo "Unable to recognize the disk type of ${ROOT_PTNAME}!" + exit 1 + ;; +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 + echo "No update file found." + exit 1 +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 + echo "The boot partition is not exists or not mounted, so it cannot be upgraded with this script!" + exit 1 +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=$(lsblk -l -o NAME,PATH,TYPE,UUID,MOUNTPOINT | awk '$3~/^part$/ && $5 ~ /^\/$/ {print $0}') +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" + ;; +*) + echo "The root partition location is invalid, so it cannot be upgraded with this script!" + exit 1 + ;; +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 + echo "The new root partition is not exists, so it cannot be upgraded with this script!" + exit 1 +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 + echo "loop device not found!" + exit 1 + fi +else + echo "losetup $IMG_FILE failed!" + exit 1 +fi +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 + 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 ... " +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 <./etc/config/fstab </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 </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" </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 </dev/null +losetup -D 2>/dev/null +rmdir ${P1} ${P2} 2>/dev/null +rm -f ${IMG_NAME} 2>/dev/null +sync + +echo "Successfully updated, automatic restarting..." +sleep 3 +reboot +exit 0 diff --git a/luci-app-amlogic/root/usr/sbin/openwrt-update-amlogic b/luci-app-amlogic/root/usr/sbin/openwrt-update-amlogic new file mode 100755 index 000000000..7a950d71a --- /dev/null +++ b/luci-app-amlogic/root/usr/sbin/openwrt-update-amlogic @@ -0,0 +1,837 @@ +#!/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 + +# 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 + echo "The device name is empty and cannot be recognized." + exit 1 +elif [[ ! -f "/etc/flippy-openwrt-release" ]]; then + echo "The [ /etc/flippy-openwrt-release ] file is missing." + exit 1 +else + echo -e "Current device: ${MYDEVICE_NAME} [ amlogic ]" + sleep 3 +fi + +# Find the partition where root is located +ROOT_PTNAME=$(df / | tail -n1 | awk '{print $1}' | awk -F '/' '{print $3}') +if [ "${ROOT_PTNAME}" == "" ]; then + echo "Cannot find the partition corresponding to the root file system!" + exit 1 +fi + +# 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}_" + ;; +*) + echo "Unable to recognize the disk type of ${ROOT_PTNAME}!" + exit 1 + ;; +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 + echo "No update file found." + exit 1 +else + echo "Start update from [ ${IMG_NAME} ]" +fi + +# Check the necessary dependencies +DEPENDS="lsblk uuidgen grep awk btrfs mkfs.fat mkfs.btrfs perl md5sum fatlabel" +echo "Check the necessary dependencies..." +for dep in ${DEPENDS}; do + WITCH=$(which ${dep}) + if [ "${WITCH}" == "" ]; then + echo "Dependent command: ${dep} does not exist, upgrade cannot be performed, only flash through U disk/TF card!" + exit 1 + 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 + echo "Boot The partition does not exist, so the update cannot be continued!" + exit 1 +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=$(lsblk -l -o NAME,PATH,TYPE,UUID,MOUNTPOINT | awk '$3~/^part$/ && $5 ~ /^\/$/ {print $0}') +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" + ;; +*) + echo "ROOTFS The partition location is incorrect, so the update cannot continue!" + exit 1 + ;; +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 + echo "The new ROOTFS partition does not exist, so the update cannot continue!" + exit 1 +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 + echo "loop device not found!" + exit 1 + fi +else + echo "losetup [ $IMG_FILE ] failed!" + exit 1 +fi + +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 + +MODULES_OLD=$(ls /lib/modules/ 2>/dev/null) +VERSION_OLD=$(echo ${MODULES_OLD} | grep -oE '^[1-9].[0-9]{1,3}' 2>/dev/null) +MODULES_NOW=$(ls ${P2}/lib/modules/ 2>/dev/null) +VERSION_NOW=$(echo ${MODULES_NOW} | grep -oE '^[1-9].[0-9]{1,3}' 2>/dev/null) +echo -e "Update from [ ${MODULES_OLD} ] to [ ${MODULES_NOW} ]" + +k510_ver=${VERSION_NOW%%.*} +k510_maj=${VERSION_NOW##*.} +if [ "${k510_ver}" -eq "5" ]; then + if [ "${k510_maj}" -ge "10" ]; then + K510="1" + else + K510="0" + fi +elif [ "${k510_ver}" -gt "5" ]; then + K510="1" +else + K510="0" +fi + +# 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} + + # With assigned parameters + #K510=${K510} +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} || \ + ( echo "rm partion ${target_pt_idx} failed" ; exit 1) + parted /dev/${target_dev_name} mkpart primary btrfs "${safe_pt_begin_byte}b" "${cur_pt_end_byte}b" || \ + ( echo "create new partion ${target_pt_idx} failed" ; exit 1) + 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 + echo "failed." + exit 1 + 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 <./etc/fstab <./etc/config/fstab </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 </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" </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 < .snapshots/etc-001" +btrfs subvolume snapshot -r etc .snapshots/etc-001 + +cd ${WORK_DIR} + +#echo -n "umount /boot ... " +#umount -f /boot +#if [ $? -ne 0 ];then +# echo "failed! " +# umount ${P1} +# umount ${P2} +# losetup -D +# exit 1 +#else +# echo "ok" +#fi +# +#echo "reformat ${BOOT_PATH} ..." +#if mkfs.fat -n "${LB_PRE}BOOT" -F 32 ${BOOT_PATH} 2>/dev/null;then +# echo -n "mount /boot ..." +# mount -t vfat -o "errors=remount-ro" ${BOOT_PATH} /boot +# if [ $? -eq 0 ];then +# echo "ok" +# else +# echo "mount failed! The system has been destroyed and must be refreshed!" +# exit 1 +# fi +#else +# echo "format failed! The system has been destroyed and must be refreshed!" +# exit 1 +#fi +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" ] && echo "uInitrd file copy failed." && exit 1 +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" ] && echo "zImage file copy failed." && exit 1 +else + echo "zImage file is missing." + exit 1 +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 +fi + +sync + +echo "Update boot parameters ... " +if [ -f /tmp/uEnv.txt ]; then + lines=$(wc -l uEnv.txt + cat >>uEnv.txt <uEnv.txt </dev/null +losetup -D 2>/dev/null +rm -rf ${P1} ${P2} 2>/dev/null +rm -f ${IMG_NAME} 2>/dev/null +sync +wait + +echo "Successfully updated, automatic restarting..." +sleep 3 +reboot +exit 0 diff --git a/luci-app-amlogic/root/usr/sbin/openwrt-update-rockchip b/luci-app-amlogic/root/usr/sbin/openwrt-update-rockchip new file mode 100755 index 000000000..de730528e --- /dev/null +++ b/luci-app-amlogic/root/usr/sbin/openwrt-update-rockchip @@ -0,0 +1,582 @@ +#!/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 + +# 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') +if [[ -z "${MYDEVICE_NAME}" ]]; then + echo "The device name is empty and cannot be recognized." + exit 1 +elif [[ "$(echo ${MYDEVICE_NAME} | grep "Chainedbox L1 Pro")" != "" ]]; then + if [ -n "$CURRENT_FDTFILE" ];then + MYDTB_FDTFILE="$CURRENT_FDTFILE" + else + MYDTB_FDTFILE="rk3328-l1pro-1296mhz.dtb" + fi + SOC="l1pro" +elif [[ "$(echo ${MYDEVICE_NAME} | grep "BeikeYun")" != "" ]]; then + if [ -n "$CURRENT_FDTFILE" ];then + MYDTB_FDTFILE="$CURRENT_FDTFILE" + else + MYDTB_FDTFILE="rk3328-beikeyun-1296mhz.dtb" + fi + SOC="beikeyun" +else + echo "Unknown device: [ ${MYDEVICE_NAME} ], Not supported." + exit 1 +fi +echo -e "Current device: ${MYDEVICE_NAME} [ ${SOC} ]" +sleep 3 + +# Find the partition where root is located +ROOT_PTNAME=$(df / | tail -n1 | awk '{print $1}' | awk -F '/' '{print $3}') +if [ "${ROOT_PTNAME}" == "" ]; then + echo "Cannot find the partition corresponding to the root file system!" + exit 1 +fi + +# 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="" + ;; +*) + echo "Unable to recognize the disk type of ${ROOT_PTNAME}!" + exit 1 + ;; +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 + echo "No update file found." + exit 1 +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 + echo "The boot partition is not exists or not mounted, so it cannot be upgraded with this script!" + exit 1 +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=$(lsblk -l -o NAME,PATH,TYPE,UUID,MOUNTPOINT | awk '$3~/^part$/ && $5 ~ /^\/$/ {print $0}') +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" + ;; +*) + echo "The root partition location is invalid, so it cannot be upgraded with this script!" + exit 1 + ;; +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 + echo "The new root partition is not exists, so it cannot be upgraded with this script!" + exit 1 +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 + echo "loop device not found!" + exit 1 + fi +else + echo "losetup $IMG_FILE failed!" + exit 1 +fi +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 <./etc/config/fstab </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 </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" </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 "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 >armbianEnv.txt </dev/null +losetup -D 2>/dev/null +rmdir ${P1} ${P2} 2>/dev/null +rm -f ${IMG_NAME} 2>/dev/null +sync + +echo "Successfully updated, automatic restarting..." +sleep 3 +reboot +exit 0 diff --git a/luci-app-amlogic/root/usr/share/amlogic/amlogic_check_firmware.sh b/luci-app-amlogic/root/usr/share/amlogic/amlogic_check_firmware.sh new file mode 100755 index 000000000..1b6a0c81b --- /dev/null +++ b/luci-app-amlogic/root/usr/share/amlogic/amlogic_check_firmware.sh @@ -0,0 +1,233 @@ +#!/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" +github_api_openwrt="${TMP_CHECK_DIR}/github_api_openwrt" +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 +} + +# 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=$(df / | tail -n1 | awk '{print $1}' | awk -F '/' '{print $3}') +if [ "${ROOT_PTNAME}" == "" ]; then + tolog "Cannot find the partition corresponding to the root file system!" "1" +fi + +# 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="" + ;; +*) + 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" + +# Current device model +MYDEVICE_NAME=$(cat /proc/device-tree/model | tr -d '\000') +if [[ -z "${MYDEVICE_NAME}" ]]; then + tolog "The device name is empty and cannot be recognized." "1" +elif [[ "$(echo ${MYDEVICE_NAME} | grep "Chainedbox L1 Pro")" != "" ]]; then + MYDTB_FILE="rockchip" + SOC="l1pro" +elif [[ "$(echo ${MYDEVICE_NAME} | grep "BeikeYun")" != "" ]]; then + MYDTB_FILE="rockchip" + SOC="beikeyun" +elif [[ "$(echo ${MYDEVICE_NAME} | grep "V-Plus Cloud")" != "" ]]; then + MYDTB_FILE="allwinner" + SOC="vplus" +elif [[ -f "${AMLOGIC_SOC_FILE}" ]]; then + MYDTB_FILE="amlogic" + source ${AMLOGIC_SOC_FILE} 2>/dev/null + SOC="${SOC}" +else + tolog "Unknown device: [ ${MYDEVICE_NAME} ], Not supported." "1" +fi +[[ ! -z "${SOC}" ]] || tolog "The custom firmware soc is invalid." "1" +tolog "Device: ${MYDEVICE_NAME} [ ${SOC} ], 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=$(ls /lib/modules/ 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_ver=$(echo "${current_kernel_v}" | cut -d '.' -f1) +main_line_maj=$(echo "${current_kernel_v}" | cut -d '.' -f2) +main_line_version="${main_line_ver}.${main_line_maj}" + +# 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" + +# Supported format: +# server_firmware_url="https://github.com/ophub/amlogic-s9xxx-openwrt" +# server_firmware_url="ophub/amlogic-s9xxx-openwrt" +if [[ ${server_firmware_url} == http* ]]; then + server_firmware_url=${server_firmware_url#*com\/} +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 + +firmware_download_url="https:.*${releases_tag_keywords}.*${SOC}.*${main_line_version}.*${firmware_suffix}" + +# 02. Check Updated +check_updated() { + tolog "02. Start checking the updated ..." + curl -s "https://api.github.com/repos/${server_firmware_url}/releases" >${github_api_openwrt} && sync + sleep 1 + + # Get the openwrt firmware updated_at + api_down_line_array=$(cat ${github_api_openwrt} | grep -n "${firmware_download_url}" | awk -F ":" '{print $1}' | tr "\n" " " | echo $(xargs)) + # return: 123 233 312 + + i=1 + api_updated_at=() + api_updated_merge=() + for x in ${api_down_line_array}; do + api_updated_at[${i}]="$(cat ${github_api_openwrt} | sed -n "$((x - 1))p" | cut -d '"' -f4)" + api_updated_merge[${i}]="${x}@$(cat ${github_api_openwrt} | sed -n "$((x - 1))p" | cut -d '"' -f4)" + let i++ + done + # return: api_updated_at: 2021-10-21T17:52:56Z 2021-10-21T11:22:39Z 2021-10-22T17:52:56Z + latest_updated_at=$(echo ${api_updated_at[*]} | tr ' ' '\n' | sort -r | head -n 1) + latest_updated_at_format=$(echo ${latest_updated_at} | tr 'T' '(' | tr 'Z' ')') + # return: latest_updated_at: 2021-10-22T17:52:56Z + api_op_down_line=$(echo ${api_updated_merge[*]} | tr ' ' '\n' | grep ${latest_updated_at} | cut -d '@' -f1) + # return: api_openwrt_download_line: 123 + + # Check the firmware update code + op_release_code="${FIRMWARE_DOWNLOAD_PATH}/.luci-app-amlogic/op_release_code" + if [ -f "${op_release_code}" ]; then + update_check_code="$(cat ${op_release_code} | xargs)" + if [[ -n "${update_check_code}" && "${update_check_code}" == "${latest_updated_at}" ]]; then + tolog "02.01 Already the latest version, no need to update." "1" + fi + fi + + # Prompt to update + if [[ -n "${api_op_down_line}" && -n "$(echo ${api_op_down_line} | sed -n "/^[0-9]\+$/p")" ]]; then + tolog ' Latest updated: '${latest_updated_at_format}'' "1" + else + tolog "02.02 Invalid firmware check." "1" + fi + + exit 0 +} + +# 03. Download Openwrt firmware +download_firmware() { + tolog "03. Download Openwrt firmware ..." + + # Get the openwrt firmware download path + if [[ ${download_version} == download* ]]; then + download_firmware_line=$(echo "${download_version}" | cut -d '_' -f2) + download_latest_updated=$(echo "${download_version}" | cut -d '_' -f3) + tolog "03.01 Start downloading..." + else + tolog "03.02 Invalid parameter" "1" + fi + + firmware_releases_path=$(cat ${github_api_openwrt} | sed -n "${download_firmware_line}p" | grep "browser_download_url" | grep -o "${firmware_download_url}" | head -n 1) + firmware_download_name="openwrt_${SOC}_k${main_line_version}_github${firmware_suffix}" + wget -c "${firmware_releases_path}" -O "${FIRMWARE_DOWNLOAD_PATH}/${firmware_download_name}" >/dev/null 2>&1 && sync + if [[ "$?" -eq "0" && -s "${FIRMWARE_DOWNLOAD_PATH}/${firmware_download_name}" ]]; then + tolog "03.01 OpenWrt firmware download complete, you can update." + else + tolog "03.02 Invalid firmware download." "1" + fi + sleep 2 + + # Delete temporary files + rm -f ${github_api_openwrt} 2>/dev/null && sync + + #echo 'Update' >$START_LOG + tolog '' "1" + + exit 0 +} + +getopts 'cd' opts +case $opts in +c | check) + check_updated + ;; +* | download) + download_firmware + ;; +esac diff --git a/luci-app-amlogic/root/usr/share/amlogic/amlogic_check_kernel.sh b/luci-app-amlogic/root/usr/share/amlogic/amlogic_check_kernel.sh new file mode 100755 index 000000000..2726a17c9 --- /dev/null +++ b/luci-app-amlogic/root/usr/share/amlogic/amlogic_check_kernel.sh @@ -0,0 +1,280 @@ +#!/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" +github_api_kernel_library="${TMP_CHECK_DIR}/github_api_kernel_library" +github_api_kernel_file="${TMP_CHECK_DIR}/github_api_kernel_file" +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 +} + +# 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=$(df / | tail -n1 | awk '{print $1}' | awk -F '/' '{print $3}') +if [ "${ROOT_PTNAME}" == "" ]; then + tolog "Cannot find the partition corresponding to the root file system!" "1" +fi + +# 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="" + ;; +*) + 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" + +# Current device model +MYDEVICE_NAME=$(cat /proc/device-tree/model | tr -d '\000') +if [[ -z "${MYDEVICE_NAME}" ]]; then + tolog "Unknown device" "1" +elif [[ "$(echo ${MYDEVICE_NAME} | grep "Chainedbox L1 Pro")" != "" ]]; then + MYDTB_FILE="rockchip" +elif [[ "$(echo ${MYDEVICE_NAME} | grep "BeikeYun")" != "" ]]; then + MYDTB_FILE="rockchip" +elif [[ "$(echo ${MYDEVICE_NAME} | grep "V-Plus Cloud")" != "" ]]; then + MYDTB_FILE="allwinner" +elif [[ -f "${AMLOGIC_SOC_FILE}" ]]; then + MYDTB_FILE="amlogic" +else + tolog "Unknown device: [ ${MYDEVICE_NAME} ], Not supported." "1" +fi +tolog "Device: ${MYDEVICE_NAME} [ ${MYDTB_FILE} ], Use in [ ${EMMC_NAME} ]" +sleep 2 + +# Step 1: URL formatting start ----------------------------------------------------------- +# +# 01. Download server version documentation +tolog "01. Start checking the kernel version." +server_firmware_url=$(uci get amlogic.config.amlogic_firmware_repo 2>/dev/null) +[[ ! -z "${server_firmware_url}" ]] || tolog "01.01 The custom kernel download repo is invalid." "1" +server_kernel_path=$(uci get amlogic.config.amlogic_kernel_path 2>/dev/null) +[[ ! -z "${server_kernel_path}" ]] || tolog "01.02 The custom kernel download path is invalid." "1" +# +# Supported format: +# +# server_firmware_url="https://github.com/ophub/amlogic-s9xxx-openwrt" +# server_firmware_url="ophub/amlogic-s9xxx-openwrt" +# +# server_kernel_path="https://github.com/ophub/amlogic-s9xxx-openwrt/tree/main/amlogic-s9xxx/amlogic-kernel" +# server_kernel_path="https://github.com/ophub/amlogic-s9xxx-openwrt/trunk/amlogic-s9xxx/amlogic-kernel" +# server_kernel_path="amlogic-s9xxx/amlogic-kernel" +# +if [[ ${server_firmware_url} == http* ]]; then + server_firmware_url=${server_firmware_url#*com\/} +fi + +if [[ ${server_kernel_path} == http* && $(echo ${server_kernel_path} | grep "tree") != "" ]]; then + # Left part + server_kernel_path_left=${server_kernel_path%\/tree*} + server_kernel_path_left=${server_kernel_path_left#*com\/} + server_firmware_url=${server_kernel_path_left} + # Right part + server_kernel_path_right=${server_kernel_path#*tree\/} + server_kernel_path_right=${server_kernel_path_right#*\/} + server_kernel_path=${server_kernel_path_right} +elif [[ ${server_kernel_path} == http* && $(echo ${server_kernel_path} | grep "trunk") != "" ]]; then + # Left part + server_kernel_path_left=${server_kernel_path%\/trunk*} + server_kernel_path_left=${server_kernel_path_left#*com\/} + server_firmware_url=${server_kernel_path_left} + # Right part + server_kernel_path_right=${server_kernel_path#*trunk\/} + server_kernel_path=${server_kernel_path_right} +fi + +server_kernel_url="https://api.github.com/repos/${server_firmware_url}/contents/${server_kernel_path}" +# +# Step 1: URL formatting end ----------------------------------------------------------- + +# 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 Query the current version + current_kernel_v=$(ls /lib/modules/ 2>/dev/null | grep -oE '^[1-9].[0-9]{1,2}.[0-9]+') + tolog "02.01 current version: ${current_kernel_v}" + sleep 2 + + # 02.02 Version comparison + main_line_ver=$(echo "${current_kernel_v}" | cut -d '.' -f1) + main_line_maj=$(echo "${current_kernel_v}" | cut -d '.' -f2) + main_line_now=$(echo "${current_kernel_v}" | cut -d '.' -f3) + main_line_version="${main_line_ver}.${main_line_maj}" + + # 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 + branch_ver=$(echo "${server_kernel_branch}" | cut -d '.' -f1) + branch_maj=$(echo "${server_kernel_branch}" | cut -d '.' -f2) + 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 + curl -s "${server_kernel_url}" >${github_api_kernel_library} && sync + sleep 1 + + latest_version=$(cat ${github_api_kernel_library} | grep "name" | grep -oE "${main_line_version}.[0-9]+" | sed -e "s/${main_line_version}.//g" | sort -n | sed -n '$p') + #latest_version="124" + [[ ! -z "${latest_version}" ]] || tolog "02.03 Failed to get the version on the server." "1" + tolog "02.03 current version: ${current_kernel_v}, Latest version: ${main_line_version}.${latest_version}" + sleep 2 + + if [[ "${latest_version}" -eq "${main_line_now}" && "${main_line_maj}" -eq "${branch_maj}" ]]; then + tolog "02.04 Already the latest version, no need to update." "1" + sleep 2 + else + tolog ' Latest version: '${main_line_version}.${latest_version}'' "1" + fi + + exit 0 +} + +# Step 3: Download the latest kernel version +download_kernel() { + tolog "03. Start download the kernels." + if [[ ${download_version} == download* ]]; then + download_version=$(echo "${download_version}" | cut -d '_' -f2) + tolog "03.01 The kernel version: ${download_version}, downloading..." + else + tolog "03.02 Invalid parameter" "1" + fi + + # Delete other residual kernel files + rm -f ${KERNEL_DOWNLOAD_PATH}/boot-*.tar.gz 2>/dev/null && sync + rm -f ${KERNEL_DOWNLOAD_PATH}/dtb-*.tar.gz 2>/dev/null && sync + rm -f ${KERNEL_DOWNLOAD_PATH}/modules-*.tar.gz 2>/dev/null && sync + + curl -s "${server_kernel_url}/${download_version}" >${github_api_kernel_file} && sync + sleep 1 + + # Download boot file from the kernel directory under the path: ${server_kernel_url}/${download_version}/ + server_kernel_boot="$(cat ${github_api_kernel_file} | grep "download_url" | grep -o "https.*/boot-${download_version}.*.tar.gz" | head -n 1)" + # Download boot file from current path: ${server_kernel_url}/ + if [ -z "${server_kernel_boot}" ]; then + server_kernel_boot="$(cat ${github_api_kernel_library} | grep "download_url" | grep -o "https.*/boot-${download_version}.*.tar.gz" | head -n 1)" + fi + boot_file_name="${server_kernel_boot##*/}" + server_kernel_boot_name="${boot_file_name//%2B/+}" + wget -c "${server_kernel_boot}" -O "${KERNEL_DOWNLOAD_PATH}/${server_kernel_boot_name}" >/dev/null 2>&1 && sync + if [[ "$?" -eq "0" && -s "${KERNEL_DOWNLOAD_PATH}/${server_kernel_boot_name}" ]]; then + tolog "03.03 The boot file complete." + else + tolog "03.04 The boot file failed to download." "1" + fi + sleep 2 + + # Download dtb file from the kernel directory under the path: ${server_kernel_url}/${download_version}/ + server_kernel_dtb="$(cat ${github_api_kernel_file} | grep "download_url" | grep -o "https.*/dtb-${MYDTB_FILE}-${download_version}.*.tar.gz" | head -n 1)" + # Download dtb file from current path: ${server_kernel_url}/ + if [ -z "${server_kernel_dtb}" ]; then + server_kernel_dtb="$(cat ${github_api_kernel_library} | grep "download_url" | grep -o "https.*/dtb-${MYDTB_FILE}-${download_version}.*.tar.gz" | head -n 1)" + fi + dtb_file_name="${server_kernel_dtb##*/}" + server_kernel_dtb_name="${dtb_file_name//%2B/+}" + wget -c "${server_kernel_dtb}" -O "${KERNEL_DOWNLOAD_PATH}/${server_kernel_dtb_name}" >/dev/null 2>&1 && sync + if [[ "$?" -eq "0" && -s "${KERNEL_DOWNLOAD_PATH}/${server_kernel_dtb_name}" ]]; then + tolog "03.05 The dtb file complete." + else + tolog "03.06 The dtb file failed to download." "1" + fi + sleep 2 + + # Download modules file from the kernel directory under the path: ${server_kernel_url}/${download_version}/ + server_kernel_modules="$(cat ${github_api_kernel_file} | grep "download_url" | grep -o "https.*/modules-${download_version}.*.tar.gz" | head -n 1)" + # Download modules file from current path: ${server_kernel_url}/ + if [ -z "${server_kernel_modules}" ]; then + server_kernel_modules="$(cat ${github_api_kernel_library} | grep "download_url" | grep -o "https.*/modules-${download_version}.*.tar.gz" | head -n 1)" + fi + modules_file_name="${server_kernel_modules##*/}" + server_kernel_modules_name="${modules_file_name//%2B/+}" + wget -c "${server_kernel_modules}" -O "${KERNEL_DOWNLOAD_PATH}/${server_kernel_modules_name}" >/dev/null 2>&1 && sync + if [[ "$?" -eq "0" && -s "${KERNEL_DOWNLOAD_PATH}/${server_kernel_modules_name}" ]]; then + tolog "03.07 The modules file complete." + else + tolog "03.08 The modules file failed to download." "1" + fi + sleep 2 + + tolog "04 The kernel is ready, you can update." + sleep 2 + + # Delete temporary files + rm -f ${github_api_kernel_library} 2>/dev/null && sync + rm -f ${github_api_kernel_file} 2>/dev/null && sync + + #echo 'Update' >$START_LOG + tolog '' "1" + + exit 0 +} + +getopts 'cd' opts +case $opts in +c | check) + check_kernel + ;; +* | download) + download_kernel + ;; +esac diff --git a/luci-app-amlogic/root/usr/share/amlogic/amlogic_check_plugin.sh b/luci-app-amlogic/root/usr/share/amlogic/amlogic_check_plugin.sh new file mode 100755 index 000000000..fa5e07e64 --- /dev/null +++ b/luci-app-amlogic/root/usr/share/amlogic/amlogic_check_plugin.sh @@ -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" +github_api_plugin="${TMP_CHECK_DIR}/github_api_plugin" +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 + +# 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 + +# Find the partition where root is located +ROOT_PTNAME=$(df / | tail -n1 | awk '{print $1}' | awk -F '/' '{print $3}') +if [ "${ROOT_PTNAME}" == "" ]; then + tolog "Cannot find the partition corresponding to the root file system!" "1" +fi + +# 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="" + ;; +*) + tolog "Unable to recognize the disk type of ${ROOT_PTNAME}!" "1" + ;; +esac + +# Current device model +MYDEVICE_NAME=$(cat /proc/device-tree/model | tr -d '\000') +if [[ -z "${MYDEVICE_NAME}" ]]; then + tolog "Unknown device" "1" +#elif [ "${MYDEVICE_NAME}" == "Phicomm N1" ]; then +# tolog "Test current device: ${MYDEVICE_NAME}" "1" +elif [[ "$(echo ${MYDEVICE_NAME} | grep "Chainedbox L1 Pro")" != "" ]]; then + MYDTB_FILE="rockchip" + SOC="l1pro" +elif [[ "$(echo ${MYDEVICE_NAME} | grep "BeikeYun")" != "" ]]; then + MYDTB_FILE="rockchip" + SOC="beikeyun" +elif [[ "$(echo ${MYDEVICE_NAME} | grep "V-Plus Cloud")" != "" ]]; then + MYDTB_FILE="allwinner" + SOC="vplus" +elif [[ -f "${AMLOGIC_SOC_FILE}" ]]; then + MYDTB_FILE="amlogic" + source ${AMLOGIC_SOC_FILE} 2>/dev/null + SOC="${SOC}" +else + tolog "Unknown device: [ ${MYDEVICE_NAME} ], Not supported." "1" +fi +[[ ! -z "${SOC}" ]] || tolog "The custom firmware soc is invalid." "1" +tolog "Device: ${MYDEVICE_NAME} [ ${SOC} ], Use in [ ${EMMC_NAME} ]" +sleep 2 + +# 01. Query local version information +tolog "01. Query current version information." +current_plugin_v="$(opkg list-installed | grep 'luci-app-amlogic' | awk '{print $3}')" +tolog "01.01 current version: ${current_plugin_v}" +sleep 2 + +# 02. Check the version on the server +tolog "02. Query server version information." + +curl -s "https://api.github.com/repos/ophub/luci-app-amlogic/releases" >${github_api_plugin} && sync +sleep 1 + +server_plugin_version=$(cat ${github_api_plugin} | grep "tag_name" | awk -F '"' '{print $4}' | tr " " "\n" | sort -rV | head -n 1) +[ -n "${server_plugin_version}" ] || tolog "02.01 Failed to get the version on the server." "1" +tolog "02.01 current version: ${current_plugin_v}, Latest version: ${server_plugin_version}" +sleep 2 + +if [[ "${current_plugin_v}" == "${server_plugin_version}" ]]; then + tolog "02.02 Already the latest version, no need to update." "1" +else + tolog "02.03 Check the latest plug-in download address." + + server_plugin_url="https://github.com/ophub/luci-app-amlogic/releases/download" + server_plugin_file_ipk="$(cat ${github_api_plugin} | grep -E "browser_.*${server_plugin_version}.*" | grep -oE "luci-app-amlogic_.*.ipk" | head -n 1)" + server_plugin_file_i18n="$(cat ${github_api_plugin} | grep -E "browser_.*${server_plugin_version}.*" | grep -oE "luci-i18n-amlogic-zh-cn_.*.ipk" | head -n 1)" + server_plugin_file_libfs="$(cat ${github_api_plugin} | grep -E "browser_.*${server_plugin_version}.*" | grep -oE "luci-lib-fs_.*.ipk" | head -n 1)" + + if [[ -n "${server_plugin_file_ipk}" && -n "${server_plugin_file_i18n}" && -n "${server_plugin_file_libfs}" ]]; then + tolog "02.04 Start downloading the latest plugin..." + else + tolog "02.04 No available plugins found!" "1" + fi + + # Download plugin ipk file + wget -c "${server_plugin_url}/${server_plugin_version}/${server_plugin_file_ipk}" -O "${TMP_CHECK_DIR}/${server_plugin_file_ipk}" >/dev/null 2>&1 && sync + if [[ "$?" -eq "0" && -s "${TMP_CHECK_DIR}/${server_plugin_file_ipk}" ]]; then + tolog "02.05 ${server_plugin_file_ipk} complete." + else + tolog "02.05 The plugin file failed to download." "1" + fi + sleep 2 + + # Download plugin i18n file + wget -c "${server_plugin_url}/${server_plugin_version}/${server_plugin_file_i18n}" -O "${TMP_CHECK_DIR}/${server_plugin_file_i18n}" >/dev/null 2>&1 && sync + if [[ "$?" -eq "0" && -s "${TMP_CHECK_DIR}/${server_plugin_file_i18n}" ]]; then + tolog "02.06 ${server_plugin_file_i18n} complete." + else + tolog "02.06 The plugin i18n failed to download." "1" + fi + sleep 2 + + # Download plugin lib-fs file + wget -c "${server_plugin_url}/${server_plugin_version}/${server_plugin_file_libfs}" -O "${TMP_CHECK_DIR}/${server_plugin_file_libfs}" >/dev/null 2>&1 && sync + if [[ "$?" -eq "0" && -s "${TMP_CHECK_DIR}/${server_plugin_file_libfs}" ]]; then + tolog "02.07 ${server_plugin_file_libfs} complete." + else + tolog "02.07 The plugin i18n failed to download." "1" + fi + sleep 2 +fi + +tolog "03. The plug is ready, you can update." +sleep 2 + +# Delete temporary files +rm -f ${github_api_plugin} 2>/dev/null && sync + +#echo 'Update' >$START_LOG +tolog ' Latest version: '${server_plugin_version}'' "1" + +exit 0 diff --git a/luci-app-amlogic/root/usr/share/rpcd/acl.d/luci-app-amlogic.json b/luci-app-amlogic/root/usr/share/rpcd/acl.d/luci-app-amlogic.json new file mode 100644 index 000000000..f5951f6e0 --- /dev/null +++ b/luci-app-amlogic/root/usr/share/rpcd/acl.d/luci-app-amlogic.json @@ -0,0 +1,11 @@ +{ + "luci-app-amlogic": { + "description": "Grant UCI access for luci-app-amlogic", + "read": { + "uci": [ "amlogic" ] + }, + "write": { + "uci": [ "amlogic" ] + } + } +} diff --git a/luci-app-unblockneteasemusic/LICENSE b/luci-app-unblockneteasemusic/LICENSE deleted file mode 100644 index f288702d2..000000000 --- a/luci-app-unblockneteasemusic/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/luci-app-unblockneteasemusic/Makefile b/luci-app-unblockneteasemusic/Makefile deleted file mode 100644 index eae83423c..000000000 --- a/luci-app-unblockneteasemusic/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# SPDX-License-Identifier: GPL-3.0-only -# -# Copyright (C) 2019-2021 Tianling Shen - -include $(TOPDIR)/rules.mk - -LUCI_TITLE:=LuCI support for UnblockNeteaseMusic -LUCI_DEPENDS:=+busybox +dnsmasq-full +ipset +jsonfilter +node +uclient-fetch \ - +PACKAGE_firewall4:ucode \ - @(PACKAGE_libustream-mbedtls||PACKAGE_libustream-openssl||PACKAGE_libustream-wolfssl) -LUCI_PKGARCH:=all - -PKG_NAME:=luci-app-unblockneteasemusic -PKG_VERSION:=2.12 -PKG_RELEASE:=3 - -PKG_MAINTAINER:=Tianling Shen - -include $(TOPDIR)/feeds/luci/luci.mk - -# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-unblockneteasemusic/README.md b/luci-app-unblockneteasemusic/README.md deleted file mode 100644 index 06bf93b78..000000000 --- a/luci-app-unblockneteasemusic/README.md +++ /dev/null @@ -1,64 +0,0 @@ -### 项目简介 -这是一个用于解除网易云音乐播放限制的 OpenWrt 插件,完整支持 播放 / 下载 无版权 / 收费 歌曲
-原理为通过获取其他平台的音乐播放链接,替换网易云音乐内 无版权 / 收费 歌曲链接
- -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FUnblockNeteaseMusic%2Fluci-app-unblockneteasemusic.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2FUnblockNeteaseMusic%2Fluci-app-unblockneteasemusic?ref=badge_shield) - -### 功能说明 -1. 支持自定义音源选择,一般设置默认即可;如需高音质音乐,推荐选择“酷我”或“咪咕” -2. 支持使用 IPset / Hosts 自动劫持相关请求,客户端无需设置代理即可使用 -3. 支持 HTTPS 劫持,客户端信任证书后即可正常使用 -4. 支持将服务公开至公网(默认监听局域网),支持开启严格模式 -5. 支持设定代理,支持指定网易云音乐服务器 IP,支持设定 EndPoint -6. 支持手动/自动更新 Core,确保插件正常运作 -7. 支持设定 JOOX/Migu/QQ Cookie / Youtube API,以正常使用相关音源 -8. 支持无损音质(目前支持 酷狗、酷我、咪咕、pyncmd、QQ 音源) - -### 编译 -```bash - #进入 OpenWrt 源码 package 目录 - cd package - #克隆插件源码 - git clone https://github.com/UnblockNeteaseMusic/luci-app-unblockneteasemusic.git - #返回上一层目录 - cd .. - #配置 - make menuconfig - #在 luci -> application 选中插件,开始编译 - make package/luci-app-unblockneteasemusic/compile V=s -``` - -### 使用方法 -- #### 路由器插件配置 -1. 在路由器 LuCI 界面“服务”选项中找到“解除网易云音乐播放限制” -2. 勾选“启用本插件” -3. “音源接口”选择“默认”(高音质音源推荐选择“酷我”或“咪咕”) -4. 点击“保存&应用” -- 现在您局域网下的所有设备,(一般情况下)无需任何设置即可自动解除网易云音乐播放限制 -- ##### 特别说明 -1. 首次使用本插件时,将会在后台下载核心程序,故启动时间可能会稍微长一点 -2. 如需使用网页端,请额外安装 Tampermonkey 插件:[NeteaseMusic UI Unlocker](https://greasyfork.org/zh-CN/scripts/382285-neteasemusic-ui-unlocker) -3. 推荐在客户端信任 [UnblockNeteaseMusic 证书](https://raw.githubusercontent.com/UnblockNeteaseMusic/server/enhanced/ca.crt),以便 HTTPS 通讯(若您不放心,也可以[自行签发证书](https://github.com/nondanee/UnblockNeteaseMusic/issues/48#issuecomment-477870013)) -4. Android 网易云音乐客户端版本不得大于 [8.0.20](https://www.wandoujia.com/apps/293217/history_v8000020) - -### 效果图 -#### LuCI 界面 - ![Image text](https://raw.githubusercontent.com/UnblockNeteaseMusic/luci-app-unblockneteasemusic/master/views/view1.jpg) - ![Image text](https://raw.githubusercontent.com/UnblockNeteaseMusic/luci-app-unblockneteasemusic/master/views/view2.jpg) - ![Image text](https://raw.githubusercontent.com/UnblockNeteaseMusic/luci-app-unblockneteasemusic/master/views/view3.jpg) -#### UWP 网易云音乐客户端 - ![Image text](https://raw.githubusercontent.com/UnblockNeteaseMusic/luci-app-unblockneteasemusic/master/views/view4.jpg) - -### 鸣谢 -[UnblockNeteaseMusic](https://github.com/UnblockNeteaseMusic/server)的开发者:[nondanee](https://github.com/nondanee)、[pan93412](https://github.com/pan93412)、[1715173329](https://github.com/1715173329)
-[luci-app-unblockmusic](https://github.com/maxlicheng/luci-app-unblockmusic)的开发者:[maxlicheng](https://github.com/maxlicheng)
-[luci-app-unblockmusic(二次修改)](https://github.com/coolsnowwolf/lede/tree/master/package/lean/luci-app-unblockmusic)的开发者:[Lean](https://github.com/coolsnowwolf)
-IPSet 劫持方式指导:[恩山 692049#125 楼](https://www.right.com.cn/forum/forum.php?mod=viewthread&tid=692049&page=9#pid4104303) [rufengsuixing](https://github.com/rufengsuixing/luci-app-unblockmusic) [binsee](https://github.com/binsee/luci-app-unblockmusic)
-Hosts劫持方式指导:[UnblockNeteaseMusic](https://github.com/nondanee/UnblockNeteaseMusic) [云音乐安卓又搞事啦](https://jixun.moe/post/netease-android-hosts-bypass/)
-核心程序版本检测方法指导:[vernesong](https://github.com/vernesong) - -### 协议 -本项目使用 [GPL-3.0-only](https://spdx.org/licenses/GPL-3.0-only.html) 协议授权
-在遵循此协议的前提下,你可以自由修改和分发 - -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FUnblockNeteaseMusic%2Fluci-app-unblockneteasemusic.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2FUnblockNeteaseMusic%2Fluci-app-unblockneteasemusic?ref=badge_large) diff --git a/luci-app-unblockneteasemusic/luasrc/controller/unblockneteasemusic.lua b/luci-app-unblockneteasemusic/luasrc/controller/unblockneteasemusic.lua deleted file mode 100644 index ab919edbe..000000000 --- a/luci-app-unblockneteasemusic/luasrc/controller/unblockneteasemusic.lua +++ /dev/null @@ -1,66 +0,0 @@ --- SPDX-License-Identifer: GPL-3.0-only --- Copyright (C) 2019-2021 Tianling Shen - -module("luci.controller.unblockneteasemusic", package.seeall) - -function index() - if not nixio.fs.access("/etc/config/unblockneteasemusic") then - return - end - - local page - page = entry({"admin", "services", "unblockneteasemusic"}, firstchild(), _("解除网易云音乐播放限制"), 50) - page.dependent = false - page.acl_depends = { "luci-app-unblockneteasemusic" } - - entry({"admin", "services", "unblockneteasemusic", "general"}, cbi("unblockneteasemusic/unblockneteasemusic"), _("基本设定"), 1) - entry({"admin", "services", "unblockneteasemusic", "upgrade"}, form("unblockneteasemusic/unblockneteasemusic_upgrade"), _("更新组件"), 2).leaf = true - entry({"admin", "services", "unblockneteasemusic", "log"}, form("unblockneteasemusic/unblockneteasemusic_log"), _("日志"), 3) - - entry({"admin", "services", "unblockneteasemusic", "status"}, call("act_status")).leaf = true - entry({"admin", "services", "unblockneteasemusic", "update_core"}, call("act_update_core")) - entry({"admin", "services", "unblockneteasemusic", "remove_core"}, call("act_remove_core")) -end - -function act_status() - local e = {} - e.running = luci.sys.call("ps |grep unblockneteasemusic |grep app.js |grep -v grep >/dev/null") == 0 - luci.http.prepare_content("application/json") - luci.http.write_json(e) -end - -function update_core() - core_cloud_ver=luci.sys.exec("uclient-fetch -qO- 'https://api.github.com/repos/UnblockNeteaseMusic/server/commits?sha=enhanced&path=precompiled' | jsonfilter -e '@[0].sha'") - core_cloud_ver_mini=string.sub(core_cloud_ver, 1, 7) - if not core_cloud_ver or not core_cloud_ver_mini then - return "1" - else - core_local_ver=luci.sys.exec("cat '/usr/share/unblockneteasemusic/core_local_ver' 2>'/dev/null'") - if not core_local_ver or (core_local_ver ~= core_cloud_ver) then - luci.sys.call("rm -f /usr/share/unblockneteasemusic/update_core_successfully") - luci.sys.call("/usr/share/unblockneteasemusic/update.sh update_core_from_luci") - if not nixio.fs.access("/usr/share/unblockneteasemusic/update_core_successfully") then - return "2" - else - luci.sys.call("rm -f /usr/share/unblockneteasemusic/update_core_successfully") - return core_cloud_ver_mini - end - else - return "0" - end - end -end - -function act_update_core() - luci.http.prepare_content("application/json") - luci.http.write_json({ - ret = update_core(); - }) -end - -function act_remove_core() - local ret = {} - ret.ret = luci.sys.call("cd /usr/share/unblockneteasemusic && rm -rf core/* && rm -f core_local_ver") == 0 - luci.http.prepare_content("application/json") - luci.http.write_json(ret) -end diff --git a/luci-app-unblockneteasemusic/luasrc/model/cbi/unblockneteasemusic/unblockneteasemusic.lua b/luci-app-unblockneteasemusic/luasrc/model/cbi/unblockneteasemusic/unblockneteasemusic.lua deleted file mode 100644 index 3c5d215e9..000000000 --- a/luci-app-unblockneteasemusic/luasrc/model/cbi/unblockneteasemusic/unblockneteasemusic.lua +++ /dev/null @@ -1,223 +0,0 @@ -mp = Map("unblockneteasemusic", translate("解除网易云音乐播放限制")) -mp.description = translate("原理:采用 [Bilibili/JOOX/酷狗/酷我/咪咕/pyncmd/QQ/Youtube] 等音源,替换网易云音乐 无版权/收费 歌曲链接
具体使用方法参见:GitHub @UnblockNeteaseMusic/luci-app-unblockneteasemusic") - -mp:section(SimpleSection).template = "unblockneteasemusic/unblockneteasemusic_status" - -s = mp:section(TypedSection, "unblockneteasemusic") -s.anonymous = true -s.addremove = false - -enable = s:option(Flag, "enable", translate("启用本插件")) -enable.description = translate("启用本插件以解除网易云音乐播放限制") -enable.default = 0 -enable.rmempty = false - -music_source = s:option(Value, "music_source", translate("音源接口")) -music_source:value("default", translate("默认")) -music_source:value("bilibili", translate("Bilibili音乐")) -music_source:value("joox", translate("JOOX音乐")) -music_source:value("kugou", translate("酷狗音乐")) -music_source:value("kuwo", translate("酷我音乐")) -music_source:value("migu", translate("咪咕音乐")) -music_source:value("pyncmd", translate("网易云音乐(pyncmd)")) -music_source:value("qq", translate("QQ音乐")) -music_source:value("youtube", translate("Youtube音乐")) -music_source:value("youtubedl", translate("Youtube音乐(youtube-dl)")) -music_source:value("ytdlp", translate("Youtube音乐(yt-dlp)")) -music_source:value("ytdownload", translate("Youtube音乐(ytdownload)")) -music_source.description = translate("自定义模式下,多个音源请用空格隔开") -music_source.default = "default" -music_source.rmempty = false - -local_vip = s:option(Flag, "local_vip", translate("启用本地 VIP")) -local_vip.description = translate("启用后,可以使用去广告、个性换肤、鲸云音效等本地功能") -local_vip.default = 0 -local_vip.rmempty = false - -enable_flac = s:option(Flag, "enable_flac", translate("启用无损音质")) -enable_flac.description = translate("目前仅支持酷狗、酷我、咪咕、pyncmd、QQ 音源") -enable_flac.default = 0 -enable_flac.rmempty = false - -replace_music_source = s:option(ListValue, "replace_music_source", translate("强制音乐音源替换")) -replace_music_source:value("dont_replace", translate("不强制替换音乐音源")) -replace_music_source:value("lower_than_192kbps", translate("当音质低于 192 Kbps(中)时")) -replace_music_source:value("lower_than_320kbps", translate("当音质低于 320 Kbps(高)时")) -replace_music_source:value("lower_than_999kbps", translate("当音质低于 999 Kbps(无损)时")) -replace_music_source:value("replace_all", translate("替换所有音乐音源")) -replace_music_source.description = translate("当音乐音质低于指定数值时,尝试强制使用其他平台的高音质版本进行替换") -replace_music_source.default = "dont_replace" -replace_music_source.rmempty = false - -use_custom_cookie = s:option(Flag, "use_custom_cookie", translate("使用自定义 Cookie")) -use_custom_cookie.description = translate("使用自定义 Cookie 请求音源接口") -use_custom_cookie.default = 0 -use_custom_cookie.rmempty = false - -joox_cookie = s:option(Value, "joox_cookie", translate("JOOX Cookie")) -joox_cookie.description = translate("在 joox.com 获取,需要 wmid 和 session_key 值") -joox_cookie.placeholder = "wmid=; session_key=" -joox_cookie.datatype = "string" -joox_cookie:depends("use_custom_cookie", 1) - -migu_cookie = s:option(Value, "migu_cookie", translate("Migu Cookie")) -migu_cookie.description = translate("通过抓包手机客户端请求获取,需要 aversionid 值") -migu_cookie.datatype = "string" -migu_cookie:depends("use_custom_cookie", 1) - -qq_cookie = s:option(Value, "qq_cookie", translate("QQ Cookie")) -qq_cookie.description = translate("在 y.qq.com 获取,需要 uin 和 qm_keyst值 ") -qq_cookie.placeholder = "uin=; qm_keyst=" -qq_cookie.datatype = "string" -qq_cookie:depends("use_custom_cookie", 1) - -youtube_key = s:option(Value, "youtube_key", translate("Youtube API Key")) -youtube_key.description = translate("API Key 申请地址:https://developers.google.com/youtube/v3/getting-started#before-you-start") -youtube_key.datatype = "string" -youtube_key:depends("use_custom_cookie", 1) - -auto_update = s:option(Flag, "auto_update", translate("启用自动更新")) -auto_update.description = translate("启用后,每天将定时自动检查最新版本并更新") -auto_update.default = 0 -auto_update.rmempty = false - -update_time = s:option(ListValue, "update_time", translate("检查更新时间")) -for update_time_hour = 0,23 do - update_time:value(update_time_hour, update_time_hour..":00") -end -update_time.default = "3" -update_time.description = translate("设定每天自动检查更新时间") -update_time:depends("auto_update", 1) - -download_cert = s:option(Button,"certificate", translate("HTTPS 证书")) -download_cert.inputtitle = translate("下载 CA 根证书") -download_cert.description = translate("Linux/iOS/MacOSX 在信任根证书后方可正常使用") -download_cert.inputstyle = "reload" -download_cert.write = function() - act_download_cert() -end - -function act_download_cert() - local t, e - t = nixio.open("/usr/share/unblockneteasemusic/core/ca.crt","r") - luci.http.header('Content-Disposition', 'attachment; filename="ca.crt"') - luci.http.prepare_content("application/octet-stream") - while true do - e = t:read(nixio.const.buffersize) - if (not e) or (#e == 0) then - break - else - luci.http.write(e) - end - end - t:close() - luci.http.close() -end - -advanced_mode = s:option(Flag, "advanced_mode", translate("启用进阶设置")) -advanced_mode.description = translate("非必要不推荐使用") -advanced_mode.default = 0 -advanced_mode.rmempty = false - -http_port = s:option(Value, "http_port", translate("HTTP 监听端口")) -http_port.description = translate("程序监听的 HTTP 端口,不可与 其他程序/HTTPS 共用一个端口") -http_port.placeholder = "5200" -http_port.default = "5200" -http_port.datatype = "port" -http_port:depends("advanced_mode", 1) - -https_port = s:option(Value, "https_port", translate("HTTPS 监听端口")) -https_port.description = translate("程序监听的 HTTPS 端口,不可与 其他程序/HTTP 共用一个端口") -https_port.placeholder = "5201" -https_port.default = "5201" -https_port.datatype = "port" -https_port:depends("advanced_mode", 1) - -endpoint_url = s:option(Value, "endpoint_url", translate("EndPoint")) -endpoint_url.description = translate("具体说明参见:https://github.com/UnblockNeteaseMusic/server") -endpoint_url.default = "https://music.163.com" -endpoint_url.placeholder = "https://music.163.com" -endpoint_url.datatype = "string" -endpoint_url:depends("advanced_mode", 1) - -cnrelay = s:option(Value, "cnrelay", translate("UNM API 服务器")) -cnrelay.description = translate("使用 UnblockNeteaseMusic 中继桥(API)以获取音源信息") -cnrelay.placeholder = "http(s)://host:port" -cnrelay.datatype = "string" -cnrelay:depends("advanced_mode", 1) - -hijack = s:option(ListValue, "hijack_ways", translate("劫持方法")) -hijack:value("dont_hijack", translate("不开启劫持")) -hijack:value("use_ipset", translate("使用 IPSet 劫持")) -hijack:value("use_hosts", translate("使用 Hosts 劫持")) -hijack.description = translate("如果使用Hosts劫持,程序监听的 HTTP/HTTPS 端口将被锁定为 80/443") -hijack.default = "dont_hijack" -hijack:depends("advanced_mode", 1) - -keep_core_when_upgrade = s:option(Flag, "keep_core_when_upgrade", translate("升级时保留核心程序")) -keep_core_when_upgrade.description = translate("默认情况下,在系统升级后会导致核心程序丢失,开启此选项后会保留当前下载的核心程序") -keep_core_when_upgrade.default = 0 -keep_core_when_upgrade.rmempty = false -keep_core_when_upgrade:depends("advanced_mode", 1) - -pub_access = s:option(Flag, "pub_access", translate("部署到公网")) -pub_access.description = translate("默认仅监听局域网,如需提供公开访问请勾选此选项") -pub_access.default = 0 -pub_access.rmempty = false -pub_access:depends("advanced_mode", 1) - -strict_mode = s:option(Flag, "strict_mode", translate("启用严格模式")) -strict_mode.description = translate("若将服务部署到公网,则强烈建议使用严格模式,此模式下仅放行网易云音乐所属域名的请求;注意:该模式下不能使用全局代理") -strict_mode.default = 0 -strict_mode.rmempty = false -strict_mode:depends("advanced_mode", 1) - -netease_server_ip = s:option(Value, "netease_server_ip", translate("网易云服务器 IP")) -netease_server_ip.description = translate("通过 ping music.163.com 即可获得 IP 地址,仅限填写一个") -netease_server_ip.placeholder = "59.111.181.38" -netease_server_ip.datatype = "ipaddr" -netease_server_ip:depends("advanced_mode", 1) - -proxy_server_ip = s:option(Value, "proxy_server_ip", translate("代理服务器地址")) -proxy_server_ip.description = translate("使用代理服务器获取音乐信息") -proxy_server_ip.placeholder = "http(s)://host:port" -proxy_server_ip.datatype = "string" -proxy_server_ip:depends("advanced_mode", 1) - -self_issue_cert_crt = s:option(Value, "self_issue_cert_crt", translate("自签发证书公钥位置")) -self_issue_cert_crt.description = translate("[公钥] 默认使用 UnblockNeteaseMusic 项目提供的 CA 证书,您可以指定为您自己的证书") -self_issue_cert_crt.placeholder = "/usr/share/unblockneteasemusic/core/server.crt" -self_issue_cert_crt.datatype = "file" -self_issue_cert_crt:depends("advanced_mode", 1) - -self_issue_cert_key = s:option(Value, "self_issue_cert_key", translate("自签发证书私钥位置")) -self_issue_cert_key.description = translate("[私钥] 默认使用 UnblockNeteaseMusic 项目提供的 CA 证书,您可以指定为您自己的证书") -self_issue_cert_key.placeholder = "/usr/share/unblockneteasemusic/core/server.key" -self_issue_cert_key.datatype = "file" -self_issue_cert_key:depends("advanced_mode", 1) - -acl_rule = mp:section(TypedSection, "acl_rule", translate("例外客户端规则"), translate("可以为局域网客户端分别设置不同的例外模式,默认无需设置")) -acl_rule.template = "cbi/tblsection" -acl_rule.sortable = true -acl_rule.anonymous = true -acl_rule.addremove = true - -acl_ip_addr = acl_rule:option(Value, "ip_addr", translate("IP 地址")) -acl_ip_addr.width = "40%" -acl_ip_addr.datatype = "ip4addr" -acl_ip_addr.placeholder = "0.0.0.0/0" -luci.ip.neighbors({ family = 4 }, function(entry) - if entry.reachable then - acl_ip_addr:value(entry.dest:string()) - end -end) - -acl_filter_mode = acl_rule:option(ListValue, "filter_mode", translate("规则")) -acl_filter_mode.width = "40%" -acl_filter_mode.default = "disable_all" -acl_filter_mode.rmempty = false -acl_filter_mode:value("disable_all", translate("不代理 HTTP 和 HTTPS")) -acl_filter_mode:value("disable_http", translate("不代理 HTTP")) -acl_filter_mode:value("disable_https", translate("不代理 HTTPS")) - -return mp diff --git a/luci-app-unblockneteasemusic/luasrc/model/cbi/unblockneteasemusic/unblockneteasemusic_log.lua b/luci-app-unblockneteasemusic/luasrc/model/cbi/unblockneteasemusic/unblockneteasemusic_log.lua deleted file mode 100644 index 65df21d85..000000000 --- a/luci-app-unblockneteasemusic/luasrc/model/cbi/unblockneteasemusic/unblockneteasemusic_log.lua +++ /dev/null @@ -1,14 +0,0 @@ -local fs = require "nixio.fs" -local conffile = "/tmp/unblockneteasemusic.log" - -f = SimpleForm("logview") - -t = f:field(TextValue, "conf") -t.rmempty = true -t.rows = 15 -function t.cfgvalue() - return fs.readfile(conffile) or "" -end -t.readonly="readonly" - -return f diff --git a/luci-app-unblockneteasemusic/luasrc/model/cbi/unblockneteasemusic/unblockneteasemusic_upgrade.lua b/luci-app-unblockneteasemusic/luasrc/model/cbi/unblockneteasemusic/unblockneteasemusic_upgrade.lua deleted file mode 100644 index 5e58988e9..000000000 --- a/luci-app-unblockneteasemusic/luasrc/model/cbi/unblockneteasemusic/unblockneteasemusic_upgrade.lua +++ /dev/null @@ -1,19 +0,0 @@ -local m, up_luci, up_core - -m = SimpleForm("Version") -m.reset = false -m.submit = false - -rm_core = m:field(DummyValue,"remove_core", translate("删除核心")) -rm_core.rawhtml = true -rm_core.template = "unblockneteasemusic/remove_core" -rm_core.value = translate("") -rm_core.description = "删除核心后,需手动点击下面的按钮重新下载,有助于解决版本冲突问题" - -up_core = m:field(DummyValue,"update_core", translate("更新核心")) -up_core.rawhtml = true -up_core.template = "unblockneteasemusic/update_core" -up_core.value = translate("") -up_core.description = "更新完毕后会自动在后台重启插件,无需手动重启" - -return m diff --git a/luci-app-unblockneteasemusic/luasrc/view/unblockneteasemusic/remove_core.htm b/luci-app-unblockneteasemusic/luasrc/view/unblockneteasemusic/remove_core.htm deleted file mode 100644 index df97046f4..000000000 --- a/luci-app-unblockneteasemusic/luasrc/view/unblockneteasemusic/remove_core.htm +++ /dev/null @@ -1,32 +0,0 @@ -<%+cbi/valueheader%> - - - - - -<%=self.value%> - -<%+cbi/valuefooter%> diff --git a/luci-app-unblockneteasemusic/luasrc/view/unblockneteasemusic/unblockneteasemusic_status.htm b/luci-app-unblockneteasemusic/luasrc/view/unblockneteasemusic/unblockneteasemusic_status.htm deleted file mode 100644 index a70889c5d..000000000 --- a/luci-app-unblockneteasemusic/luasrc/view/unblockneteasemusic/unblockneteasemusic_status.htm +++ /dev/null @@ -1,22 +0,0 @@ - - -
-

- <%:Collecting data...%> -

-
diff --git a/luci-app-unblockneteasemusic/luasrc/view/unblockneteasemusic/update_core.htm b/luci-app-unblockneteasemusic/luasrc/view/unblockneteasemusic/update_core.htm deleted file mode 100644 index 8acb275ea..000000000 --- a/luci-app-unblockneteasemusic/luasrc/view/unblockneteasemusic/update_core.htm +++ /dev/null @@ -1,36 +0,0 @@ -<%+cbi/valueheader%> - - - - - -<%=self.value%> - -<%+cbi/valuefooter%> diff --git a/luci-app-unblockneteasemusic/root/etc/config/unblockneteasemusic b/luci-app-unblockneteasemusic/root/etc/config/unblockneteasemusic deleted file mode 100644 index 18b45dd8c..000000000 --- a/luci-app-unblockneteasemusic/root/etc/config/unblockneteasemusic +++ /dev/null @@ -1,11 +0,0 @@ - -config unblockneteasemusic 'config' - option enable '0' - option music_source 'default' - option enable_flac '0' - option replace_music_source 'dont_replace' - option use_custom_cookie '0' - option local_vip '0' - option auto_update '1' - option update_time '3' - option advanced_mode '0' diff --git a/luci-app-unblockneteasemusic/root/etc/init.d/unblockneteasemusic b/luci-app-unblockneteasemusic/root/etc/init.d/unblockneteasemusic deleted file mode 100755 index 67d9251a7..000000000 --- a/luci-app-unblockneteasemusic/root/etc/init.d/unblockneteasemusic +++ /dev/null @@ -1,316 +0,0 @@ -#!/bin/sh /etc/rc.common -# SPDX-License-Identifier: GPL-3.0-only -# -# Copyright (C) 2019-2021 Tianling Shen - -USE_PROCD=1 - -START=99 -STOP=10 - -NAME="unblockneteasemusic" -UPGRADE_CONF="/lib/upgrade/keep.d/$NAME" - -IPT_N="iptables -t nat" -RULES_UC="/usr/share/$NAME/rules/default.uc" -RULES_NFT="/etc/nftables.d/90-$NAME-rules.nft" - -is_enabled() { - local enabled - config_get_bool enabled "$1" "$2" "${3:-0}" - if [ "$enabled" -eq "1" ]; then - return 0 - else - return 1 - fi -} - -append_param() { - procd_append_param command "$1" $2 -} - -append_param_arg() { - local value - config_get value "$1" "$2" $4 - [ -n "$value" ] && append_param "$3" "$value" -} - -append_param_env() { - local value - config_get value "$1" "$2" $4 - [ -n "$value" ] && procd_append_param env "$3"="$value" -} - -uci_get_by_name() { - local ret - ret="$(uci -q get "$NAME".@"$1"["${4:-0}"]."$2")" - echo "${ret:-$3}" -} - -start_service() -{ - config_load "$NAME" - is_enabled "config" "enable" || exit 1 - - local update_time - config_get update_time "config" "update_time" "3" - sed -i "/$NAME/d" /etc/crontabs/root - is_enabled "config" "auto_update" && echo "0 ${update_time} * * * /usr/share/$NAME/update.sh update_core" >> "/etc/crontabs/root" - echo "*/5 * * * * /usr/share/$NAME/log_check.sh" >> "/etc/crontabs/root" - /etc/init.d/cron restart - - [ ! -s "/usr/share/$NAME/core/app.js" ] && { rm -f "/usr/share/$NAME/local_ver"; sh "/usr/share/$NAME/update.sh" "update_core_non_restart"; } - [ ! -s "/usr/share/$NAME/core/app.js" ] && { echo "Core Not Found, please download it before starting." >> "/tmp/$NAME.log"; exit 1; } - - procd_open_instance "$NAME" - procd_set_param command node "/usr/share/$NAME/core/app.js" - append_param "-a" "0.0.0.0" - - local http_port https_port hijack_ways - config_get http_port "config" "http_port" "5200" - config_get https_port "config" "https_port" "5201" - config_get hijack_ways "config" "hijack_ways" "use_ipset" - [ "${hijack_ways}" = "use_hosts" ] && { http_port="80"; https_port="443"; } - append_param "-p" "${http_port}":"${https_port}" - - if [ -e "$(command -v fw4)" ]; then - json_init - if is_enabled "config" "pub_access"; then - json_add_int o_pub_access "1" - else - json_add_int o_pub_access "0" - fi - json_add_int o_http_port "${http_port}" - json_add_int o_https_port "${https_port}" - json_add_string o_hijack_ways "${hijack_ways}" - else - if is_enabled "config" "pub_access"; then - iptables -I "INPUT" -p "tcp" --dport "${http_port}" -j "ACCEPT" - iptables -I "INPUT" -p "tcp" --dport "${https_port}" -j "ACCEPT" - echo "${http_port}:${https_port}" > "/tmp/$NAME.ports" - - mkdir -p "/var/etc/" - echo "/etc/init.d/$NAME restart" > "/var/etc/$NAME.include" - fi - fi - - local music_source - config_get music_source "config" "music_source" "default" - [ "${music_source}" != "default" ] && append_param -o "${music_source}" - - append_param_arg "config" "cnrelay" "-c" - append_param_arg "config" "endpoint_url" "-e" "https://music.163.com" - append_param_arg "config" "netease_server_ip" "-f" - append_param_arg "config" "proxy_server_ip" "-u" - is_enabled "config" "strict_mode" && append_param "-s" - - procd_set_param env LOG_FILE="/tmp/$NAME.log" - - append_param_env "config" "joox_cookie" "JOOX_COOKIE" - append_param_env "config" "migu_cookie" "MIGU_COOKIE" - append_param_env "config" "qq_cookie" "QQ_COOKIE" - append_param_env "config" "youtube_key" "YOUTUBE_KEY" - append_param_env "config" "self_issue_cert_crt" "SIGN_CERT" "/usr/share/$NAME/core/server.crt" - append_param_env "config" "self_issue_cert_key" "SIGN_KEY" "/usr/share/$NAME/core/server.key" - - is_enabled "config" "enable_flac" && procd_append_param env ENABLE_FLAC="true" - is_enabled "config" "local_vip" && procd_append_param env ENABLE_LOCAL_VIP="true" - case "$(config_get "config" "replace_music_source")" in - "lower_than_192kbps") procd_append_param env MIN_BR="192000" ;; - "lower_than_320kbps") procd_append_param env MIN_BR="320000" ;; - "lower_than_999kbps") procd_append_param env MIN_BR="600000" ;; - "replace_all") procd_append_param env MIN_BR="9999999" ;; - esac - procd_append_param env JSON_LOG="true" - - procd_set_param stdout 1 - procd_set_param stderr 1 - procd_set_param respawn - - local lan_addr="$(uci -q get network.lan.ipaddr)" - local tmp="/tmp/$NAME" - if [ "${hijack_ways}" = "use_ipset" ]; then - # TODO: wating for dnsmasq support nftset - mkdir -p "/tmp/dnsmasq.d" - rm -f "/tmp/dnsmasq.d/dnsmasq-$NAME.conf" - cat <<-EOF > "/tmp/dnsmasq.d/dnsmasq-$NAME.conf" - dhcp-option=252,http://${lan_addr}:${http_port}/proxy.pac - ipset=/.music.163.com/neteasemusic - ipset=/interface.music.163.com/neteasemusic - ipset=/interface3.music.163.com/neteasemusic - ipset=/apm.music.163.com/neteasemusic - ipset=/apm3.music.163.com/neteasemusic - ipset=/clientlog.music.163.com/neteasemusic - ipset=/clientlog3.music.163.com/neteasemusic - EOF - /etc/init.d/dnsmasq reload - - [ -e "$(command -v fw4)" ] || { - ipset create "acl_neteasemusic_http" hash:ip - ipset create "acl_neteasemusic_https" hash:ip - ipset create "neteasemusic" hash:ip - } - - local ip_addr_num="$(uci show "$NAME" | grep -c "filter_mode")" - let ip_addr_num="ip_addr_num-1" - local acl_http_addr acl_https_addr - [ "${ip_addr_num}" -ge "0" ] && for i in $(seq 0 "${ip_addr_num}") - do - ip_addr="$(uci_get_by_name "acl_rule" "ip_addr" "" "$i")" - filter_mode="$(uci_get_by_name "acl_rule" "filter_mode" "" "$i")" - - case "${filter_mode}" in - "disable_http") - if [ -e "$(command -v fw4)" ];then - acl_http_addr="${acl_http_addr}${ip_addr}\n" - else - ipset -! add "acl_neteasemusic_http" "${ip_addr}" - fi - ;; - "disable_https") - if [ -e "$(command -v fw4)" ]; then - acl_https_addr="${acl_https_addr}${ip_addr}\n" - else - ipset -! add "acl_neteasemusic_https" "${ip_addr}" - fi - ;; - "disable_all") - if [ -e "$(command -v fw4)" ]; then - acl_http_addr="${acl_http_addr}${ip_addr}\n" - acl_https_addr="${acl_https_addr}${ip_addr}\n" - else - ipset -! add "acl_neteasemusic_http" "${ip_addr}" - ipset -! add "acl_neteasemusic_https" "${ip_addr}" - fi - ;; - esac - done - - local netease_music_ips="$(uclient-fetch -qO- "http://httpdns.n.netease.com/httpdns/v2/d?domain=music.163.com,interface.music.163.com,interface3.music.163.com,apm.music.163.com,apm3.music.163.com,clientlog.music.163.com,clientlog3.music.163.com" |jsonfilter -e '@.data.*.ip.*')" - local netease_music_ips2="$(uclient-fetch -qO- "https://music.httpdns.c.163.com/d" --post-data="music.163.com,interface.music.163.com,interface3.music.163.com,apm.music.163.com,apm3.music.163.com,clientlog.music.163.com,clientlog3.music.163.com" |jsonfilter -e '@.dns.*["ips"].*')" - if [ -e "$(command -v fw4)" ]; then - local neteasemusic_addr="$(echo -e "${netease_music_ips}\n${netease_music_ips2}" |sort -u |awk '{print $1}')" - - json_add_string o_acl_http_addr "$acl_http_addr" - json_add_string o_acl_https_addr "$acl_https_addr" - json_add_string o_neteasemusic_addr "$neteasemusic_addr" - json_dump -i >"$tmp.json" - - if ucode -S -i "$RULES_UC" -E "$tmp.json" >"$tmp.nft" \ - && ! cmp -s "$tmp.nft" "$RULES_NFT"; then - echo "table inet chk {include \"$tmp.nft\";}" >"$tmp.nft.chk" - if nft -f "$tmp.nft.chk" -c; then - mv -f "$tmp.nft" "$RULES_NFT" - fw4 reload - fi - rm -f "$tmp.nft.chk" - fi - rm -f "$tmp.json" "$tmp.nft" - else - echo -e "${netease_music_ips}\n${netease_music_ips2}" |sort -u |awk '{print "ipset add neteasemusic "$1}' |sh - - $IPT_N -N "netease_cloud_music" - for local_addr in "0.0.0.0/8" "10.0.0.0/8" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.168.0.0/16" "224.0.0.0/4" "240.0.0.0/4"; do - $IPT_N -A "netease_cloud_music" -d "${local_addr}" -j "RETURN" - done - - $IPT_N -A "netease_cloud_music" -p "tcp" -m "set" ! --match-set "acl_neteasemusic_http" "src" --dport "80" -j "REDIRECT" --to-ports "${http_port}" - $IPT_N -A "netease_cloud_music" -p "tcp" -m "set" ! --match-set "acl_neteasemusic_https" "src" --dport "443" -j "REDIRECT" --to-ports "${https_port}" - $IPT_N -I "PREROUTING" -p "tcp" -m "set" --match-set "neteasemusic" "dst" -j "netease_cloud_music" - - mkdir -p "/var/etc/" - echo "/etc/init.d/$NAME restart" > "/var/etc/$NAME.include" - fi - elif [ "${hijack_ways}" = "use_hosts" ]; then - mkdir -p "/tmp/dnsmasq.d" - rm -f "/tmp/dnsmasq.d/dnsmasq-$NAME.conf" - cat <<-EOF > "/tmp/dnsmasq.d/dnsmasq-$NAME.conf" - dhcp-option=252,http://${lan_addr}:${http_port}/proxy.pac - address=/music.163.com/${lan_addr} - address=/interface.music.163.com/${lan_addr} - address=/interface3.music.163.com/${lan_addr} - address=/apm.music.163.com/${lan_addr} - address=/apm3.music.163.com/${lan_addr} - address=/clientlog.music.163.com/${lan_addr} - address=/clientlog3.music.163.com/${lan_addr} - address=/music.httpdns.c.163.com/0.0.0.0 - EOF - /etc/init.d/dnsmasq reload - - ip route add "223.252.199.10" dev lo - if [ -e "$(command -v fw4)" ]; then - json_dump -i >"$tmp.json" - if ucode -S -i "$RULES_UC" -E "$tmp.json" >"$tmp.nft" \ - && ! cmp -s "$tmp.nft" "$RULES_NFT"; then - echo "table inet chk {include \"$tmp.nft\";}" >"$tmp.nft.chk" - if nft -f "$tmp.nft.chk" -c; then - mv -f "$tmp.nft" "$RULES_NFT" - fw4 reload - fi - rm -f "$tmp.nft.chk" - fi - rm -f "$tmp.json" "$tmp.nft" - fi - fi - - procd_close_instance -} >"/dev/null" 2>&1 - -stop_service() -{ - config_load "$NAME" - - sed -i "/$NAME/d" "/etc/crontabs/root" - /etc/init.d/cron restart - - rm -f "${UPGRADE_CONF}" - is_enabled "config" "keep_core_when_upgrade" && { - echo "/usr/share/$NAME/core/" >> "${UPGRADE_CONF}" - echo "/usr/share/$NAME/local_ver" >> "${UPGRADE_CONF}" - } - - local self_issue_cert_crt self_issue_cert_key - config_get "self_issue_cert_crt" "config" "self_issue_cert_crt" - config_get "self_issue_cert_key" "config" "self_issue_cert_key" - { [ -f "${self_issue_cert_crt}" ] && [ -f "${self_issue_cert_key}" ]; } && { - echo "${self_issue_cert_crt}" >> "${UPGRADE_CONF}" - echo "${self_issue_cert_key}" >> "${UPGRADE_CONF}" - } - - if [ -e "$(command -v fw4)" ]; then - [ ! -e "$RULES_NFT" ] || rm -f "$RULES_NFT" - fw4 reload - else - [ ! -e "/tmp/$NAME.ports" ] || { - iptables -D "INPUT" -p "tcp" --dport "$(awk -F ':' 'print $1' "/tmp/$NAME.ports")" -j "ACCEPT" - iptables -D "INPUT" -p "tcp" --dport "$(awk -F ':' 'print $2' "/tmp/$NAME.ports")" -j "ACCEPT" - } - rm -f "/tmp/$NAME.ports" - - $IPT_N -D "PREROUTING" -p "tcp" -m set --match-set "neteasemusic" "dst" -j "netease_cloud_music" - $IPT_N -F "netease_cloud_music" - $IPT_N -X "netease_cloud_music" - - ipset destroy "neteasemusic" - ipset destroy "acl_neteasemusic_http" - ipset destroy "acl_neteasemusic_https" - - echo "" > "/var/etc/$NAME.include" - fi - - rm -f "/tmp/dnsmasq.d/dnsmasq-$NAME.conf" - /etc/init.d/dnsmasq reload - - ip route del "223.252.199.10" - - rm -f "/tmp/$NAME.log" -} >"/dev/null" 2>&1 - -reload_service() { - stop - start -} - -service_triggers() { - procd_add_reload_trigger "$NAME" -} diff --git a/luci-app-unblockneteasemusic/root/etc/uci-defaults/luci-unblockneteasemusic b/luci-app-unblockneteasemusic/root/etc/uci-defaults/luci-unblockneteasemusic deleted file mode 100755 index f47a6d08c..000000000 --- a/luci-app-unblockneteasemusic/root/etc/uci-defaults/luci-unblockneteasemusic +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh - -uci -q batch <<-EOF >/dev/null - delete ucitrack.@unblockneteasemusic[-1] - add ucitrack unblockneteasemusic - set ucitrack.@unblockneteasemusic[-1].init=unblockneteasemusic - commit ucitrack -EOF -[ -e "$(command -v fw4)" ] || { -uci -q batch <<-EOF >/dev/null - delete firewall.unblockneteasemusic - set firewall.unblockneteasemusic=include - set firewall.unblockneteasemusic.type=script - set firewall.unblockneteasemusic.path=/var/etc/unblockneteasemusic.include - set firewall.unblockneteasemusic.reload=1 - commit firewall -EOF -} - -rm -f /tmp/luci-indexcache -exit 0 diff --git a/luci-app-unblockneteasemusic/root/usr/bin/unm-debug b/luci-app-unblockneteasemusic/root/usr/bin/unm-debug deleted file mode 100755 index 6657791db..000000000 --- a/luci-app-unblockneteasemusic/root/usr/bin/unm-debug +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -# Copyright (C) 2021 Tianling Shen - -command -v "curl" >"/dev/null" || { echo -e "curl is not found."; exit 1; } - -mkdir -p "/tmp" -/usr/share/unblockneteasemusic/debugging.sh 2>&1 | tee "/tmp/unm-debugging-output.txt" - -catbox_link="$(curl -fsS -F "reqtype=fileupload" -F "time=72h" -F "fileToUpload=@/tmp/unm-debugging-output.txt" "https://litterbox.catbox.moe/resources/internals/api.php")" -transfer_link="$(curl -fsS --upload-file "/tmp/unm-debugging-output.txt" "https://transfer.sh/unm-debugging-output.txt")" -echo -e "\n" -echo -e "Log is available at:" -echo -e "$catbox_link" -echo -e "$transfer_link" - -rm -f "/tmp/unm-debugging-output.txt" diff --git a/luci-app-unblockneteasemusic/root/usr/share/rpcd/acl.d/luci-app-unblockneteasemusic.json b/luci-app-unblockneteasemusic/root/usr/share/rpcd/acl.d/luci-app-unblockneteasemusic.json deleted file mode 100644 index 06f074232..000000000 --- a/luci-app-unblockneteasemusic/root/usr/share/rpcd/acl.d/luci-app-unblockneteasemusic.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "luci-app-unblockneteasemusic": { - "description": "Grant UCI access for luci-app-unblockneteasemusic", - "read": { - "uci": [ "unblockneteasemusic" ] - }, - "write": { - "uci": [ "unblockneteasemusic" ] - } - } -} diff --git a/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/debugging.sh b/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/debugging.sh deleted file mode 100755 index 9eca9c77b..000000000 --- a/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/debugging.sh +++ /dev/null @@ -1,108 +0,0 @@ -#!/bin/sh -# Copyright (C) 2021 Tianling Shen - -. /lib/functions.sh - -command -v "curl" >"/dev/null" || { echo -e "curl is not found."; exit 1; } - -echo -e "Launching luci-app-unblockneteasmusic Debugging Tool..." -echo -e "\n" - -echo -e "OpenWrt info:" -cat "/etc/openwrt_release" -echo -e "\n" - -echo -e "uclient-fetch info:" -opkg info uclient-fetch -opkg info libustream-* -uclient-fetch -O- 'https://api.github.com/repos/UnblockNeteaseMusic/server/commits?sha=enhanced&path=precompiled' | jsonfilter -e '@[0].sha' || echo -e "Failed to connect to GitHub with uclient-fetch." -echo -e "\n" - -echo -e "Node.js info:" -opkg info node -echo -e "Node.js is placed at $(command -v node || echo "Not Found")" -echo -e "Node.js version: $(node -v 2>"/dev/null" || echo "Not Found")" -echo -e "\n" - -echo -e "luci-app-unblockneteasmusic info:" -opkg info "luci-app-unblockneteasemusic" -ls -lh "/etc/config/unblockneteasemusic" "/etc/init.d/unblockneteasemusic" "/usr/share/unblockneteasemusic" -cat "/etc/config/unblockneteasemusic" | sed -e "s,joox_cookie .*,joox_cookie 'set',g" \ - -e "s,migu_cookie .*,migu_cookie 'set',g" \ - -e "s,qq_cookie .*,qq_cookie 'set',g" \ - -e "s,youtube_key .*,youtube_key 'set',g" \ - -e "s,proxy_server_ip .*,proxy_server_ip 'set',g" -echo -e "\n" - -echo -e "UnblockNeteaseMusic Node.js info:" -echo -e "Git HEAD version: $(cat "/usr/share/unblockneteasemusic/core_local_ver" 2>"/dev/null" || echo "Not Found")" -echo -e "Core version: $(node "/usr/share/unblockneteasemusic/core/app.js" -v 2>"/dev/null" || echo "Not Found")" -ls -lh "/usr/share/unblockneteasemusic/core" 2>"/dev/null" -echo -e "\n" - -echo -e "Netease networking info:" -curl -fsv "http://music.163.com/song/media/outer/url?id=641644.mp3" 2>&1 | grep "Location" || echo -e "Cannot connect to NeteaseMusic." -curl -sSL "http://httpdns.n.netease.com/httpdns/v2/d?domain=music.163.com" || echo -e "Cannot connect to Netease HTTPDNS." -config_load "unblockneteasemusic" -config_get custom_proxy "config" "proxy_server_ip" -[ -n "$custom_proxy" ] && { curl -sL -x "$custom_proxy" "http://music.163.com/song/media/outer/url?id=641644.mp3" 2>&1 | grep "Location" || echo -e "Cannot connect to NeteaseMusic via proxy."; } -echo -e "\n" - -echo -e "Port status:" -config_get unm_port "config" "http_port" "5200" -config_get unm_ports "config" "https_port" "5201" -[ "x$(config_get "config" "hijack_ways")" = "xuse_hosts" ] && { unm_port="80"; unm_ports="443"; } -netstat -tlpen | grep "$unm_port" || echo -e "No instance found on port $unm_port." -netstat -tlpen | grep "$unm_ports" || echo -e "No instance found on port $unm_ports." -echo -e "\n" - -echo -e "Running info:" -procd_running_status="$(/etc/init.d/unblockneteasemusic status)" -echo -e "PROCD running status: $procd_running_status" -[ "$procd_running_status" = "running" ] && { ps | grep "unblockneteasemusic" | grep "app\.js" || echo -e "Thread is not found."; } -echo -e "\n" - -[ "$procd_running_status" != "running" ] || { - echo -e "Firewall info:" - if [ -e "$(command -v fw4)" ]; then - [ -e "/etc/nftables.d/90-unblockneteasemusic-rules.nft" ] || echo -e 'netease_cloud_music nft rule file not found.' - echo -e "" - nft list set inet fw4 "acl_neteasemusic_http" 2>&1 - echo -e "" - nft list set inet fw4 "acl_neteasemusic_https" 2>&1 - echo -e "" - nft list set inet fw4 "local_addr" 2>&1 - echo -e "" - nft list set inet fw4 "neteasemusic" 2>&1 - echo -e "" - nft list chain inet fw4 "input_wan" | grep "unblockneteasemusic-http-" 2>"/dev/null" || echo -e 'Http Port pub access rule not found.' - echo -e "" - nft list chain inet fw4 "input_wan" | grep "unblockneteasemusic-https-" 2>"/dev/null" || echo -e 'Https Port pub access rule not found.' - echo -e "" - nft list chain inet fw4 "netease_cloud_music" 2>&1 - echo -e "" - nft list chain inet fw4 "netease_cloud_music_redir" 2>&1 - else - iptables -t "nat" -L "netease_cloud_music" 2>"/dev/null" || echo -e 'Chain "netease_cloud_music" not found.' - echo -e "" - ipset list "neteasemusic" 2>"/dev/null" || echo -e 'Table "neteasemusic" not found.' - echo -e "" - ipset list "acl_neteasemusic_http" 2>"/dev/null" || echo -e 'Table "acl_neteasemusic_http" not found.' - echo -e "" - ipset list "acl_neteasemusic_https" 2>"/dev/null" || echo -e 'Table "acl_neteasemusic_https" not found.' - fi - echo -e "" - cat "/tmp/dnsmasq.d/dnsmasq-unblockneteasemusic.conf" - echo -e "\n" - - echo -e "Testing source replacing..." - lan_ip="$(uci -q get "network.lan.ipaddr" || echo "127.0.0.1")" - - echo -n "" > "/tmp/unblockneteasemusic.log" - curl -sSL -X "POST" "https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token=" --data "params=bf3kf%2BOyalbxNS%2FeHAXquH8D2nt2YrhBzww4zy5rj2H%2BeAhdOIaGh4HHHzcoREFcu9Ve35LUgc%2BGE1YJD1HxrJ87ucm5zK%2FFn1lLvHFv1A8ZAuyU1afjG28s2Xja6zpfg00T0EcCeqkK61OpTfAaqw%3D%3D&encSecKey=6bab0dfa7ee3b292f9263a7af466636731cdbbd1d8747c9178c17477e70be899b7788c4a4e315c9fdb8c6e787603db6f9dff62c356f164d35b16b7f2d9ad5ede3cc7336130605521a8f916d308ce86b15c32b81c883ae2ba9c244444d91e1683be93fa0ea3e2a85207c9d693b86b5bb31adb002dd56c0bbcce9c73ec3bf5c105" - echo -e "" - curl -ksSL -X "POST" -x "http://$lan_ip:$unm_port" "https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token=" --data "params=bf3kf%2BOyalbxNS%2FeHAXquH8D2nt2YrhBzww4zy5rj2H%2BeAhdOIaGh4HHHzcoREFcu9Ve35LUgc%2BGE1YJD1HxrJ87ucm5zK%2FFn1lLvHFv1A8ZAuyU1afjG28s2Xja6zpfg00T0EcCeqkK61OpTfAaqw%3D%3D&encSecKey=6bab0dfa7ee3b292f9263a7af466636731cdbbd1d8747c9178c17477e70be899b7788c4a4e315c9fdb8c6e787603db6f9dff62c356f164d35b16b7f2d9ad5ede3cc7336130605521a8f916d308ce86b15c32b81c883ae2ba9c244444d91e1683be93fa0ea3e2a85207c9d693b86b5bb31adb002dd56c0bbcce9c73ec3bf5c105" - echo -e "" -} - -cat "/tmp/unblockneteasemusic.log" diff --git a/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/log_check.sh b/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/log_check.sh deleted file mode 100755 index 40e921cad..000000000 --- a/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/log_check.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-3.0-only -# Copyright (C) 2019-2021 Tianling Shen - -NAME="unblockneteasemusic" - -log_max_size="4" #使用KB计算 -log_file="/tmp/$NAME.log" - -log_size="$(expr $(ls -l "${log_file}" | awk -F ' ' '{print $5}') / "1024")" -[ "${log_size}" -lt "${log_max_size}" ] || echo "" > "${log_file}" diff --git a/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/rules/chain.uc b/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/rules/chain.uc deleted file mode 100644 index ee477c1f1..000000000 --- a/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/rules/chain.uc +++ /dev/null @@ -1,30 +0,0 @@ -{% - -let http_port = o_http_port; -let https_port = o_https_port; -let pub_access = o_pub_access; -let hijack_ways = o_hijack_ways; - -%} - -{% if (pub_access == 1): %} -chain input_wan { - tcp dport {{ http_port }} counter accept comment "!fw4: unblockneteasemusic-http-pub-access" - tcp dport {{ https_port }} counter accept comment "!fw4: unblockneteasemusic-https-pub-access" -} -{% endif %} - -{% if (hijack_ways == "use_ipset"): %} -chain netease_cloud_music { - type nat hook prerouting priority -1; policy accept; - meta l4proto tcp ip daddr @neteasemusic jump netease_cloud_music_redir; -} - -chain netease_cloud_music_redir { - ip daddr @local_addr return; - ip saddr @acl_neteasemusic_http accept; - ip saddr @acl_neteasemusic_https accept; - tcp dport 80 counter redirect to :{{ http_port }}; - tcp dport 443 counter redirect to :{{ https_port }}; -} -{% endif %} diff --git a/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/rules/default.uc b/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/rules/default.uc deleted file mode 100644 index be6fb9ee1..000000000 --- a/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/rules/default.uc +++ /dev/null @@ -1,9 +0,0 @@ -{% - -let hijack_ways = o_hijack_ways; -if (hijack_ways == "use_ipset") { - include("set.uc"); -} -include("chain.uc"); - -%} diff --git a/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/rules/set.uc b/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/rules/set.uc deleted file mode 100644 index b5895c849..000000000 --- a/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/rules/set.uc +++ /dev/null @@ -1,73 +0,0 @@ -{% - -let o_local_bypass = " - 0.0.0.0/8 - 10.0.0.0/8 - 100.64.0.0/10 - 127.0.0.0/8 - 169.254.0.0/16 - 172.16.0.0/12 - 192.0.0.0/24 - 192.0.2.0/24 - 192.31.196.0/24 - 192.52.193.0/24 - 192.88.99.0/24 - 192.168.0.0/16 - 192.175.48.0/24 - 198.18.0.0/15 - 198.51.100.0/24 - 203.0.113.0/24 - 224.0.0.0/4 - 240.0.0.0/4 -"; - -let set_suffix = { - "acl_neteasemusic_http": { - str: o_acl_http_addr, - }, - "acl_neteasemusic_https": { - str: o_acl_https_addr, - }, - "local_addr": { - str: o_local_bypass, - }, - "neteasemusic": { - str: o_neteasemusic_addr, - }, -}; - -function set_elements_parse(res, str) { - for (let addr in split(str, /[ \t\n]/)) { - addr = trim(addr); - if (!addr) continue; - push(res, addr); - } -} - -function set_elements(suf) { - let obj = set_suffix[suf]; - let res = []; - let addr; - - let str = obj["str"]; - if (str) { - set_elements_parse(res, str); - } - - return res; -} -%} - -{% for (let suf in set_suffix): %} -set {{ suf }} { - type ipv4_addr; - flags interval; -{% let elems = set_elements(suf); if (length(elems)): %} - elements = { -{% for (let i = 0; i < length(elems); i++): %} - {{ elems[i] }}{% if (i < length(elems) - 1): %},{% endif %}{% print("\n") %} -{% endfor %} - } -{% endif %} -} -{% endfor %} diff --git a/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/update.sh b/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/update.sh deleted file mode 100755 index 424bd8cc1..000000000 --- a/luci-app-unblockneteasemusic/root/usr/share/unblockneteasemusic/update.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-3.0-only -# Copyright (C) 2019-2021 Tianling Shen - -NAME="unblockneteasemusic" - -check_core_if_already_running(){ - running_tasks="$(ps |grep "$NAME" |grep "update.sh" |grep "update_core" |grep -v "grep" |awk '{print $1}' |wc -l)" - [ "${running_tasks}" -gt "2" ] && { echo -e "\nA task is already running." >> "/tmp/$NAME.log"; exit 2; } -} - -clean_log(){ - echo "" > "/tmp/$NAME.log" -} - -check_core_latest_version(){ - core_latest_ver="$(uclient-fetch -qO- 'https://api.github.com/repos/UnblockNeteaseMusic/server/commits?sha=enhanced&path=precompiled' | jsonfilter -e '@[0].sha')" - [ -z "${core_latest_ver}" ] && { echo -e "\nFailed to check latest core version, please try again later." >> "/tmp/$NAME.log"; exit 1; } - if [ ! -e "/usr/share/$NAME/core_local_ver" ]; then - clean_log - echo -e "Local version: NOT FOUND, latest version: ${core_latest_ver}." >> "/tmp/$NAME.log" - update_core - else - if [ "$(cat /usr/share/$NAME/core_local_ver)" != "${core_latest_ver}" ]; then - clean_log - echo -e "Local version: $(cat /usr/share/$NAME/core_local_ver 2>"/dev/null"), latest version: ${core_latest_ver}." >> "/tmp/$NAME.log" - update_core - else - echo -e "\nLocal version: $(cat /usr/share/$NAME/core_local_ver 2>"/dev/null"), latest version: ${core_latest_ver}." >> "/tmp/$NAME.log" - echo -e "You're already using the latest version." >> "/tmp/$NAME.log" - exit 3 - fi - fi -} - -update_core(){ - echo -e "Updating core..." >> "/tmp/$NAME.log" - - mkdir -p "/usr/share/$NAME/core" > "/dev/null" 2>&1 - rm -rf /usr/share/$NAME/core/* > "/dev/null" 2>&1 - - for url in $(uclient-fetch -qO- "https://api.github.com/repos/UnblockNeteaseMusic/server/contents/precompiled" |jsonfilter -e '@[*].download_url') - do - uclient-fetch "${url}" -qO "/usr/share/$NAME/core/${url##*/}" - [ -s "/usr/share/$NAME/core/${url##*/}" ] || { - echo -e "Failed to download ${url##*/}." >> "/tmp/$NAME.log" - exit 1 - } - done - - for cert in "ca.crt" "server.crt" "server.key" - do - uclient-fetch "https://raw.githubusercontent.com/UnblockNeteaseMusic/server/enhanced/${cert}" -qO "/usr/share/$NAME/core/${cert}" - [ -s "/usr/share/$NAME/core/${cert}" ] || { - echo -e "Failed to download ${cert}." >> "/tmp/$NAME.log" - exit 1 - } - done - - [ -n "${update_core_from_luci}" ] && touch "/usr/share/$NAME/update_core_successfully" - echo -e "${core_latest_ver}" > "/usr/share/$NAME/core_local_ver" - [ -z "${non_restart}" ] && /etc/init.d/$NAME restart - - echo -e "Succeeded in updating core." > "/tmp/$NAME.log" - echo -e "Current core version: ${core_latest_ver}.\n" >> "/tmp/$NAME.log" -} - -case "$1" in - "update_core") - check_core_if_already_running - check_core_latest_version - ;; - "update_core_non_restart") - non_restart=1 - check_core_if_already_running - check_core_latest_version - ;; - "update_core_from_luci") - update_core_from_luci=1 - check_core_if_already_running - check_core_latest_version - ;; - *) - echo -e "Usage: ./update.sh update_core" - ;; -esac diff --git a/luci-app-unblockneteasemusic/views/view1.jpg b/luci-app-unblockneteasemusic/views/view1.jpg deleted file mode 100644 index ad5acca9e..000000000 Binary files a/luci-app-unblockneteasemusic/views/view1.jpg and /dev/null differ diff --git a/luci-app-unblockneteasemusic/views/view2.jpg b/luci-app-unblockneteasemusic/views/view2.jpg deleted file mode 100644 index da74790cb..000000000 Binary files a/luci-app-unblockneteasemusic/views/view2.jpg and /dev/null differ diff --git a/luci-app-unblockneteasemusic/views/view3.jpg b/luci-app-unblockneteasemusic/views/view3.jpg deleted file mode 100644 index 633154e0b..000000000 Binary files a/luci-app-unblockneteasemusic/views/view3.jpg and /dev/null differ diff --git a/luci-app-unblockneteasemusic/views/view4.jpg b/luci-app-unblockneteasemusic/views/view4.jpg deleted file mode 100644 index 7144b8a47..000000000 Binary files a/luci-app-unblockneteasemusic/views/view4.jpg and /dev/null differ