commit 781fcd76d5706b0450ce0caa62da997f97af1df1 Author: sbwml Date: Tue Jul 26 06:32:34 2022 +0800 autocore - from https://github.com/immortalwrt/immortalwrt/tree/master/package/emortal/autocore diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8242911 --- /dev/null +++ b/Makefile @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: GPL-3.0-only +# +# Copyright (C) 2020 Lean +# Copyright (C) 2021 ImmortalWrt.org + +include $(TOPDIR)/rules.mk + +PKG_NAME:=autocore +PKG_FLAGS:=nonshared +PKG_RELEASE:=$(COMMITCOUNT) + +PKG_CONFIG_DEPENDS:= \ + CONFIG_TARGET_bcm27xx \ + CONFIG_TARGET_bcm53xx + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/target.mk + +define Package/autocore-arm + TITLE:=ARM auto core script. + MAINTAINER:=CN_SZTL + DEPENDS:=@(arm||aarch64) \ + +TARGET_bcm27xx:bcm27xx-userland \ + +TARGET_bcm53xx:nvram + VARIANT:=arm +endef + +define Package/autocore-x86 + TITLE:=x86/x64 auto core loadbalance script. + MAINTAINER:=Lean / CN_SZTL + DEPENDS:=@TARGET_x86 +lm-sensors +ethtool + VARIANT:=x86 +endef + +define Build/Compile +endef + +define Package/autocore/install/Default + $(INSTALL_DIR) $(1)/etc + $(CP) ./files/generic/10_system.js $(1)/etc/rpcd_10_system.js + $(CP) ./files/generic/luci $(1)/etc/rpcd_luci + + $(INSTALL_DIR) $(1)/etc/uci-defaults + $(INSTALL_BIN) ./files/generic/090-cover-index_files $(1)/etc/uci-defaults/ + + $(INSTALL_DIR) $(1)/sbin + $(INSTALL_BIN) ./files/generic/cpuinfo $(1)/sbin/ + $(INSTALL_BIN) ./files/generic/ethinfo $(1)/sbin/ + + $(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d + $(CP) ./files/generic/luci-mod-status-autocore.json $(1)/usr/share/rpcd/acl.d/ + + $(INSTALL_DIR) $(1)/www/luci-static/resources/view/status/include + $(INSTALL_DATA) ./files/generic/29_ethinfo.js $(1)/www/luci-static/resources/view/status/include/ +endef + +define Package/autocore-arm/install + $(call Package/autocore/install/Default,$(1)) + +ifneq ($(filter ipq% %mt7622, $(TARGETID)),) + $(INSTALL_BIN) ./files/arm/tempinfo $(1)/sbin/ +endif +endef + +define Package/autocore-x86/install + $(call Package/autocore/install/Default,$(1)) + + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/x86/autocore $(1)/etc/init.d/ +endef + +$(eval $(call BuildPackage,autocore-arm)) +$(eval $(call BuildPackage,autocore-x86)) diff --git a/files/arm/tempinfo b/files/arm/tempinfo new file mode 100755 index 0000000..22877a7 --- /dev/null +++ b/files/arm/tempinfo @@ -0,0 +1,21 @@ +#!/bin/sh + +IEEE_PATH="/sys/class/ieee80211" +THERMAL_PATH="/sys/class/thermal" + +if grep -Eq "ipq40xx|ipq806x" "/etc/openwrt_release"; then + wifi_temp="$(awk '{printf("%.1f°C ", $0 / 1000)}' "$IEEE_PATH"/phy*/device/hwmon/hwmon*/temp1_input | awk '$1=$1')" +else + wifi_temp="$(awk '{printf("%.1f°C ", $0 / 1000)}' "$IEEE_PATH"/phy*/hwmon*/temp1_input | awk '$1=$1')" +fi + +if grep -q "ipq40xx" "/etc/openwrt_release"; then + if [ -e "$IEEE_PATH/phy0/hwmon0/temp1_input" ]; then + mt76_temp=" $(awk -F ': ' '{print $2}' "$IEEE_PATH/phy0/hwmon0/temp1_input")°C" + fi + + echo -n "WiFi:${mt76_temp} ${wifi_temp}" +else + cpu_temp="$(awk '{printf("%.1f°C", $0 / 1000)}' "$THERMAL_PATH/thermal_zone0/temp")" + echo -n "CPU: ${cpu_temp}, WiFi: ${wifi_temp}" +fi diff --git a/files/generic/090-cover-index_files b/files/generic/090-cover-index_files new file mode 100755 index 0000000..8480059 --- /dev/null +++ b/files/generic/090-cover-index_files @@ -0,0 +1,9 @@ +#!/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' +/etc/init.d/rpcd restart + +exit 0 diff --git a/files/generic/10_system.js b/files/generic/10_system.js new file mode 100644 index 0000000..0352649 --- /dev/null +++ b/files/generic/10_system.js @@ -0,0 +1,114 @@ +'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' +}); + +var callTempInfo = rpc.declare({ + object: 'luci', + method: 'getTempInfo' +}); + +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(), {}), + L.resolveDefault(callTempInfo(), {}), + 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], + tempinfo = data[5], + luciversion = data[6]; + + 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, + _('Architecture'), 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 + ]; + + if (tempinfo.tempinfo) { + fields.splice(6, 0, _('Temperature')); + fields.splice(7, 0, tempinfo.tempinfo); + } + + 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; + } +}); diff --git a/files/generic/29_ethinfo.js b/files/generic/29_ethinfo.js new file mode 100644 index 0000000..fa89c4a --- /dev/null +++ b/files/generic/29_ethinfo.js @@ -0,0 +1,60 @@ +'use strict'; +'require baseclass'; +'require rpc'; + +var callLuciETHInfo = rpc.declare({ + object: 'luci', + method: 'getETHInfo', + expect: { '': {} } +}); + +return L.Class.extend({ + title: _('Ethernet Information'), + + load: function() { + return Promise.all([ + L.resolveDefault(callLuciETHInfo(), {}) + ]); + }, + + render: function(data) { + var ethinfo = Array.isArray(data[0].ethinfo) ? data[0].ethinfo : []; + + var table = E('table', { 'class': 'table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th' }, _('Ethernet Name')), + E('th', { 'class': 'th' }, _('Link Status')), + E('th', { 'class': 'th' }, _('Speed')), + E('th', { 'class': 'th' }, _('Duplex')) + ]) + ]); + + cbi_update_table(table, ethinfo.map(function(info) { + var exp1; + var exp2; + + if (info.status == "yes") + exp1 = _('Link Up'); + else if (info.status == "no") + exp1 = _('Link Down'); + + if (info.duplex == "Full") + exp2 = _('Full Duplex'); + else if (info.duplex == "Half") + exp2 = _('Half Duplex'); + else + exp2 = _('-'); + + return [ + info.name, + exp1, + info.speed, + exp2 + ]; + })); + + return E([ + table + ]); + } +}); diff --git a/files/generic/cpuinfo b/files/generic/cpuinfo new file mode 100755 index 0000000..e92c0af --- /dev/null +++ b/files/generic/cpuinfo @@ -0,0 +1,61 @@ +#!/bin/sh + +. /etc/openwrt_release + +CPUINFO_PATH="/proc/cpuinfo" +CPUFREQ_PATH="/sys/devices/system/cpu/cpufreq" +THERMAL_PATH="/sys/class/thermal" + +cpu_arch="$(awk -F ': ' '/model name/ {print $2}' "$CPUINFO_PATH" | head -n1)" +[ -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="$(awk -F ': ' '/BogoMIPS/ {print $2}' "$CPUINFO_PATH" | head -n1)MHz" ;; +"x86"/*) + cpu_freq="$(awk -F ': ' '/MHz/ {print $2}' "$CPUINFO_PATH" | head -n1)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" | awk '/Tdie/ {print $2}' | head -n1 | 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" ] || \ + grep -Eq "ipq|mt7622" "/etc/openwrt_release"; 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 diff --git a/files/generic/ethinfo b/files/generic/ethinfo new file mode 100755 index 0000000..68f2917 --- /dev/null +++ b/files/generic/ethinfo @@ -0,0 +1,39 @@ +#!/usr/bin/lua +-- Copyright (C) 2022 Tianling Shen + +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)) diff --git a/files/generic/luci b/files/generic/luci new file mode 100755 index 0000000..06ae4c1 --- /dev/null +++ b/files/generic/luci @@ -0,0 +1,748 @@ +#!/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/dsl_cpe_control") or 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 = "? x ? (2.33MHz, 2.33°C)" + end + + return cpuinfo + end + }, + + getCPUUsage = { + call = function() + local sys = require "luci.sys" + local cpuusage = {} + + cpuusage.cpuusage = sys.exec("busybox top -n1 | awk '/^CPU/ {printf(\"%d%%\", 100 - $8)}'") or "6%" + return cpuusage + 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" + local onlineusers = {} + + onlineusers.onlineusers = sys.exec("cat /proc/net/arp | grep 'br-lan' | grep '0x2' | wc -l") + return onlineusers + + end + }, + + getTempInfo = { + call = function() + local sys = require "luci.sys" + local tempinfo = {} + + tempinfo.tempinfo = sys.exec("/sbin/tempinfo 2>/dev/null") + return tempinfo + 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 diff --git a/files/generic/luci-mod-status-autocore.json b/files/generic/luci-mod-status-autocore.json new file mode 100644 index 0000000..47c4d33 --- /dev/null +++ b/files/generic/luci-mod-status-autocore.json @@ -0,0 +1,10 @@ +{ + "luci-mod-status-autocore": { + "description": "Grant access to autocore", + "read": { + "ubus": { + "luci": [ "getCPUInfo", "getETHInfo", "getTempInfo", "getCPUBench", "getCPUUsage" ] + } + } + } +} diff --git a/files/x86/autocore b/files/x86/autocore new file mode 100755 index 0000000..1fcb9dc --- /dev/null +++ b/files/x86/autocore @@ -0,0 +1,39 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2017 lean + +START=99 + +start() { + rfc=4096 + 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 "$threads" > "$fileRps" + done + + for fileRfc in /sys/class/net/eth*/queues/rx-*/rps_flow_cnt + do + echo "$rfc" > "$fileRfc" + done + + uci set network.@globals[0].packet_steering="1" + uci commit network + + for i in $(ip address | awk -F ': ' '/eth[0-9]+/ {print $2}' | xargs) + do + { + 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 +} >"/dev/null" 2>&1