autocore: minor cleanup

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Tianling Shen 2022-03-25 23:32:57 +08:00
parent c3ab6a927a
commit d03e7618a2
No known key found for this signature in database
GPG Key ID: 6850B6345C862176
16 changed files with 159 additions and 1084 deletions

View File

@ -27,52 +27,34 @@ endef
define Package/autocore-x86
TITLE:=x86/x64 auto core loadbalance script.
MAINTAINER:=Lean / CN_SZTL
DEPENDS:=@TARGET_x86 +bc +lm-sensors +ethtool
DEPENDS:=@TARGET_x86 +lm-sensors +ethtool
VARIANT:=x86
endef
define Package/autocore-arm/description
Display more details info about the devices in LuCI.
endef
define Package/autocore-x86/description
A USB autoconfig hotplug script.
endef
define Build/Compile
endef
define Package/autocore-arm/install
$(INSTALL_DIR) $(1)/etc
$(INSTALL_BIN) ./files/arm/rpcd_luci $(1)/etc/rpcd_luci
$(INSTALL_DATA) ./files/arm/rpcd_luci-mod-status.json $(1)/etc/rpcd_luci-mod-status.json
$(INSTALL_DATA) ./files/arm/rpcd_10_system.js $(1)/etc/rpcd_10_system.js
define Package/autocore/install/Default
$(INSTALL_DIR) $$(1)/etc
$(CP) ./files/generic/index.htm $$(1)/etc/
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) ./files/090-cover-index_files $(1)/etc/uci-defaults/090-cover-index_files
$(INSTALL_BIN) ./files/generic/090-cover-index_htm $$(1)/etc/uci-defaults/
$(INSTALL_DIR) $(1)/sbin
$(INSTALL_BIN) ./files/arm/cpuinfo $(1)/sbin/cpuinfo
$(INSTALL_BIN) ./files/generic/cpuinfo $$(1)/sbin/
$(INSTALL_BIN) ./files/generic/ethinfo $$(1)/sbin/
endef
define Package/autocore-arm/install
$(call Package/autocore/install/Default,$(1))
endef
define Package/autocore-x86/install
$(INSTALL_DIR) $(1)/etc
$(INSTALL_BIN) ./files/x86/rpcd_luci $(1)/etc/rpcd_luci
$(INSTALL_DATA) ./files/x86/rpcd_luci-mod-status.json $(1)/etc/rpcd_luci-mod-status.json
$(INSTALL_DATA) ./files/x86/rpcd_10_system.js $(1)/etc/rpcd_10_system.js
$(call Package/autocore/install/Default)
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/x86/autocore $(1)/etc/init.d/autocore
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) ./files/090-cover-index_files $(1)/etc/uci-defaults/090-cover-index_files
$(INSTALL_DIR) $(1)/sbin
$(INSTALL_BIN) ./files/x86/cpuinfo $(1)/sbin/cpuinfo
$(INSTALL_BIN) ./files/x86/ethinfo $(1)/sbin/ethinfo
$(INSTALL_DIR) $(1)/www/luci-static/resources/view/status/include
$(INSTALL_DATA) ./files/x86/rpcd_21_ethinfo.js $(1)/www/luci-static/resources/view/status/include/21_ethinfo.js
$(INSTALL_BIN) ./files/x86/autocore $(1)/etc/init.d/
endef
$(eval $(call BuildPackage,autocore-arm))

View File

@ -1,5 +0,0 @@
#!/bin/sh
[ -f '/etc/rpcd_luci' ] && mv -f '/etc/rpcd_luci' '/usr/libexec/rpcd/luci'
[ -f '/etc/rpcd_luci-mod-status.json' ] && { mv -f '/etc/rpcd_luci-mod-status.json' '/usr/share/rpcd/acl.d/luci-mod-status.json'; /etc/init.d/rpcd restart; }
[ -f '/etc/rpcd_10_system.js' ] && mv -f '/etc/rpcd_10_system.js' '/www/luci-static/resources/view/status/include/10_system.js'

View File

@ -1,37 +0,0 @@
#!/bin/sh
cpu_arch="$(cat "/proc/cpuinfo" | grep "model name" | sed -n "1p" | awk -F ': ' '{print $2}')"
[ -z "${cpu_arch}" ] && cpu_arch="?"
cpu_cores="$(cat "/proc/cpuinfo" | grep "processor" | wc -l)"
if grep -q "bcm27xx" "/etc/openwrt_release"; then
cpu_freq="$(expr $(vcgencmd measure_clock arm | awk -F '=' '{print $2}') / 1000000)Mhz"
elif grep -q "bcm53xx" "/etc/openwrt_release"; then
cpu_freq="$(nvram get clkfreq | awk -F ',' '{print $1}')MHz"
elif grep -q "mvebu" "/etc/openwrt_release"; then
cpu_freq="$(cat "/proc/cpuinfo" | grep "BogoMIPS" | sed -n "1p" | awk -F ': ' '{print $2}')MHz"
elif [ -e "/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_cur_freq" ]; then
cpu_freq="$(expr $(cat "/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_cur_freq") / 1000)MHz"
fi
if [ -e "/sys/devices/system/cpu/cpufreq/policy4/cpuinfo_cur_freq" ]; then
big_cpu_freq="$(expr $(cat "/sys/devices/system/cpu/cpufreq/policy4/cpuinfo_cur_freq") / 1000)MHz "
fi
if grep -q "bcm27xx" "/etc/openwrt_release"; then
cpu_temp="$(vcgencmd measure_temp | awk -F '=' '{print $2}' | awk -F "'" '{print $1}')°C"
elif grep -q "ipq40xx" "/etc/openwrt_release"; then
cpu_temp="$(awk '{printf("%.1f°C ", $0 / 1000)}' /sys/class/ieee80211/phy*/device/hwmon/hwmon*/temp1_input | awk '$1=$1')"
else
[ -e "/sys/class/thermal/thermal_zone0/temp" ] && \
cpu_temp="$(awk '{printf("%.1f°C", $0 / 1000)}' /sys/class/thermal/thermal_zone0/temp)"
fi
if [ -z "${cpu_freq}" ] && [ -z "${cpu_temp}" ]; then
echo -n "${cpu_arch} x ${cpu_cores}"
elif [ -z "${cpu_temp}" ]; then
echo -n "${cpu_arch} x ${cpu_cores} (${cpu_freq})"
elif [ -z "${cpu_freq}" ]; then
echo -n "${cpu_arch} x ${cpu_cores} (${cpu_temp})"
else
echo -n "${cpu_arch} x ${cpu_cores} (${big_cpu_freq}${cpu_freq}, ${cpu_temp})"
fi

View File

@ -1,95 +0,0 @@
{
"luci-mod-status-realtime": {
"description": "Grant access to realtime statistics",
"read": {
"ubus": {
"luci": [ "getConntrackList", "getRealtimeStats", "getCPUBench", "getCPUInfo", "getCPUUsage", "getOnlineUsers" ],
"network.rrdns": [ "lookup" ]
}
}
},
"luci-mod-status-processes": {
"description": "Grant access to process status",
"read": {
"ubus": {
"luci": [ "getProcessList" ]
}
},
"write": {
"file": {
"/bin/kill": [ "exec" ]
},
"ubus": {
"file": [ "exec" ]
}
}
},
"luci-mod-status-logs": {
"description": "Grant access to system logs",
"read": {
"cgi-io": [ "exec" ],
"file": {
"/bin/dmesg -r": [ "exec" ],
"/sbin/logread": [ "stat" ],
"/sbin/logread -e ^": [ "exec" ],
"/usr/sbin/logread": [ "stat" ],
"/usr/sbin/logread -e ^": [ "exec" ]
},
"ubus": {
"file": [ "stat" ]
}
}
},
"luci-mod-status-routes": {
"description": "Grant access to routing status",
"read": {
"file": {
"/sbin/ip -[46] neigh show": [ "exec" ],
"/sbin/ip -[46] route show table all": [ "exec" ],
"/sbin/ip -[46] rule show": [ "exec" ]
},
"ubus": {
"file": [ "exec" ]
}
}
},
"luci-mod-status-channel_analysis": {
"description": "Grant access to wireless channel status",
"read": {
"ubus": {
"iwinfo": [ "info", "freqlist" ]
}
}
},
"luci-mod-status-firewall": {
"description": "Grant access to firewall status",
"read": {
"cgi-io": [ "exec" ],
"file": {
"/usr/sbin/nft --json list ruleset": [ "exec" ],
"/usr/sbin/iptables --line-numbers -w -nvxL -t *": [ "exec" ],
"/usr/sbin/ip6tables --line-numbers -w -nvxL -t *": [ "exec" ],
"/usr/sbin/ip6tables": [ "list" ]
},
"ubus": {
"file": [ "stat" ]
}
},
"write": {
"cgi-io": [ "exec" ],
"file": {
"/etc/init.d/firewall restart": [ "exec" ],
"/usr/sbin/iptables -Z": [ "exec" ],
"/usr/sbin/ip6tables -Z": [ "exec" ]
},
"ubus": {
"file": [ "exec" ]
}
}
}
}

View File

@ -0,0 +1,11 @@
#!/bin/sh
[ ! -f '/etc/rpcd_10_system.js' ] || \
mv -f '/etc/rpcd_10_system.js' '/www/luci-static/resources/view/status/include/10_system.js'
[ ! -f '/etc/rpcd_luci' ] || \
mv -f '/etc/rpcd_luci' '/usr/libexec/rpcd/luci'
[ ! -f '/etc/rpcd_luci-mod-status.json' ] || \
mv -f '/etc/rpcd_luci-mod-status.json' '/usr/share/rpcd/acl.d/luci-mod-status.json'
/etc/init.d/rpcd restart
exit 0

View File

@ -0,0 +1,60 @@
#!/bin/sh
. /etc/openwrt_release
CPUINFO_PATH="/proc/cpuinfo"
CPUFREQ_PATH="/sys/devices/system/cpu/cpufreq"
THERMAL_PATH="/sys/class/thermal"
cpu_arch="$(grep "model name" "$CPUINFO_PATH" | head -n1 | awk -F ': ' '{print $2}' | xargs)"
[ -n "${cpu_arch}" ] || cpu_arch="?"
case "$DISTRIB_TARGET" in
"x86"/*)
cpu_cores="$(grep "core id" "$CPUINFO_PATH" | sort -u | wc -l)C $(grep -c "processor" "$CPUINFO_PATH")T" ;;
*)
cpu_cores="$(grep -c "processor" "$CPUINFO_PATH")" ;;
esac
case "$DISTRIB_TARGET" in
"bcm27xx"/*)
cpu_freq="$(( $(vcgencmd measure_clock arm | awk -F '=' '{print $2}') / 1000000 ))Mhz" ;;
"bcm53xx"/*)
cpu_freq="$(nvram get clkfreq | awk -F ',' '{print $1}')MHz" ;;
"mvebu"/*)
cpu_freq="$(grep "BogoMIPS" "$CPUINFO_PATH" | sed -n "1p" | awk -F ': ' '{print $2}')MHz" ;;
"x86"/*)
cpu_freq="$(grep "MHz" "$CPUINFO_PATH" | head -n1 | awk -F ': ' '{print $2}')MHz"
;;
*)
[ ! -e "$CPUFREQ_PATH/policy0/cpuinfo_cur_freq" ] || \
cpu_freq="$(awk '{printf("%.fMHz", $0 / 1000)}' "$CPUFREQ_PATH/policy0/cpuinfo_cur_freq")"
[ ! -e "$CPUFREQ_PATH/policy4/cpuinfo_cur_freq" ] || \
big_cpu_freq="$(awk '{printf("%.fMHz ", $0 / 1000)}' "$CPUFREQ_PATH/policy4/cpuinfo_cur_freq")"
;;
esac
case "$DISTRIB_TARGET" in
"bcm27xx"/*)
cpu_temp="$(vcgencmd measure_temp | awk -F '=' '{print $2}' | awk -F "'" '{print $1}')°C" ;;
"x86"/*)
# Intel
cpu_temp="$(sensors "coretemp-*" 2>"/dev/null" | grep -E "(Package id |Core )" | grep -Eo "\+[0-9.]*°C" | head -n1 | tr -d "+")"
# AMD
[ -n "${cpu_temp}" ] || cpu_temp="$(sensors "k*temp-*" 2>"/dev/null" | grep "Tdie" | head -n1 | awk '{print $2}' | tr -d "+")"
;;
*)
[ ! -e "$THERMAL_PATH/thermal_zone0/temp" ] || \
cpu_temp="$(awk '{printf("%.1f°C", $0 / 1000)}' "$THERMAL_PATH/thermal_zone0/temp")"
;;
esac
if [ -z "$big_cpu_freq$cpu_freq" ] && [ -n "$cpu_temp" ]; then
echo -n "$cpu_arch x $cpu_cores ($cpu_temp)"
elif [ -z "$cpu_temp" ] && [ -n "$big_cpu_freq$cpu_freq" ]; then
echo -n "$cpu_arch x $cpu_cores ($big_cpu_freq$cpu_freq)"
elif [ -n "$cpu_temp" ] && [ -n "$big_cpu_freq$cpu_freq" ]; then
echo -n "$cpu_arch x $cpu_cores ($big_cpu_freq$cpu_freq, ${cpu_temp})"
else
echo -n "$cpu_arch x $cpu_cores"
fi

View File

@ -0,0 +1,39 @@
#!/usr/bin/lua
-- Copyright (C) 2022 Tianling Shen <cnsztl@immortalwrt.org>
local util = require "luci.util"
local jsonc = require "luci.jsonc"
local eth_info = {}
local ifname, stat
for ifname, stat in pairs(util.ubus("network.device", "status")) do
if ifname:match("^(eth%d+)$") == ifname then
local status, speed, duplex
status = stat.carrier and "yes" or "no"
if stat.speed:sub(1, 1) == "-" then
speed = "-"
else
speed = stat.speed:sub(1, -2) .. "Mb/s"
end
if not stat.carrier then
duplex = "-"
elseif stat.speed:sub(-1) == "F" then
duplex = "Full"
else
duplex = "Half"
end
eth_info[#eth_info+1] = { name = ifname, status = status,
speed = speed, duplex = duplex }
end
end
table.sort(eth_info,
function(a, b)
return a.name < b.name
end)
print(jsonc.stringify(eth_info))

View File

@ -75,7 +75,7 @@ return baseclass.extend({
_('Hostname'), boardinfo.hostname,
_('Model'), boardinfo.model + cpubench.cpubench,
_('Architecture'), cpuinfo.cpuinfo,
_('Target Platform'), (L.isObject(boardinfo.release) ? boardinfo.release.target : ''),
_('Target Platform'), (L.isObject(boardinfo.release) ? boardinfo.release.target : ''),
_('Firmware Version'), (L.isObject(boardinfo.release) ? boardinfo.release.description + ' / ' : '') + (luciversion || ''),
_('Kernel Version'), boardinfo.kernel,
_('Local Time'), datestr,

View File

@ -638,7 +638,7 @@ local methods = {
cpuinfo.cpuinfo = sys.exec("/sbin/cpuinfo")
if (cpuinfo.cpuinfo == nil) or (cpuinfo.cpuinfo == "") then
cpuinfo.cpuinfo = "(2.33MHz, +2.33°C)"
cpuinfo.cpuinfo = "2.33 MHz +2.33 C"
end
return cpuinfo
@ -655,6 +655,15 @@ local methods = {
end
},
getETHInfo = {
call = function()
local sys = require "luci.sys"
local rv = json.parse(sys.exec("/sbin/ethinfo")) or {}
return { ethinfo = rv }
end
},
getOnlineUsers = {
call = function()
local sys = require "luci.sys"

View File

@ -3,50 +3,37 @@
START=99
start()
{
start() {
rfc=4096
cc=$(grep -c processor /proc/cpuinfo)
rsfe=$(echo $cc*$rfc | bc)
sysctl -w net.core.rps_sock_flow_entries=$rsfe
for fileRps in $(ls /sys/class/net/eth*/queues/rx-*/rps_cpus)
threads="$(grep -c "processor" "/proc/cpuinfo")"
sysctl -w net.core.rps_sock_flow_entries="$(( rfc * threads ))"
for fileRps in /sys/class/net/eth*/queues/rx-*/rps_cpus
do
echo $cc > $fileRps
echo "$threads" > "$fileRps"
done
for fileRfc in $(ls /sys/class/net/eth*/queues/rx-*/rps_flow_cnt)
for fileRfc in /sys/class/net/eth*/queues/rx-*/rps_flow_cnt
do
echo $rfc > $fileRfc
echo "$rfc" > "$fileRfc"
done
for fileRps in $(ls /sys/class/net/eth*/queues/tx-*/xps_cpus)
uci set network.@globals[0].packet_steering="1"
uci commit network
for i in $(ip address | grep -E 'eth[0-9]+' | awk -F ': ' '{print $2}' | xargs)
do
echo $cc > $fileRps
{
ethtool -K "$i" rx-checksum on
ethtool -K "$i" tx-checksum-ip-generic on || {
ethtool -K "$i" tx-checksum-ipv4 on
ethtool -K "$i" tx-checksum-ipv6 on
}
ethtool -K "$i" tx-scatter-gather on
ethtool -K "$i" gso on
ethtool -K "$i" tso on
ethtool -K "$i" ufo on
}
done
a=$(cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq)
b=$(echo -n ' : ')
c=$(cat /proc/cpuinfo | grep 'core id' | sort -u | wc -l)
d=$(echo -n ' Core ')
e=$(cat /proc/cpuinfo | grep 'processor' | wc -l)
f=$(echo -n ' Thread ')
g=${a}${b}${c}${d}${e}${f}
mkdir -p /tmp/sysinfo
echo $g > /tmp/sysinfo/model
a=$(ip address | grep ^[0-9] | awk -F: '{print $2}' | sed "s/ //g" | grep '^[e]' | grep -v "@" | grep -v "\.")
b=$(echo "$a" | wc -l)
for i in $(seq 1 $b)
do
c=$(echo "$a" | sed -n ${i}p)
ethtool -K $c rx-checksum on >/dev/null 2>&1
ethtool -K $c tx-checksum-ip-generic on >/dev/null 2>&1 || (
ethtool -K $c tx-checksum-ipv4 on >/dev/null 2>&1
ethtool -K $c tx-checksum-ipv6 on >/dev/null 2>&1)
ethtool -K $c tx-scatter-gather on >/dev/null 2>&1
ethtool -K $c gso on >/dev/null 2>&1
ethtool -K $c tso on >/dev/null 2>&1
ethtool -K $c ufo on >/dev/null 2>&1
done
}
} >"/dev/null" 2>&1

View File

@ -1,5 +0,0 @@
#!/bin/sh
MHz=`grep 'MHz' /proc/cpuinfo | cut -c11- |sed -n '1p'`
TEMP=`sensors 2>/dev/null | grep 'Core 0' | cut -c12-`
echo "$MHz MHz $TEMP "

View File

@ -1,17 +0,0 @@
#!/bin/sh
a=$(ip address | grep ^[0-9] | awk -F: '{print $2}' | sed "s/ //g" | grep '^[e]' | grep -v "@" | grep -v "\.")
b=$(echo "$a" | wc -l)
rm -f /tmp/state/ethinfo
for i in $(seq 1 $b)
do
c=$(echo "$a" | sed -n ${i}p)
d=$(ethtool $c)
e=$(echo "$d" | grep "Link detected" | awk -F: '{printf $2}' | sed 's/^[ \t]*//g')
f=$(echo "$d" | grep "Speed" | awk -F: '{printf $2}' | sed 's/^[ \t]*//g' | tr -d "Unknown!")
[ -z "$f" ] && f="-"
g=$(echo "$d" | grep "Duplex" | awk -F: '{printf $2}' | sed 's/^[ \t]*//g')
[ "$g" != "Full" -a "$g" != "Half" ] && g="-"
echo "$c $e $f $g" >> /tmp/state/ethinfo
done

View File

@ -1,102 +0,0 @@
'use strict';
'require baseclass';
'require fs';
'require rpc';
var callSystemBoard = rpc.declare({
object: 'system',
method: 'board'
});
var callSystemInfo = rpc.declare({
object: 'system',
method: 'info'
});
var callCPUBench = rpc.declare({
object: 'luci',
method: 'getCPUBench'
});
var callCPUInfo = rpc.declare({
object: 'luci',
method: 'getCPUInfo'
});
var callCPUUsage = rpc.declare({
object: 'luci',
method: 'getCPUUsage'
});
return baseclass.extend({
title: _('System'),
load: function() {
return Promise.all([
L.resolveDefault(callSystemBoard(), {}),
L.resolveDefault(callSystemInfo(), {}),
L.resolveDefault(callCPUBench(), {}),
L.resolveDefault(callCPUInfo(), {}),
L.resolveDefault(callCPUUsage(), {}),
fs.lines('/usr/lib/lua/luci/version.lua')
]);
},
render: function(data) {
var boardinfo = data[0],
systeminfo = data[1],
cpubench = data[2],
cpuinfo = data[3],
cpuusage = data[4],
luciversion = data[5];
luciversion = luciversion.filter(function(l) {
return l.match(/^\s*(luciname|luciversion)\s*=/);
}).map(function(l) {
return l.replace(/^\s*\w+\s*=\s*['"]([^'"]+)['"].*$/, '$1');
}).join(' ');
var datestr = null;
if (systeminfo.localtime) {
var date = new Date(systeminfo.localtime * 1000);
datestr = '%04d-%02d-%02d %02d:%02d:%02d'.format(
date.getUTCFullYear(),
date.getUTCMonth() + 1,
date.getUTCDate(),
date.getUTCHours(),
date.getUTCMinutes(),
date.getUTCSeconds()
);
}
var fields = [
_('Hostname'), boardinfo.hostname,
_('Model'), boardinfo.model + cpubench.cpubench,
_('CPU Info'), cpuinfo.cpuinfo,
_('Target Platform'), (L.isObject(boardinfo.release) ? boardinfo.release.target : ''),
_('Firmware Version'), (L.isObject(boardinfo.release) ? boardinfo.release.description + ' / ' : '') + (luciversion || ''),
_('Kernel Version'), boardinfo.kernel,
_('Local Time'), datestr,
_('Uptime'), systeminfo.uptime ? '%t'.format(systeminfo.uptime) : null,
_('Load Average'), Array.isArray(systeminfo.load) ? '%.2f, %.2f, %.2f'.format(
systeminfo.load[0] / 65535.0,
systeminfo.load[1] / 65535.0,
systeminfo.load[2] / 65535.0
) : null,
_('CPU usage (%)'), cpuusage.cpuusage
];
var table = E('table', { 'class': 'table' });
for (var i = 0; i < fields.length; i += 2) {
table.appendChild(E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'width': '33%' }, [ fields[i] ]),
E('td', { 'class': 'td left' }, [ (fields[i + 1] != null) ? fields[i + 1] : '?' ])
]));
}
return table;
}
});

View File

@ -1,752 +0,0 @@
#!/usr/bin/env lua
local json = require "luci.jsonc"
local fs = require "nixio.fs"
local function readfile(path)
local s = fs.readfile(path)
return s and (s:gsub("^%s+", ""):gsub("%s+$", ""))
end
local methods = {
getInitList = {
args = { name = "name" },
call = function(args)
local sys = require "luci.sys"
local _, name, scripts = nil, nil, {}
for _, name in ipairs(args.name and { args.name } or sys.init.names()) do
local index = sys.init.index(name)
if index then
scripts[name] = { index = index, enabled = sys.init.enabled(name) }
else
return { error = "No such init script" }
end
end
return scripts
end
},
setInitAction = {
args = { name = "name", action = "action" },
call = function(args)
local sys = require "luci.sys"
if type(sys.init[args.action]) ~= "function" then
return { error = "Invalid action" }
end
return { result = sys.init[args.action](args.name) }
end
},
getLocaltime = {
call = function(args)
return { result = os.time() }
end
},
setLocaltime = {
args = { localtime = 0 },
call = function(args)
local sys = require "luci.sys"
local date = os.date("*t", args.localtime)
if date then
sys.call("date -s '%04d-%02d-%02d %02d:%02d:%02d' >/dev/null" %{ date.year, date.month, date.day, date.hour, date.min, date.sec })
sys.call("/etc/init.d/sysfixtime restart >/dev/null")
end
return { result = args.localtime }
end
},
getTimezones = {
call = function(args)
local util = require "luci.util"
local zones = require "luci.sys.zoneinfo"
local tz = readfile("/etc/TZ")
local res = util.ubus("uci", "get", {
config = "system",
section = "@system[0]",
option = "zonename"
})
local result = {}
local _, zone
for _, zone in ipairs(zones.TZ) do
result[zone[1]] = {
tzstring = zone[2],
active = (res and res.value == zone[1]) and true or nil
}
end
return result
end
},
getLEDs = {
call = function()
local iter = fs.dir("/sys/class/leds")
local result = { }
if iter then
local led
for led in iter do
local m, s
result[led] = { triggers = {} }
s = readfile("/sys/class/leds/"..led.."/trigger")
for s in (s or ""):gmatch("%S+") do
m = s:match("^%[(.+)%]$")
result[led].triggers[#result[led].triggers+1] = m or s
result[led].active_trigger = m or result[led].active_trigger
end
s = readfile("/sys/class/leds/"..led.."/brightness")
if s then
result[led].brightness = tonumber(s)
end
s = readfile("/sys/class/leds/"..led.."/max_brightness")
if s then
result[led].max_brightness = tonumber(s)
end
end
end
return result
end
},
getUSBDevices = {
call = function()
local fs = require "nixio.fs"
local iter = fs.glob("/sys/bus/usb/devices/[0-9]*/manufacturer")
local result = { }
if iter then
result.devices = {}
local p
for p in iter do
local id = p:match("/([^/]+)/manufacturer$")
result.devices[#result.devices+1] = {
id = id,
vid = readfile("/sys/bus/usb/devices/"..id.."/idVendor"),
pid = readfile("/sys/bus/usb/devices/"..id.."/idProduct"),
vendor = readfile("/sys/bus/usb/devices/"..id.."/manufacturer"),
product = readfile("/sys/bus/usb/devices/"..id.."/product"),
speed = tonumber((readfile("/sys/bus/usb/devices/"..id.."/product")))
}
end
end
iter = fs.glob("/sys/bus/usb/devices/*/*-port[0-9]*")
if iter then
result.ports = {}
local p
for p in iter do
local port = p:match("([^/]+)$")
local link = fs.readlink(p.."/device")
result.ports[#result.ports+1] = {
port = port,
device = link and fs.basename(link)
}
end
end
return result
end
},
getConntrackHelpers = {
call = function()
local ok, fd = pcall(io.open, "/usr/share/fw3/helpers.conf", "r")
local rv = {}
if not (ok and fd) then
ok, fd = pcall(io.open, "/usr/share/firewall4/helpers", "r")
end
if ok and fd then
local entry
while true do
local line = fd:read("*l")
if not line then
break
end
if line:match("^%s*config%s") then
if entry then
rv[#rv+1] = entry
end
entry = {}
else
local opt, val = line:match("^%s*option%s+(%S+)%s+(%S.*)$")
if opt and val then
opt = opt:gsub("^'(.+)'$", "%1"):gsub('^"(.+)"$', "%1")
val = val:gsub("^'(.+)'$", "%1"):gsub('^"(.+)"$', "%1")
entry[opt] = val
end
end
end
if entry then
rv[#rv+1] = entry
end
fd:close()
end
return { result = rv }
end
},
getFeatures = {
call = function()
local fs = require "nixio.fs"
local rv = {}
local ok, fd
rv.firewall = fs.access("/sbin/fw3")
rv.firewall4 = fs.access("/sbin/fw4")
rv.opkg = fs.access("/bin/opkg")
rv.offloading = fs.access("/sys/module/xt_FLOWOFFLOAD/refcnt") or fs.access("/sys/module/nft_flow_offload/refcnt")
rv.br2684ctl = fs.access("/usr/sbin/br2684ctl")
rv.swconfig = fs.access("/sbin/swconfig")
rv.odhcpd = fs.access("/usr/sbin/odhcpd")
rv.zram = fs.access("/sys/class/zram-control")
rv.sysntpd = fs.readlink("/usr/sbin/ntpd") and true
rv.ipv6 = fs.access("/proc/net/ipv6_route")
rv.dropbear = fs.access("/usr/sbin/dropbear")
rv.cabundle = fs.access("/etc/ssl/certs/ca-certificates.crt")
rv.relayd = fs.access("/usr/sbin/relayd")
rv.dsl = fs.access("/sbin/vdsl_cpe_control")
local wifi_features = { "eap", "11n", "11ac", "11r", "acs", "sae", "owe", "suiteb192", "wep", "wps" }
if fs.access("/usr/sbin/hostapd") then
rv.hostapd = { cli = fs.access("/usr/sbin/hostapd_cli") }
local _, feature
for _, feature in ipairs(wifi_features) do
rv.hostapd[feature] =
(os.execute(string.format("/usr/sbin/hostapd -v%s >/dev/null 2>/dev/null", feature)) == 0)
end
end
if fs.access("/usr/sbin/wpa_supplicant") then
rv.wpasupplicant = { cli = fs.access("/usr/sbin/wpa_cli") }
local _, feature
for _, feature in ipairs(wifi_features) do
rv.wpasupplicant[feature] =
(os.execute(string.format("/usr/sbin/wpa_supplicant -v%s >/dev/null 2>/dev/null", feature)) == 0)
end
end
ok, fd = pcall(io.popen, "dnsmasq --version 2>/dev/null")
if ok then
rv.dnsmasq = {}
while true do
local line = fd:read("*l")
if not line then
break
end
local opts = line:match("^Compile time options: (.+)$")
if opts then
local opt
for opt in opts:gmatch("%S+") do
local no = opt:match("^no%-(%S+)$")
rv.dnsmasq[string.lower(no or opt)] = not no
end
break
end
end
fd:close()
end
ok, fd = pcall(io.popen, "ipset --help 2>/dev/null")
if ok then
rv.ipset = {}
local sets = false
while true do
local line = fd:read("*l")
if not line then
break
elseif line:match("^Supported set types:") then
sets = true
elseif sets then
local set, ver = line:match("^%s+(%S+)%s+(%d+)")
if set and not rv.ipset[set] then
rv.ipset[set] = tonumber(ver)
end
end
end
fd:close()
end
return rv
end
},
getSwconfigFeatures = {
args = { switch = "switch0" },
call = function(args)
local util = require "luci.util"
-- Parse some common switch properties from swconfig help output.
local swc, err = io.popen("swconfig dev %s help 2>/dev/null" % util.shellquote(args.switch))
if swc then
local is_port_attr = false
local is_vlan_attr = false
local rv = {}
while true do
local line = swc:read("*l")
if not line then break end
if line:match("^%s+%-%-vlan") then
is_vlan_attr = true
elseif line:match("^%s+%-%-port") then
is_vlan_attr = false
is_port_attr = true
elseif line:match("cpu @") then
rv.switch_title = line:match("^switch%d: %w+%((.-)%)")
rv.num_vlans = tonumber(line:match("vlans: (%d+)")) or 16
rv.min_vid = 1
elseif line:match(": pvid") or line:match(": tag") or line:match(": vid") then
if is_vlan_attr then rv.vid_option = line:match(": (%w+)") end
elseif line:match(": enable_vlan4k") then
rv.vlan4k_option = "enable_vlan4k"
elseif line:match(": enable_vlan") then
rv.vlan_option = "enable_vlan"
elseif line:match(": enable_learning") then
rv.learning_option = "enable_learning"
elseif line:match(": enable_mirror_rx") then
rv.mirror_option = "enable_mirror_rx"
elseif line:match(": max_length") then
rv.jumbo_option = "max_length"
end
end
swc:close()
if not next(rv) then
return { error = "No such switch" }
end
return rv
else
return { error = err }
end
end
},
getSwconfigPortState = {
args = { switch = "switch0" },
call = function(args)
local util = require "luci.util"
local swc, err = io.popen("swconfig dev %s show 2>/dev/null" % util.shellquote(args.switch))
if swc then
local ports = { }
while true do
local line = swc:read("*l")
if not line or (line:match("^VLAN %d+:") and #ports > 0) then
break
end
local pnum = line:match("^Port (%d+):$")
if pnum then
port = {
port = tonumber(pnum),
duplex = false,
speed = 0,
link = false,
auto = false,
rxflow = false,
txflow = false
}
ports[#ports+1] = port
end
if port then
local m
if line:match("full[%- ]duplex") then
port.duplex = true
end
m = line:match(" speed:(%d+)")
if m then
port.speed = tonumber(m)
end
m = line:match("(%d+) Mbps")
if m and port.speed == 0 then
port.speed = tonumber(m)
end
m = line:match("link: (%d+)")
if m and port.speed == 0 then
port.speed = tonumber(m)
end
if line:match("link: ?up") or line:match("status: ?up") then
port.link = true
end
if line:match("auto%-negotiate") or line:match("link:.-auto") then
port.auto = true
end
if line:match("link:.-rxflow") then
port.rxflow = true
end
if line:match("link:.-txflow") then
port.txflow = true
end
end
end
swc:close()
if not next(ports) then
return { error = "No such switch" }
end
return { result = ports }
else
return { error = err }
end
end
},
setPassword = {
args = { username = "root", password = "password" },
call = function(args)
local util = require "luci.util"
return {
result = (os.execute("(echo %s; sleep 1; echo %s) | /bin/busybox passwd %s >/dev/null 2>&1" %{
luci.util.shellquote(args.password),
luci.util.shellquote(args.password),
luci.util.shellquote(args.username)
}) == 0)
}
end
},
getBlockDevices = {
call = function()
local fs = require "nixio.fs"
local block = io.popen("/sbin/block info", "r")
if block then
local rv = {}
while true do
local ln = block:read("*l")
if not ln then
break
end
local dev = ln:match("^/dev/(.-):")
if dev then
local s = tonumber((fs.readfile("/sys/class/block/" .. dev .."/size")))
local e = {
dev = "/dev/" .. dev,
size = s and s * 512
}
local key, val = { }
for key, val in ln:gmatch([[(%w+)="(.-)"]]) do
e[key:lower()] = val
end
rv[dev] = e
end
end
block:close()
return rv
else
return { error = "Unable to execute block utility" }
end
end
},
setBlockDetect = {
call = function()
return { result = (os.execute("/sbin/block detect > /etc/config/fstab") == 0) }
end
},
getMountPoints = {
call = function()
local fs = require "nixio.fs"
local fd, err = io.open("/proc/mounts", "r")
if fd then
local rv = {}
while true do
local ln = fd:read("*l")
if not ln then
break
end
local device, mount, fstype, options, freq, pass = ln:match("^(%S*) (%S*) (%S*) (%S*) (%d+) (%d+)$")
if device and mount then
device = device:gsub("\\(%d+)", function(n) return string.char(tonumber(n, 8)) end)
mount = mount:gsub("\\(%d+)", function(n) return string.char(tonumber(n, 8)) end)
local stat = fs.statvfs(mount)
if stat and stat.blocks > 0 then
rv[#rv+1] = {
device = device,
mount = mount,
size = stat.bsize * stat.blocks,
avail = stat.bsize * stat.bavail,
free = stat.bsize * stat.bfree
}
end
end
end
fd:close()
return { result = rv }
else
return { error = err }
end
end
},
getRealtimeStats = {
args = { mode = "interface", device = "eth0" },
call = function(args)
local util = require "luci.util"
local flags
if args.mode == "interface" then
flags = "-i %s" % util.shellquote(args.device)
elseif args.mode == "wireless" then
flags = "-r %s" % util.shellquote(args.device)
elseif args.mode == "conntrack" then
flags = "-c"
elseif args.mode == "load" then
flags = "-l"
else
return { error = "Invalid mode" }
end
local fd, err = io.popen("luci-bwc %s" % flags, "r")
if fd then
local parse = json.new()
local done
parse:parse("[")
while true do
local ln = fd:read("*l")
if not ln then
break
end
done, err = parse:parse((ln:gsub("%d+", "%1.0")))
if done then
err = "Unexpected JSON data"
end
if err then
break
end
end
fd:close()
done, err = parse:parse("]")
if err then
return { error = err }
elseif not done then
return { error = "Incomplete JSON data" }
else
return { result = parse:get() }
end
else
return { error = err }
end
end
},
getConntrackList = {
call = function()
local sys = require "luci.sys"
return { result = sys.net.conntrack() }
end
},
getProcessList = {
call = function()
local sys = require "luci.sys"
local res = {}
for _, v in pairs(sys.process.list()) do
res[#res + 1] = v
end
return { result = res }
end
},
getCPUBench = {
call = function()
local sys = require "luci.sys"
local cpubench = {}
cpubench.cpubench = sys.exec("cat /etc/bench.log 2>/dev/null")
return cpubench
end
},
getCPUInfo = {
call = function()
local sys = require "luci.sys"
local cpuinfo = {}
cpuinfo.cpuinfo = sys.exec("/sbin/cpuinfo")
if (cpuinfo.cpuinfo == nil) or (cpuinfo.cpuinfo == "") then
cpuinfo.cpuinfo = "2.33 MHz +2.33 C"
end
return cpuinfo
end
},
getCPUUsage = {
call = function()
local sys = require "luci.sys"
local cpuusage = {}
cpuusage.cpuusage = sys.exec("top -n1 | awk '/^CPU/ {printf(\"%d%\", 100 - $8)}'") or "6%"
return cpuusage
end
},
getETHInfo = {
call = function()
local sys = require "luci.sys"
local rv = {}
sys.call("/sbin/ethinfo")
local ok, fd = pcall(io.open, "/tmp/state/ethinfo", "r")
local line
for line in fd:lines() do
local line1
line1 = string.split(line , " ")
rv[#rv+1] = {
name = line1[1],
status = line1[2],
speed = line1[3],
duplex = line1[4]
}
end
fd:close()
return { ethinfo = rv }
end
},
getOnlineUsers = {
call = function()
local sys = require "luci.sys"
local onlineusers = {}
onlineusers.onlineusers = sys.exec("cat /proc/net/arp | grep 'br-lan' | grep '0x2' | wc -l")
return onlineusers
end
}
}
local function parseInput()
local parse = json.new()
local done, err
while true do
local chunk = io.read(4096)
if not chunk then
break
elseif not done and not err then
done, err = parse:parse(chunk)
end
end
if not done then
print(json.stringify({ error = err or "Incomplete input" }))
os.exit(1)
end
return parse:get()
end
local function validateArgs(func, uargs)
local method = methods[func]
if not method then
print(json.stringify({ error = "Method not found" }))
os.exit(1)
end
if type(uargs) ~= "table" then
print(json.stringify({ error = "Invalid arguments" }))
os.exit(1)
end
uargs.ubus_rpc_session = nil
local k, v
local margs = method.args or {}
for k, v in pairs(uargs) do
if margs[k] == nil or
(v ~= nil and type(v) ~= type(margs[k]))
then
print(json.stringify({ error = "Invalid arguments" }))
os.exit(1)
end
end
return method
end
if arg[1] == "list" then
local _, method, rv = nil, nil, {}
for _, method in pairs(methods) do rv[_] = method.args or {} end
print((json.stringify(rv):gsub(":%[%]", ":{}")))
elseif arg[1] == "call" then
local args = parseInput()
local method = validateArgs(arg[2], args)
local result, code = method.call(args)
print((json.stringify(result):gsub("^%[%]$", "{}")))
os.exit(code or 0)
end