mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-11-01 09:23:56 +08:00
update 2026-05-11 18:57:00
This commit is contained in:
1 parent
14e58a8438
commit
8e46047008
44 files changed
+3037
-2431
No files matched your search
@@ -64,8 +64,8 @@ fi
|
||||
tolog "PLATFORM: [ ${PLATFORM} ]"
|
||||
sleep 2
|
||||
|
||||
# Read plugin branch from UCI config; default to "" (main-lua) when missing or empty
|
||||
# When amlogic_plugin_branch is missing, add it with empty value (main-lua default)
|
||||
# Read plugin branch from UCI config; default to "" (main-js) when missing or empty
|
||||
# When amlogic_plugin_branch is missing, add it with empty value (main-js default)
|
||||
if [[ -f "${AMLOGIC_CONFIG_FILE}" ]]; then
|
||||
plugin_branch="$(uci get amlogic.config.amlogic_plugin_branch 2>/dev/null | xargs)"
|
||||
if ! grep -q "amlogic_plugin_branch" "${AMLOGIC_CONFIG_FILE}" 2>/dev/null; then
|
||||
@@ -76,7 +76,7 @@ if [[ -f "${AMLOGIC_CONFIG_FILE}" ]]; then
|
||||
else
|
||||
plugin_branch=""
|
||||
fi
|
||||
tolog "Plugin branch: [ ${plugin_branch:-main-lua} ]"
|
||||
tolog "Plugin branch: [ ${plugin_branch:-main-js} ]"
|
||||
sleep 1
|
||||
get_plugin_info() {
|
||||
package_manager=""
|
||||
@@ -88,7 +88,8 @@ get_plugin_info() {
|
||||
local full_v
|
||||
full_v="$(opkg list-installed | grep '^luci-app-amlogic ' | awk '{print $3}')"
|
||||
current_plugin_v="$(echo "${full_v}" | cut -d'-' -f1)"
|
||||
current_plugin_release="$(echo "${full_v}" | cut -d'-' -f2)"
|
||||
# Strip optional "r" prefix from release (e.g. "r2" -> "2")
|
||||
current_plugin_release="$(echo "${full_v}" | cut -d'-' -f2 | sed 's/^r//')"
|
||||
elif command -v apk >/dev/null 2>&1; then
|
||||
package_manager="apk"
|
||||
# Package name e.g. "luci-app-amlogic-3.1.295-r2"
|
||||
@@ -113,11 +114,11 @@ check_plugin() {
|
||||
sleep 2
|
||||
|
||||
tolog "02. Start querying plugin version..."
|
||||
if [[ "${plugin_branch}" == "js" ]]; then
|
||||
if [[ "${plugin_branch}" == "lua" ]]; then
|
||||
latest_version="$(
|
||||
curl -fsSL -m 10 \
|
||||
https://github.com/ophub/luci-app-amlogic/releases |
|
||||
grep -oE 'expanded_assets/[0-9]+\.[0-9]+\.[0-9]+-js' | sed 's|expanded_assets/||g' |
|
||||
grep -oE 'expanded_assets/[0-9]+\.[0-9]+\.[0-9]+-lua' | sed 's|expanded_assets/||g' |
|
||||
sort -urV | head -n 1
|
||||
)"
|
||||
else
|
||||
@@ -125,7 +126,7 @@ check_plugin() {
|
||||
curl -fsSL -m 10 \
|
||||
https://github.com/ophub/luci-app-amlogic/releases |
|
||||
grep -oE 'expanded_assets/[0-9]+\.[0-9]+\.[0-9]+' | sed 's|expanded_assets/||g' |
|
||||
grep -v '\-js' |
|
||||
grep -v '\-lua' |
|
||||
sort -urV | head -n 1
|
||||
)"
|
||||
fi
|
||||
@@ -136,16 +137,16 @@ check_plugin() {
|
||||
tolog "02.01 Current version: ${current_plugin_v}, Latest version: ${latest_version}"
|
||||
sleep 2
|
||||
|
||||
# Strip variant suffix (e.g. "-js") from latest_version to get the numeric part.
|
||||
# Strip variant suffix (e.g. "-lua") from latest_version to get the numeric part.
|
||||
latest_version_base="${latest_version%%-*}"
|
||||
|
||||
# Determine target PKG_RELEASE for the selected branch:
|
||||
# js branch -> release 2
|
||||
# lua branch -> release 1
|
||||
if [[ "${plugin_branch}" == "js" ]]; then
|
||||
target_release="2"
|
||||
else
|
||||
# js branch (default) -> release 2
|
||||
# lua branch -> release 1
|
||||
if [[ "${plugin_branch}" == "lua" ]]; then
|
||||
target_release="1"
|
||||
else
|
||||
target_release="2"
|
||||
fi
|
||||
|
||||
# Only report "already latest" when BOTH the version number AND the installed
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"admin/system/amlogic": {
|
||||
"title": "Amlogic Service",
|
||||
"order": 88,
|
||||
"action": {
|
||||
"type": "firstchild"
|
||||
},
|
||||
"depends": {
|
||||
"acl": [ "luci-app-amlogic" ],
|
||||
"fs": { "/etc/config/amlogic": "file" }
|
||||
}
|
||||
},
|
||||
|
||||
"admin/system/amlogic/info": {
|
||||
"title": "Amlogic Service",
|
||||
"order": 1,
|
||||
"action": { "type": "view", "path": "amlogic/info" }
|
||||
},
|
||||
|
||||
"admin/system/amlogic/install": {
|
||||
"title": "Install OpenWrt",
|
||||
"order": 2,
|
||||
"action": { "type": "view", "path": "amlogic/install" },
|
||||
"depends": {
|
||||
"uci": { "amlogic": { "config": { "menu_install": "yes" } } }
|
||||
}
|
||||
},
|
||||
|
||||
"admin/system/amlogic/upload": {
|
||||
"title": "Manually Upload Update",
|
||||
"order": 3,
|
||||
"action": { "type": "view", "path": "amlogic/upload" }
|
||||
},
|
||||
|
||||
"admin/system/amlogic/check": {
|
||||
"title": "Online Download Update",
|
||||
"order": 4,
|
||||
"action": { "type": "view", "path": "amlogic/check" }
|
||||
},
|
||||
|
||||
"admin/system/amlogic/backup": {
|
||||
"title": "Backup Firmware Config",
|
||||
"order": 5,
|
||||
"action": { "type": "view", "path": "amlogic/backup" }
|
||||
},
|
||||
|
||||
"admin/system/amlogic/backuplist": {
|
||||
"action": { "type": "view", "path": "amlogic/backuplist" }
|
||||
},
|
||||
|
||||
"admin/system/amlogic/armcpu": {
|
||||
"title": "CPU Settings",
|
||||
"order": 6,
|
||||
"action": { "type": "view", "path": "amlogic/armcpu" },
|
||||
"depends": {
|
||||
"uci": { "amlogic": { "config": { "menu_armcpu": "yes" } } }
|
||||
}
|
||||
},
|
||||
|
||||
"admin/system/amlogic/config": {
|
||||
"title": "Plugin Settings",
|
||||
"order": 7,
|
||||
"action": { "type": "view", "path": "amlogic/config" }
|
||||
},
|
||||
|
||||
"admin/system/amlogic/log": {
|
||||
"title": "Server Logs",
|
||||
"order": 8,
|
||||
"action": { "type": "view", "path": "amlogic/log" }
|
||||
},
|
||||
|
||||
"admin/system/amlogic/poweroff": {
|
||||
"title": "PowerOff",
|
||||
"order": 9,
|
||||
"action": { "type": "view", "path": "amlogic/poweroff" }
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,75 @@
|
||||
{
|
||||
"luci-app-amlogic": {
|
||||
"description": "Grant UCI access for luci-app-amlogic",
|
||||
"description": "Grant UCI/file/RPC access for the Amlogic Service plugin",
|
||||
"read": {
|
||||
"uci": [ "amlogic" ]
|
||||
"ubus": {
|
||||
"luci.amlogic": [
|
||||
"state",
|
||||
"author",
|
||||
"model_database",
|
||||
"platform_info",
|
||||
"snapshot_list",
|
||||
"check_upfiles",
|
||||
"upload_path",
|
||||
"list_uploads",
|
||||
"read_log_tail",
|
||||
"read_log_full",
|
||||
"cpu_policies"
|
||||
]
|
||||
},
|
||||
"uci": [ "amlogic" ],
|
||||
"file": {
|
||||
"/tmp/amlogic/amlogic.log": [ "read" ],
|
||||
"/tmp/amlogic/amlogic_check_install.log": [ "read" ],
|
||||
"/tmp/amlogic/amlogic_check_upfiles.log": [ "read" ],
|
||||
"/tmp/amlogic/amlogic_check_plugin.log": [ "read" ],
|
||||
"/tmp/amlogic/amlogic_check_kernel.log": [ "read" ],
|
||||
"/tmp/amlogic/amlogic_check_firmware.log": [ "read" ],
|
||||
"/tmp/amlogic/amlogic_check_rescue.log": [ "read" ],
|
||||
"/tmp/amlogic/amlogic_running_script.log": [ "read" ],
|
||||
"/etc/amlogic_backup_list.conf": [ "read" ],
|
||||
"/etc/flippy-openwrt-release": [ "read" ],
|
||||
"/etc/model_database.txt": [ "read" ],
|
||||
"/.reserved/openwrt_config.tar.gz": [ "read" ]
|
||||
}
|
||||
},
|
||||
"write": {
|
||||
"uci": [ "amlogic" ]
|
||||
"ubus": {
|
||||
"luci.amlogic": [
|
||||
"snapshot_create",
|
||||
"snapshot_delete",
|
||||
"snapshot_restore",
|
||||
"check_plugin",
|
||||
"check_kernel",
|
||||
"check_firmware",
|
||||
"start_plugin",
|
||||
"start_kernel",
|
||||
"start_update",
|
||||
"start_install",
|
||||
"start_rescue",
|
||||
"del_log",
|
||||
"poweroff",
|
||||
"kvm_switch",
|
||||
"delete_upload",
|
||||
"install_upload",
|
||||
"upload_chunk",
|
||||
"backup_create",
|
||||
"save_backup_list",
|
||||
"prime_backup_list",
|
||||
"reload_cpu",
|
||||
"sync_menu"
|
||||
]
|
||||
},
|
||||
"uci": [ "amlogic" ],
|
||||
"file": {
|
||||
"/etc/amlogic_backup_list.conf": [ "write" ],
|
||||
"/tmp/upload/*": [ "write" ],
|
||||
"/tmp/amlogic/*": [ "write" ],
|
||||
"/mnt/mmcblk*p4/*": [ "write" ],
|
||||
"/mnt/sd*4/*": [ "write" ],
|
||||
"/mnt/hd*4/*": [ "write" ],
|
||||
"/mnt/vd*4/*": [ "write" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,759 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// luci.amlogic - ucode RPC bridge for the JS-based luci-app-amlogic.
|
||||
//
|
||||
// Helpers
|
||||
'use strict';
|
||||
|
||||
import { popen, readfile, writefile, mkstemp, stat, glob, error as fserror,
|
||||
unlink, mkdir, access, open as fsopen } from 'fs';
|
||||
|
||||
const LOG_DIR = '/tmp/amlogic';
|
||||
const LOG_FILE = LOG_DIR + '/amlogic.log';
|
||||
const LOG_RUNNING = LOG_DIR + '/amlogic_running_script.log';
|
||||
const LOG_INSTALL = LOG_DIR + '/amlogic_check_install.log';
|
||||
const LOG_UPFILES = LOG_DIR + '/amlogic_check_upfiles.log';
|
||||
const LOG_PLUGIN = LOG_DIR + '/amlogic_check_plugin.log';
|
||||
const LOG_KERNEL = LOG_DIR + '/amlogic_check_kernel.log';
|
||||
const LOG_FIRMWARE = LOG_DIR + '/amlogic_check_firmware.log';
|
||||
const LOG_RESCUE = LOG_DIR + '/amlogic_check_rescue.log';
|
||||
const UPLOAD_TMP = '/tmp/upload';
|
||||
const PKG_NAME = 'luci-app-amlogic';
|
||||
const BACKUP_LIST = '/etc/amlogic_backup_list.conf';
|
||||
|
||||
// Map of safe log names -> file paths (for read_log_tail/read_log_full)
|
||||
const LOG_MAP = {
|
||||
'main': LOG_FILE,
|
||||
'install': LOG_INSTALL,
|
||||
'upfiles': LOG_UPFILES,
|
||||
'plugin': LOG_PLUGIN,
|
||||
'kernel': LOG_KERNEL,
|
||||
'firmware': LOG_FIRMWARE,
|
||||
'rescue': LOG_RESCUE,
|
||||
'running': LOG_RUNNING
|
||||
};
|
||||
|
||||
// Run a shell command, return trimmed stdout
|
||||
function sh(cmd) {
|
||||
const p = popen(cmd, 'r');
|
||||
if (!p) return '';
|
||||
const out = p.read('all') ?? '';
|
||||
p.close();
|
||||
return trim(out);
|
||||
}
|
||||
|
||||
// Run a shell command, return exit code (0 on success)
|
||||
function shcall(cmd) {
|
||||
// `sh -c "...; echo $?"` — last line is exit code.
|
||||
const out = sh('(' + cmd + ') >/dev/null 2>&1; echo $?');
|
||||
const lines = split(out, '\n');
|
||||
const last = lines[length(lines) - 1] ?? '1';
|
||||
return int(last);
|
||||
}
|
||||
|
||||
// Run a shell command in the background (fire-and-forget).
|
||||
// Returns immediately so rpcd is not blocked, allowing concurrent
|
||||
// read_log_tail / read_log_full polls to succeed.
|
||||
function shbg(cmd) {
|
||||
// Detach from rpcd: close stdin so interactive prompts don't block,
|
||||
// but let the command manage its own stdout/stderr (e.g. redirect to log).
|
||||
const wrapper = '(' + cmd + ') </dev/null &';
|
||||
const p = popen(wrapper, 'r');
|
||||
if (p) p.close();
|
||||
}
|
||||
|
||||
// Shell-quote a string for embedding into a /bin/sh command line
|
||||
function shq(s) {
|
||||
return "'" + replace(s ?? '', "'", "'\\''") + "'";
|
||||
}
|
||||
|
||||
// Ensure the runtime tmp dirs exist (mirrors the luci.sys.exec calls in the
|
||||
// original controller's index() function).
|
||||
function ensure_dirs() {
|
||||
mkdir(LOG_DIR);
|
||||
mkdir(UPLOAD_TMP);
|
||||
}
|
||||
|
||||
// Read flippy-openwrt-release platform identifier
|
||||
function flippy_var(name) {
|
||||
return sh("cat /etc/flippy-openwrt-release 2>/dev/null | grep " + shq(name) +
|
||||
" | awk -F= '{print $2}' | tr -d '\"' | xargs");
|
||||
}
|
||||
|
||||
function platform() {
|
||||
const v = flippy_var('PLATFORM');
|
||||
const m = match(v, /(amlogic|rockchip|allwinner|qemu)/);
|
||||
return m ? m[1] : 'Unknown';
|
||||
}
|
||||
|
||||
function show_install_menu() {
|
||||
const v = flippy_var('SHOW_INSTALL_MENU');
|
||||
const m = match(v, /(yes|no)/);
|
||||
return m ? m[1] : 'Unknown';
|
||||
}
|
||||
|
||||
// Pick the helper script names for the current platform (as the original
|
||||
// controller did).
|
||||
function platform_scripts() {
|
||||
const p = platform();
|
||||
if (index(p, 'rockchip') >= 0)
|
||||
return { install: '', update: 'openwrt-update-rockchip', kernel: 'openwrt-kernel' };
|
||||
if (index(p, 'allwinner') >= 0)
|
||||
return { install: 'openwrt-install-allwinner', update: 'openwrt-update-allwinner', kernel: 'openwrt-kernel' };
|
||||
if (index(p, 'qemu') >= 0)
|
||||
return { install: '', update: 'openwrt-update-kvm', kernel: 'openwrt-kernel' };
|
||||
return { install: 'openwrt-install-amlogic', update: 'openwrt-update-amlogic', kernel: 'openwrt-kernel' };
|
||||
}
|
||||
|
||||
// Read an option from the [config] section of /etc/config/amlogic
|
||||
function uci_cfg(opt) {
|
||||
return sh('uci -q get amlogic.config.' + opt);
|
||||
}
|
||||
|
||||
// --- Version helpers (identical logic to controller's *_version() funcs) ---
|
||||
function current_firmware_version() {
|
||||
const v = sh("uname -r 2>/dev/null | grep -oE '^[1-9]\\.[0-9]{1,3}\\.[0-9]+'");
|
||||
return v != '' ? v : 'Invalid value.';
|
||||
}
|
||||
function current_kernel_version() { return current_firmware_version(); }
|
||||
function current_kernel_branch() {
|
||||
const def = sh("uname -r 2>/dev/null | grep -oE '^[1-9]\\.[0-9]{1,3}'");
|
||||
const cfg = sh("uci -q get amlogic.config.amlogic_kernel_branch | grep -oE '^[1-9]\\.[0-9]{1,3}'");
|
||||
return cfg != '' ? cfg : def;
|
||||
}
|
||||
function current_plugin_version() {
|
||||
let v = '';
|
||||
if (shcall('command -v opkg') == 0)
|
||||
v = sh("opkg list-installed | grep '^" + PKG_NAME + "' | awk '{print $3}' | cut -d'-' -f1");
|
||||
if (v == '' && shcall('command -v apk') == 0)
|
||||
v = sh("apk list --installed 2>/dev/null | grep '^" + PKG_NAME + "' | awk '{print $1}' | cut -d'-' -f4");
|
||||
return v != '' ? v : 'Invalid value.';
|
||||
}
|
||||
|
||||
// --- Config-driven flags used when invoking helper scripts ---
|
||||
function update_restore_config() {
|
||||
const v = uci_cfg('amlogic_firmware_config');
|
||||
return (v == '' || int(v) != 0) ? 'restore' : 'no-restore';
|
||||
}
|
||||
function auto_write_bootloader() {
|
||||
const v = uci_cfg('amlogic_write_bootloader');
|
||||
return (v == '' || int(v) != 0) ? 'yes' : 'no';
|
||||
}
|
||||
function auto_shared_fstype() {
|
||||
const v = trim(uci_cfg('amlogic_shared_fstype'));
|
||||
return v != '' ? v : 'ext4';
|
||||
}
|
||||
|
||||
// Read tail / full content of a known log file
|
||||
function _safe_log_path(name) {
|
||||
return LOG_MAP[name] ?? null;
|
||||
}
|
||||
function read_log_tail(name) {
|
||||
const p = _safe_log_path(name);
|
||||
if (!p) return '';
|
||||
const pipe = popen('cat ' + p + ' 2>/dev/null | tail -c 4096', 'r');
|
||||
if (!pipe) return '';
|
||||
const content = pipe.read('all') ?? '';
|
||||
pipe.close();
|
||||
if (!content) return '';
|
||||
// Find the last non-empty line
|
||||
const lines = split(content, '\n');
|
||||
for (let i = length(lines) - 1; i >= 0; i--) {
|
||||
const line = trim(lines[i]);
|
||||
if (line !== '') return line;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
function read_log_full(name) {
|
||||
const p = _safe_log_path(name ?? 'main');
|
||||
if (!p) return '';
|
||||
// Use popen+cat for consistency with read_log_tail; readfile() may be
|
||||
// stale inside the long-lived rpcd ucode process.
|
||||
const pipe = popen('cat ' + p + ' 2>/dev/null', 'r');
|
||||
if (!pipe) return '';
|
||||
const t = pipe.read('all') ?? '';
|
||||
pipe.close();
|
||||
return t;
|
||||
}
|
||||
|
||||
// Lazily seed the main log on first read (matches the Lua action_refresh_log
|
||||
// behaviour: when the log is missing, populate it with `uname -a`).
|
||||
function ensure_main_log() {
|
||||
ensure_dirs();
|
||||
if (!access(LOG_FILE)) {
|
||||
shcall("uname -a > " + LOG_FILE);
|
||||
let _logs1 = [LOG_INSTALL, LOG_UPFILES, LOG_PLUGIN, LOG_KERNEL,
|
||||
LOG_FIRMWARE, LOG_RESCUE, LOG_RUNNING];
|
||||
for (let i = 0; i < length(_logs1); i++)
|
||||
writefile(_logs1[i], '');
|
||||
}
|
||||
}
|
||||
|
||||
// Helper: clear (truncate) a file
|
||||
function clear(path) { writefile(path, ''); }
|
||||
|
||||
// Cast/sanitise an `amlogic_install_sel` token: form is
|
||||
// "<soc_id>@<dtb>:<socname>:<ubootname>" (from old install view)
|
||||
// The Lua original passed res[2] verbatim (colon-string) to the install
|
||||
// script as the dtb_filename argument when soc_id == 99.
|
||||
function parse_install_sel(s) {
|
||||
const parts = split(s ?? '', '@');
|
||||
const soc_id = (parts[0] ?? '99');
|
||||
let dtb = 'auto_dtb';
|
||||
if (int(parts[0]) == 99 && length(parts) > 1 && parts[1] != '')
|
||||
dtb = parts[1];
|
||||
return { soc_id, dtb };
|
||||
}
|
||||
|
||||
// Helper: parse `amlogic_update_sel` form
|
||||
// "<firmware_name>@<updated>@<write_path>"
|
||||
function parse_update_sel(s) {
|
||||
const a = split(s ?? '', '@');
|
||||
return {
|
||||
name: a[0] ?? 'auto',
|
||||
updated: a[1] ?? 'updated',
|
||||
path: a[2] ?? '/tmp'
|
||||
};
|
||||
}
|
||||
|
||||
// === ubus method bodies ===
|
||||
|
||||
function m_state() {
|
||||
return {
|
||||
current_firmware_version: current_firmware_version(),
|
||||
current_plugin_version: current_plugin_version(),
|
||||
current_kernel_version: current_kernel_version(),
|
||||
current_kernel_branch: current_kernel_branch(),
|
||||
kernel_release: sh('uname -r')
|
||||
};
|
||||
}
|
||||
|
||||
function m_author() {
|
||||
const r = uci_cfg('amlogic_firmware_repo');
|
||||
return { openwrt_author: r != '' ? r : 'Invalid value.' };
|
||||
}
|
||||
|
||||
function m_platform_info() {
|
||||
const p = platform();
|
||||
const m = show_install_menu();
|
||||
const has_kvm = access('/boot/efi/EFI/BOOT/grub.cfg.prev') ? true : false;
|
||||
// can_install: amlogic or allwinner have an install script; also forced by SHOW_INSTALL_MENU=yes
|
||||
const can_install = (index(p, 'amlogic') >= 0 || index(p, 'allwinner') >= 0 || index(m, 'yes') >= 0);
|
||||
// can_armcpu: all platforms except qemu support CPU frequency settings
|
||||
const can_armcpu = (index(p, 'qemu') < 0);
|
||||
// is_installed: root fs is on an internal storage device (mmcblk/sd/hd/vd),
|
||||
// meaning OpenWrt has already been installed to eMMC/NVMe/disk. When true,
|
||||
// the Install OpenWrt menu should be hidden.
|
||||
const root_pt = sh("df / | tail -n1 | awk '{print $1}' | awk -F '/' '{print $3}'");
|
||||
const is_installed = (root_pt != '' &&
|
||||
(match(root_pt, /^mmcblk[0-9]+p[1-4]$/) ||
|
||||
match(root_pt, /^[hsv]d[a-z][0-9]+$/) ||
|
||||
match(root_pt, /^nvme[0-9]+n[0-9]+p[0-9]+$/)));
|
||||
return {
|
||||
platform: p,
|
||||
install_menu: m,
|
||||
can_install,
|
||||
can_armcpu,
|
||||
has_kvm,
|
||||
is_installed: is_installed ? true : false
|
||||
};
|
||||
}
|
||||
|
||||
function m_model_database() {
|
||||
const p = platform();
|
||||
let pat;
|
||||
if (index(p, 'allwinner') >= 0)
|
||||
pat = "^w[0-9]{1,9}.*:";
|
||||
else
|
||||
pat = "^[0-9]{1,9}.*:";
|
||||
const out = sh("cat /etc/model_database.txt 2>/dev/null | grep -E " + shq(pat) +
|
||||
" | awk -F ':' '{print $1\"###\"$2}' | tr ' ' '~'");
|
||||
const entries = [];
|
||||
for (let line in split(out, '\n')) {
|
||||
const t = trim(line);
|
||||
if (t == '') continue;
|
||||
const kv = split(t, '###');
|
||||
if (length(kv) >= 2)
|
||||
push(entries, { id: trim(kv[0]), name: replace(trim(kv[1]), '~', ' ') });
|
||||
}
|
||||
return { entries };
|
||||
}
|
||||
|
||||
function m_snapshot_list() {
|
||||
const out = sh("btrfs subvolume list -rt / 2>/dev/null | awk '{print $4}' | grep .snapshots");
|
||||
const names = [];
|
||||
for (let l in split(out, '\n')) {
|
||||
const n = replace(trim(l), '.snapshots/', '');
|
||||
if (n != '') push(names, n);
|
||||
}
|
||||
return { names };
|
||||
}
|
||||
|
||||
// Mirrors the Lua "Edit List" button's side-effect: if the backup-list file is
|
||||
// missing or empty, pre-populate it from the BACKUP_LIST shell variable inside
|
||||
// /usr/sbin/openwrt-backup.
|
||||
function m_prime_backup_list() {
|
||||
shcall("[ -s " + BACKUP_LIST + " ] || sed -n \"/BACKUP_LIST='/,/.*'$/p\" /usr/sbin/openwrt-backup | sed -e \"s/BACKUP_LIST=\\(.*\\)/\\1/; s/'//g; s/\\\\\\\\//g; s/ //g\" > " + BACKUP_LIST + " 2>/dev/null");
|
||||
return { code: 0 };
|
||||
}
|
||||
|
||||
// Create a read-only snapshot of /etc into /.snapshots/etc-<MM.DD.HHMMSS>.
|
||||
// Mirrors the `Create Snapshot` button in amlogic_backup.lua.
|
||||
function m_snapshot_create() {
|
||||
shcall("btrfs subvolume snapshot -r /etc /.snapshots/etc-$(date +%m.%d.%H%M%S) && sync");
|
||||
return { code: 0 };
|
||||
}
|
||||
|
||||
function m_snapshot_delete(req) {
|
||||
const n = req.args?.name ?? '';
|
||||
if (!match(n, /^[A-Za-z0-9._-]+$/))
|
||||
return { code: 1, error: 'invalid name' };
|
||||
const rc = shcall("btrfs subvolume delete -c /.snapshots/etc-" + n + " && sync");
|
||||
return { code: rc };
|
||||
}
|
||||
|
||||
function m_snapshot_restore(req) {
|
||||
const n = req.args?.name ?? '';
|
||||
if (!match(n, /^[A-Za-z0-9._-]+$/))
|
||||
return { error: 'invalid name' };
|
||||
shcall("btrfs subvolume snapshot /.snapshots/etc-" + n + " /etc && sync");
|
||||
// trigger a reboot like the Lua version (echo b > /proc/sysrq-trigger)
|
||||
shcall("(sleep 1 && echo b > /proc/sysrq-trigger) &");
|
||||
return { code: 0 };
|
||||
}
|
||||
|
||||
function m_check_plugin(req) {
|
||||
ensure_dirs();
|
||||
const opt = req.args?.options ?? 'check';
|
||||
writefile(LOG_PLUGIN, '');
|
||||
shcall('chmod +x /usr/share/amlogic/amlogic_check_plugin.sh');
|
||||
if (opt === 'check') {
|
||||
shbg('/usr/share/amlogic/amlogic_check_plugin.sh -check');
|
||||
return { code: 0 };
|
||||
}
|
||||
// download option: e.g. "download_3.1.290" — pass verbatim to the script
|
||||
shbg('/usr/share/amlogic/amlogic_check_plugin.sh -download ' + shq(opt));
|
||||
return { code: 0 };
|
||||
}
|
||||
|
||||
function m_check_kernel(req) {
|
||||
ensure_dirs();
|
||||
const opt = req.args?.options ?? 'check';
|
||||
writefile(LOG_KERNEL, '');
|
||||
shcall('chmod +x /usr/share/amlogic/amlogic_check_kernel.sh');
|
||||
if (opt == 'check') {
|
||||
shbg('/usr/share/amlogic/amlogic_check_kernel.sh -check');
|
||||
return { code: 0 };
|
||||
}
|
||||
// download option: pass the full param string directly to the script
|
||||
// (it may contain underscores, dots, and digits — safe to pass verbatim
|
||||
// since shbg wraps the whole command in single-quoted sh -c)
|
||||
shbg('/usr/share/amlogic/amlogic_check_kernel.sh -download ' + shq(opt));
|
||||
return { code: 0 };
|
||||
}
|
||||
|
||||
function m_check_firmware(req) {
|
||||
ensure_dirs();
|
||||
const opt = req.args?.options ?? 'check';
|
||||
writefile(LOG_FIRMWARE, '');
|
||||
shcall('chmod +x /usr/share/amlogic/amlogic_check_firmware.sh');
|
||||
if (opt == 'check') {
|
||||
shbg('/usr/share/amlogic/amlogic_check_firmware.sh -check');
|
||||
return { code: 0 };
|
||||
}
|
||||
// download option: may contain @, /, dots, etc. — pass via shq
|
||||
shbg('/usr/share/amlogic/amlogic_check_firmware.sh -download ' + shq(opt));
|
||||
return { code: 0 };
|
||||
}
|
||||
|
||||
function m_start_plugin() {
|
||||
ensure_dirs();
|
||||
const cfg = '/etc/config/amlogic';
|
||||
const cfg_bak = '/etc/config/amlogic_bak';
|
||||
const script_path = LOG_DIR + '/amlogic_install_plugin.sh';
|
||||
writefile(LOG_RUNNING, '1@Plugin update in progress, try again later!\n');
|
||||
writefile(LOG_PLUGIN, '');
|
||||
// Write install script to a file so shbg (which redirects stdin from
|
||||
// /dev/null) can execute it — heredoc via shbg does not work because
|
||||
// shbg closes stdin before sh can read the here-document.
|
||||
const script = '#!/bin/sh\n'
|
||||
+ 'LOG=' + shq(LOG_PLUGIN) + '\n'
|
||||
+ 'LOG_RUNNING=' + shq(LOG_RUNNING) + '\n'
|
||||
+ 'cfg=' + shq(cfg) + '\n'
|
||||
+ 'cfg_bak=' + shq(cfg_bak) + '\n'
|
||||
+ '[ -f "$cfg" ] && cp -f "$cfg" "$cfg_bak"\n'
|
||||
+ 'if command -v opkg >/dev/null 2>&1; then\n'
|
||||
+ ' echo "System uses opkg." >> "$LOG"\n'
|
||||
+ ' opkg --force-reinstall --force-downgrade install /tmp/amlogic/*.ipk >> "$LOG" 2>&1\n'
|
||||
+ ' rc=$?\n'
|
||||
+ 'elif command -v apk >/dev/null 2>&1; then\n'
|
||||
+ ' echo "System uses apk." >> "$LOG"\n'
|
||||
+ ' apk add --force-overwrite --allow-untrusted /tmp/amlogic/*.apk >> "$LOG" 2>&1\n'
|
||||
+ ' rc=$?\n'
|
||||
+ 'else\n'
|
||||
+ ' echo "Error: No package manager." >> "$LOG"\n'
|
||||
+ ' rc=1\n'
|
||||
+ 'fi\n'
|
||||
+ 'if [ "$rc" = "0" ]; then\n'
|
||||
+ ' [ -f "$cfg_bak" ] && cp -f "$cfg_bak" "$cfg"\n'
|
||||
+ ' rm -f /etc/config/amlogic.apk-new /etc/config/amlogic.ipk-old\n'
|
||||
+ ' rm -rf /tmp/luci-indexcache /tmp/luci-modulecache/* "$cfg_bak"\n'
|
||||
+ ' echo "" > "$LOG_RUNNING"\n'
|
||||
+ ' echo "Successful Update" > "$LOG"\n'
|
||||
+ ' # Cross-branch cleanup: run in background after a delay so the browser\n'
|
||||
+ ' # can poll "Successful Update" before any files are removed.\n'
|
||||
+ ' (sleep 3\n'
|
||||
+ ' new_release=""\n'
|
||||
+ ' if command -v opkg >/dev/null 2>&1; then\n'
|
||||
+ ' _raw="$(opkg list-installed | grep \'^luci-app-amlogic \' | awk \'{print $3}\' | cut -d\'-\' -f2)"\n'
|
||||
+ ' new_release="${_raw#r}"\n'
|
||||
+ ' elif command -v apk >/dev/null 2>&1; then\n'
|
||||
+ ' new_release="$(apk list --installed 2>/dev/null | grep \'^luci-app-amlogic-\' | awk \'{print $1}\' | cut -d\'-\' -f5 | sed \'s/^r//\')"\n'
|
||||
+ ' fi\n'
|
||||
+ ' if [ "${new_release}" = "2" ]; then\n'
|
||||
+ ' rm -f /usr/lib/lua/luci/controller/amlogic.lua\n'
|
||||
+ ' rm -rf /usr/lib/lua/luci/model/cbi/amlogic\n'
|
||||
+ ' rm -rf /usr/lib/lua/luci/view/amlogic\n'
|
||||
+ ' elif [ "${new_release}" = "1" ]; then\n'
|
||||
+ ' rm -f /usr/share/rpcd/ucode/luci.amlogic\n'
|
||||
+ ' rm -f /www/luci-static/resources/view/amlogic/*.js\n'
|
||||
+ ' rm -f /usr/share/luci/menu.d/luci-app-amlogic.json\n'
|
||||
+ ' fi) &\n'
|
||||
+ 'else\n'
|
||||
+ ' echo "--- INSTALLATION FAILED! ---" >> "$LOG"\n'
|
||||
+ ' [ -f "$cfg_bak" ] && cp -f "$cfg_bak" "$cfg"\n'
|
||||
+ ' rm -f "$cfg_bak"\n'
|
||||
+ ' echo "" > "$LOG_RUNNING"\n'
|
||||
+ 'fi\n';
|
||||
writefile(script_path, script);
|
||||
shbg('sh ' + shq(script_path));
|
||||
return { code: 0 };
|
||||
}
|
||||
|
||||
function m_start_kernel() {
|
||||
ensure_dirs();
|
||||
const sc = platform_scripts();
|
||||
writefile(LOG_RUNNING, '2@Kernel update in progress, try again later!\n');
|
||||
shcall('chmod +x /usr/sbin/' + sc.kernel);
|
||||
shbg('/usr/sbin/' + sc.kernel + ' ' + auto_write_bootloader() + ' > ' + LOG_KERNEL + ' 2>&1 && sync && echo "" > ' + LOG_RUNNING);
|
||||
return { code: 0 };
|
||||
}
|
||||
|
||||
function m_start_update(req) {
|
||||
ensure_dirs();
|
||||
const sc = platform_scripts();
|
||||
writefile(LOG_RUNNING, '3@OpenWrt update in progress, try again later!\n');
|
||||
shcall('chmod +x /usr/sbin/' + sc.update);
|
||||
const u = parse_update_sel(req.args?.amlogic_update_sel);
|
||||
shcall('mkdir -p ' + shq(u.path + '/.luci-app-amlogic'));
|
||||
shcall('echo ' + shq(u.updated) + ' > ' + shq(u.path + '/.luci-app-amlogic/op_release_code') + ' && sync');
|
||||
shbg('/usr/sbin/' + sc.update + ' ' + shq(u.name) + ' ' +
|
||||
auto_write_bootloader() + ' ' + update_restore_config() +
|
||||
' > ' + LOG_FIRMWARE + ' 2>&1 && sync && echo "" > ' + LOG_RUNNING);
|
||||
return { code: 0 };
|
||||
}
|
||||
|
||||
function m_start_install(req) {
|
||||
ensure_dirs();
|
||||
const sc = platform_scripts();
|
||||
if (sc.install == '') return { error: 'install not supported on platform' };
|
||||
shcall('chmod +x /usr/sbin/' + sc.install);
|
||||
const i = parse_install_sel(req.args?.amlogic_install_sel);
|
||||
if (!match(i.soc_id, /^[0-9]+$/) || !match(i.dtb, /^[A-Za-z0-9._:-]+$/))
|
||||
return { error: 'invalid install sel' };
|
||||
writefile(LOG_INSTALL, '');
|
||||
shbg('/usr/sbin/' + sc.install + ' ' + auto_write_bootloader() + ' ' +
|
||||
i.soc_id + ' ' + i.dtb + ' ' + auto_shared_fstype() +
|
||||
' > ' + LOG_INSTALL + ' 2>&1 && sync');
|
||||
return { code: 0 };
|
||||
}
|
||||
|
||||
function m_start_rescue() {
|
||||
ensure_dirs();
|
||||
const sc = platform_scripts();
|
||||
writefile(LOG_RUNNING, '4@Kernel rescue in progress, try again later!\n');
|
||||
shcall('chmod +x /usr/sbin/' + sc.kernel);
|
||||
shbg('/usr/sbin/' + sc.kernel + ' -s > ' + LOG_RESCUE + ' 2>&1 && sync && echo "" > ' + LOG_RUNNING);
|
||||
return { code: 0 };
|
||||
}
|
||||
|
||||
function m_read_log_tail(req) {
|
||||
return { line: read_log_tail(req.args?.name ?? '') };
|
||||
}
|
||||
|
||||
function m_read_log_full(req) {
|
||||
ensure_main_log();
|
||||
return { content: read_log_full(req.args?.name ?? 'main') };
|
||||
}
|
||||
|
||||
function m_del_log() {
|
||||
let _logs2 = [LOG_FILE, LOG_INSTALL, LOG_UPFILES, LOG_PLUGIN, LOG_KERNEL,
|
||||
LOG_FIRMWARE, LOG_RESCUE, LOG_RUNNING];
|
||||
for (let i = 0; i < length(_logs2); i++)
|
||||
writefile(_logs2[i], '');
|
||||
return { code: 0 };
|
||||
}
|
||||
|
||||
function m_poweroff() {
|
||||
shcall('(sleep 1 && /sbin/poweroff) &');
|
||||
return { code: 0 };
|
||||
}
|
||||
|
||||
function m_kvm_switch() {
|
||||
shcall('[ -f /boot/efi/EFI/BOOT/grub.cfg.prev ] && (cd /boot/efi/EFI/BOOT/ && ' +
|
||||
'mv -f grub.cfg grub.cfg.bak && mv -f grub.cfg.prev grub.cfg && ' +
|
||||
'mv -f grub.cfg.bak grub.cfg.prev)');
|
||||
shcall('(sync && sleep 1 && reboot) &');
|
||||
return { code: 0 };
|
||||
}
|
||||
|
||||
function m_check_upfiles() {
|
||||
const t = readfile(LOG_UPFILES) ?? '';
|
||||
return { value: trim(t) };
|
||||
}
|
||||
|
||||
// Pick upload directory using exactly the same heuristic as the Lua version
|
||||
function compute_upload_path() {
|
||||
const root_pt = sh("df / | tail -n1 | awk '{print $1}' | awk -F '/' '{print $3}'");
|
||||
if (root_pt != '' && match(root_pt, /^mmcblk[0-4]p[1-4]$/)) {
|
||||
const emmc = sh('echo ' + shq(root_pt) + " | awk '{print substr($1,1,length($1)-2)}'");
|
||||
return '/mnt/' + emmc + 'p4/';
|
||||
}
|
||||
if (root_pt != '' && match(root_pt, /^[hsv]d[a-z][0-9]+$/)) {
|
||||
const emmc = sh('echo ' + shq(root_pt) + " | awk '{print substr($1,1,length($1)-1)}'");
|
||||
return '/mnt/' + emmc + '4/';
|
||||
}
|
||||
return '/tmp/upload/';
|
||||
}
|
||||
|
||||
function m_upload_path() {
|
||||
const p = compute_upload_path();
|
||||
mkdir(p);
|
||||
return { path: p };
|
||||
}
|
||||
|
||||
function _human_size(n) {
|
||||
const units = [' kB', ' MB', ' GB', ' TB'];
|
||||
let i = -1;
|
||||
let s = +n;
|
||||
while (s > 1024 && i < length(units) - 1) {
|
||||
s = s / 1024;
|
||||
i++;
|
||||
}
|
||||
if (i < 0) { s = n / 1024; i = 0; }
|
||||
return sprintf('%.1f', s) + units[i];
|
||||
}
|
||||
|
||||
function m_list_uploads() {
|
||||
const dir = compute_upload_path();
|
||||
mkdir(dir);
|
||||
const items = [];
|
||||
let firmware = false, boot = false, dtb = false, modules = false, cfg = false;
|
||||
const files = glob(dir + '*') ?? [];
|
||||
for (let f in files) {
|
||||
const st = stat(f);
|
||||
if (!st || st.type != 'file') continue;
|
||||
const base = replace(f, /^.*\//, '');
|
||||
const lcname = lc(base);
|
||||
if (match(lcname, /\.img\.gz$/) || match(lcname, /\.img\.xz$/) ||
|
||||
match(lcname, /\.7z$/) || match(lcname, /\.img$/))
|
||||
firmware = true;
|
||||
if (match(lcname, /^boot-/)) boot = true;
|
||||
if (match(lcname, /^dtb-/)) dtb = true;
|
||||
if (match(lcname, /^modules-/)) modules = true;
|
||||
if (lcname == 'openwrt_config.tar.gz') cfg = true;
|
||||
push(items, {
|
||||
name: base,
|
||||
mtime: sprintf('%s', sh('date -d @' + st.mtime + ' +"%Y-%m-%d %H:%M:%S"')),
|
||||
modestr: st.modestr ?? '',
|
||||
size: _human_size(st.size),
|
||||
ipk: match(lcname, /\.(ipk|apk)$/) ? true : false,
|
||||
cfg: (lcname == 'openwrt_config.tar.gz')
|
||||
});
|
||||
}
|
||||
// Match the Lua page side-effect: write the upfiles status flag.
|
||||
ensure_dirs();
|
||||
if (firmware) writefile(LOG_UPFILES, 'firmware\n');
|
||||
else if (boot && dtb && modules) writefile(LOG_UPFILES, 'kernel\n');
|
||||
else writefile(LOG_UPFILES, '');
|
||||
return { path: dir, items, has_firmware: firmware,
|
||||
has_kernel: (boot && dtb && modules),
|
||||
has_config: cfg };
|
||||
}
|
||||
|
||||
function _safe_basename(s) {
|
||||
const b = replace(s ?? '', /^.*[\\\/]/, '');
|
||||
// Permissive basename check: only reject empty, dot/dotdot and anything
|
||||
// still containing path separators after the strip. Strict allowlists
|
||||
// rejected legitimate filenames (e.g. some i18n packages) on certain
|
||||
// runtimes where the regex character class behaved unexpectedly.
|
||||
if (b == '' || b == '.' || b == '..') return null;
|
||||
if (index(b, '/') >= 0 || index(b, '\\') >= 0) return null;
|
||||
return b;
|
||||
}
|
||||
|
||||
// Chunked upload helper. The browser-side view splits the file into base64
|
||||
// chunks and calls this method N times. The first call (append=false)
|
||||
// truncates / creates the file; later calls append. Implemented through our
|
||||
// own ubus method so it bypasses the cgi-upload ACL flow entirely (the
|
||||
// ucode runs as root and owns the upload dir).
|
||||
function m_upload_chunk(req) {
|
||||
const dir = compute_upload_path();
|
||||
mkdir(dir);
|
||||
const b = _safe_basename(req.args?.name);
|
||||
if (!b) return { ok: false, error: 'invalid name: ' + (req.args?.name ?? '') };
|
||||
const full = dir + b;
|
||||
const data = b64dec(req.args?.data ?? '');
|
||||
if (data === null) return { ok: false, error: 'invalid data' };
|
||||
const append = !!req.args?.append;
|
||||
const fp = fsopen(full, append ? 'a' : 'w');
|
||||
if (!fp) return { ok: false, error: 'open failed: ' + (fserror() ?? '') };
|
||||
const n = fp.write(data);
|
||||
fp.close();
|
||||
if (n === null) return { ok: false, error: 'write failed: ' + (fserror() ?? '') };
|
||||
return { ok: true, written: n };
|
||||
}
|
||||
|
||||
function m_delete_upload(req) {
|
||||
const dir = compute_upload_path();
|
||||
const b = _safe_basename(req.args?.name);
|
||||
if (!b) return { error: 'invalid name' };
|
||||
return { ok: (unlink(dir + b) ? true : false) };
|
||||
}
|
||||
|
||||
function m_install_upload(req) {
|
||||
const dir = compute_upload_path();
|
||||
const b = _safe_basename(req.args?.name);
|
||||
if (!b) return { error: 'invalid name' };
|
||||
const full = dir + b;
|
||||
const lc_b = lc(b);
|
||||
if (lc_b == 'openwrt_config.tar.gz') {
|
||||
shcall('chmod +x /usr/sbin/openwrt-backup');
|
||||
// Use shbg so the restore+reboot does not block the rpcd thread.
|
||||
shbg('/usr/sbin/openwrt-backup -r > ' + LOG_FILE + ' 2>&1 && sync');
|
||||
return { code: 0, kind: 'config' };
|
||||
}
|
||||
if (match(lc_b, /\.ipk$/) || match(lc_b, /\.apk$/)) {
|
||||
let out = '';
|
||||
if (shcall('command -v opkg') == 0)
|
||||
out = sh('opkg --force-reinstall --force-downgrade install ' + shq(full) + ' 2>&1');
|
||||
else if (shcall('command -v apk') == 0)
|
||||
out = sh('apk add --force-overwrite --allow-untrusted ' + shq(full) + ' 2>&1');
|
||||
else
|
||||
out = "Error: Neither 'opkg' nor 'apk' package manager found on the system.";
|
||||
shcall('rm -rf /tmp/luci-indexcache /tmp/luci-modulecache/*');
|
||||
return { code: 0, kind: 'package', output: out };
|
||||
}
|
||||
return { error: 'unsupported file type' };
|
||||
}
|
||||
|
||||
function m_backup_create() {
|
||||
ensure_dirs();
|
||||
shcall('chmod +x /usr/sbin/openwrt-backup');
|
||||
shcall('/usr/sbin/openwrt-backup -b > ' + LOG_FILE + ' && sync');
|
||||
const path = '/.reserved/openwrt_config.tar.gz';
|
||||
const ok = access(path);
|
||||
return { ok: ok ? true : false, path };
|
||||
}
|
||||
|
||||
function m_save_backup_list(req) {
|
||||
let v = req.args?.content ?? '';
|
||||
// strip leading whitespace per line
|
||||
v = replace(v, /\r/g, '');
|
||||
const lines = split(v, '\n');
|
||||
const out = [];
|
||||
for (let l in lines) {
|
||||
let t = replace(l, /^\s+/, '');
|
||||
// strip trailing backslash continuation
|
||||
t = replace(t, /\s*\\\s*$/, '');
|
||||
if (t != '') push(out, t);
|
||||
}
|
||||
writefile(BACKUP_LIST, join('\n', out) + '\n');
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
function m_reload_cpu() {
|
||||
shcall('(sleep 1 && /etc/init.d/amlogic start) &');
|
||||
return { code: 0 };
|
||||
}
|
||||
|
||||
// Sync menu visibility UCI flags from runtime platform detection.
|
||||
// Called from info.js on every page load so the sidebar reflects the
|
||||
// current hardware state without requiring the user to visit Plugin Settings.
|
||||
function m_sync_menu() {
|
||||
const p = platform();
|
||||
const m = show_install_menu();
|
||||
// Detect whether OpenWrt has already been installed to internal storage
|
||||
const root_pt = sh("df / | tail -n1 | awk '{print $1}' | awk -F '/' '{print $3}'");
|
||||
const is_installed = (root_pt != '' &&
|
||||
(match(root_pt, /^mmcblk[0-9]+p[1-4]$/) ||
|
||||
match(root_pt, /^[hsv]d[a-z][0-9]+$/) ||
|
||||
match(root_pt, /^nvme[0-9]+n[0-9]+p[0-9]+$/)));
|
||||
const can_install = (index(p, 'amlogic') >= 0 || index(p, 'allwinner') >= 0 || index(m, 'yes') >= 0);
|
||||
const show_install = (can_install && !is_installed) ? 'yes' : 'no';
|
||||
const show_armcpu = (index(p, 'qemu') < 0) ? 'yes' : 'no';
|
||||
shcall('uci -q set amlogic.config.menu_install=' + shq(show_install) +
|
||||
' && uci -q set amlogic.config.menu_armcpu=' + shq(show_armcpu) +
|
||||
' && uci commit amlogic');
|
||||
return { code: 0, show_install, show_armcpu };
|
||||
}
|
||||
|
||||
// Enumerate cpufreq policies + their available freqs/governors so the armcpu
|
||||
// view can render a tab per CPU policy (mirrors the Lua dynamic taboption
|
||||
// loop in amlogic_armcpu.lua).
|
||||
function m_cpu_policies() {
|
||||
const policies_str = sh("ls /sys/devices/system/cpu/cpufreq 2>/dev/null | grep -E 'policy[0-9]{1,3}' | xargs");
|
||||
let names = split(policies_str, ' ');
|
||||
if (length(names) == 1 && names[0] == '') names = ['policy0'];
|
||||
const out = [];
|
||||
for (let n in names) {
|
||||
const name = trim(n);
|
||||
if (name == '') continue;
|
||||
const id = replace(name, 'policy', '');
|
||||
const freqs_raw = readfile('/sys/devices/system/cpu/cpufreq/' + name + '/scaling_available_frequencies') ?? '';
|
||||
const govs_raw = readfile('/sys/devices/system/cpu/cpufreq/' + name + '/scaling_available_governors') ?? '';
|
||||
const freqs = []; for (let v in split(trim(freqs_raw), ' ')) if (v != '') push(freqs, v);
|
||||
const govs = []; for (let v in split(trim(govs_raw), ' ')) if (v != '') push(govs, v);
|
||||
const core_type = sh('cat /sys/devices/system/cpu/cpu' + id + "/uevent | grep -E '^OF_COMPATIBLE_0' | sed 's/^OF_COMPATIBLE_0=//' | xargs");
|
||||
push(out, { name, id, freqs, governors: govs, core_type: core_type != '' ? core_type : 'Unknown' });
|
||||
}
|
||||
return { policies: out };
|
||||
}
|
||||
|
||||
const methods = {
|
||||
state: { call: m_state },
|
||||
author: { call: m_author },
|
||||
platform_info: { call: m_platform_info },
|
||||
model_database: { call: m_model_database },
|
||||
snapshot_list: { call: m_snapshot_list },
|
||||
snapshot_create: { call: m_snapshot_create },
|
||||
snapshot_delete: { args: { name: '' }, call: m_snapshot_delete },
|
||||
snapshot_restore:{ args: { name: '' }, call: m_snapshot_restore },
|
||||
check_plugin: { args: { options: '' }, call: m_check_plugin },
|
||||
check_kernel: { args: { options: '' }, call: m_check_kernel },
|
||||
check_firmware: { args: { options: '' }, call: m_check_firmware },
|
||||
start_plugin: { call: m_start_plugin },
|
||||
start_kernel: { call: m_start_kernel },
|
||||
start_update: { args: { amlogic_update_sel: '' }, call: m_start_update },
|
||||
start_install: { args: { amlogic_install_sel: '' }, call: m_start_install },
|
||||
start_rescue: { call: m_start_rescue },
|
||||
read_log_tail: { args: { name: '' }, call: m_read_log_tail },
|
||||
read_log_full: { args: { name: '' }, call: m_read_log_full },
|
||||
del_log: { call: m_del_log },
|
||||
poweroff: { call: m_poweroff },
|
||||
kvm_switch: { call: m_kvm_switch },
|
||||
check_upfiles: { call: m_check_upfiles },
|
||||
upload_path: { call: m_upload_path },
|
||||
upload_chunk: { args: { name: '', data: '', append: false }, call: m_upload_chunk },
|
||||
list_uploads: { call: m_list_uploads },
|
||||
delete_upload: { args: { name: '' }, call: m_delete_upload },
|
||||
install_upload: { args: { name: '' }, call: m_install_upload },
|
||||
backup_create: { call: m_backup_create },
|
||||
save_backup_list:{ args: { content: '' }, call: m_save_backup_list },
|
||||
prime_backup_list:{ call: m_prime_backup_list },
|
||||
reload_cpu: { call: m_reload_cpu },
|
||||
sync_menu: { call: m_sync_menu },
|
||||
cpu_policies: { call: m_cpu_policies }
|
||||
};
|
||||
|
||||
return { 'luci.amlogic': methods };
|
||||
Reference in new issue
Block a user