]]--
-local io = require "io"
-local os = require "os"
-local posix = require "posix"
-local table = require "table"
+local io = require "io"
+local os = require "os"
+local table = require "table"
+local nixio = require "nixio"
+local fs = require "nixio.fs"
+local iwinfo = require "iwinfo"
local luci = {}
luci.util = require "luci.util"
-luci.fs = require "luci.fs"
luci.ip = require "luci.ip"
-local tonumber, ipairs, pairs, pcall, type =
- tonumber, ipairs, pairs, pcall, type
+local tonumber, ipairs, pairs, pcall, type, next, setmetatable =
+ tonumber, ipairs, pairs, pcall, type, next, setmetatable
--- LuCI Linux and POSIX system utilities.
-- @param var Name of the environment variable to retrieve (optional)
-- @return String containg the value of the specified variable
-- @return Table containing all variables if no variable name is given
-getenv = posix.getenv
+getenv = nixio.getenv
--- Get or set the current hostname.
-- @param String containing a new hostname to set (optional)
-- @return String containing the system hostname
function hostname(newname)
if type(newname) == "string" and #newname > 0 then
- luci.fs.writefile( "/proc/sys/kernel/hostname", newname .. "\n" )
+ fs.writefile( "/proc/sys/kernel/hostname", newname )
return newname
else
- return posix.uname("%n")
+ return nixio.uname().nodename
end
end
-- @return String containing the average load value 1 minute ago
-- @return String containing the average load value 5 minutes ago
-- @return String containing the average load value 15 minutes ago
--- @return String containing the active and total number of processes
--- @return String containing the last used pid
function loadavg()
- local loadavg = io.lines("/proc/loadavg")()
- return loadavg:match("^(.-) (.-) (.-) (.-) (.-)$")
+ local info = nixio.sysinfo()
+ return info.loads[1], info.loads[2], info.loads[3]
end
--- Initiate a system reboot.
-- @return String containing the memory used for buffering in kB
-- @return String containing the free memory amount in kB
function sysinfo()
- local cpuinfo = luci.fs.readfile("/proc/cpuinfo")
- local meminfo = luci.fs.readfile("/proc/meminfo")
+ local cpuinfo = fs.readfile("/proc/cpuinfo")
+ local meminfo = fs.readfile("/proc/meminfo")
local system = cpuinfo:match("system typ.-:%s*([^\n]+)")
local model = ""
local membuffers = tonumber(meminfo:match("Buffers:%s*(%d+)"))
if not system then
- system = posix.uname("%m")
+ system = nixio.uname().machine
model = cpuinfo:match("model name.-:%s*([^\n]+)")
if not model then
model = cpuinfo:match("Processor.-:%s*([^\n]+)")
-- @param bytes Number of bytes for the unique id
-- @return String containing hex encoded id
function uniqueid(bytes)
- local fp = io.open("/dev/urandom")
- local chunk = { fp:read(bytes):byte(1, bytes) }
- fp:close()
-
- local hex = ""
-
- local pattern = "%02X"
- for i, byte in ipairs(chunk) do
- hex = hex .. pattern:format(byte)
- end
-
- return hex
+ local rand = fs.readfile("/dev/urandom", bytes)
+ return rand and nixio.bin.hexlify(rand)
end
--- Returns the current system uptime stats.
-- @return String containing total uptime in seconds
--- @return String containing idle time in seconds
function uptime()
- local loadavg = io.lines("/proc/uptime")()
- return loadavg:match("^(.-) (.-)$")
+ return nixio.sysinfo().uptime
end
---- LuCI system utilities / POSIX user group related functions.
--- @class module
--- @name luci.sys.group
-group = {}
-
---- Returns information about a POSIX user group.
--- @class function
--- @name getgroup
--- @param group Group ID or name of a system user group
--- @return Table with information about the requested group
-group.getgroup = posix.getgroup
-
--- LuCI system utilities / network related functions.
-- @class module
-- @return Table of table containing the current arp entries.
-- The following fields are defined for arp entry objects:
-- { "IP address", "HW address", "HW type", "Flags", "Mask", "Device" }
-function net.arptable()
- return _parse_delimited_table(io.lines("/proc/net/arp"), "%s%s+")
+function net.arptable(callback)
+ return _parse_delimited_table(io.lines("/proc/net/arp"), "%s%s+", callback)
end
--- Returns conntrack information
-- @return Table with the currently tracked IP connections
-function net.conntrack()
+function net.conntrack(callback)
local connt = {}
- if luci.fs.access("/proc/net/nf_conntrack", "r") then
+ if fs.access("/proc/net/nf_conntrack", "r") then
for line in io.lines("/proc/net/nf_conntrack") do
line = line:match "^(.-( [^ =]+=).-)%2"
local entry, flags = _parse_mixed_record(line, " +")
entry[i] = nil
end
- connt[#connt+1] = entry
+ if callback then
+ callback(entry)
+ else
+ connt[#connt+1] = entry
+ end
end
- elseif luci.fs.access("/proc/net/ip_conntrack", "r") then
+ elseif fs.access("/proc/net/ip_conntrack", "r") then
for line in io.lines("/proc/net/ip_conntrack") do
line = line:match "^(.-( [^ =]+=).-)%2"
local entry, flags = _parse_mixed_record(line, " +")
entry[i] = nil
end
- connt[#connt+1] = entry
+ if callback then
+ callback(entry)
+ else
+ connt[#connt+1] = entry
+ end
end
else
return nil
-- { "dest", "gateway", "metric", "refcount", "usecount", "irtt",
-- "flags", "device" }
function net.defaultroute()
- local route = nil
- for _, r in pairs(net.routes()) do
- if r.dest:prefix() == 0 and (not route or route.metric > r.metric) then
- route = r
+ local route
+
+ net.routes(function(rt)
+ if rt.dest:prefix() == 0 and (not route or route.metric > rt.metric) then
+ route = rt
end
- end
+ end)
+
return route
end
-- { "source", "dest", "nexthop", "metric", "refcount", "usecount",
-- "flags", "device" }
function net.defaultroute6()
- local route = nil
- local routes6 = net.routes6()
- if routes6 then
- for _, r in pairs(routes6) do
- if r.dest:prefix() == 0 and
- (not route or route.metric > r.metric)
- then
- route = r
- end
+ local route
+
+ net.routes6(function(rt)
+ if rt.dest:prefix() == 0 and (not route or route.metric > rt.metric) then
+ route = rt
end
- end
+ end)
+
return route
end
--- Determine the names of available network interfaces.
-- @return Table containing all current interface names
function net.devices()
- local devices = {}
- for line in io.lines("/proc/net/dev") do
- table.insert(devices, line:match(" *(.-):"))
+ local devs = {}
+ for k, v in ipairs(nixio.getifaddrs()) do
+ if v.family == "packet" then
+ devs[#devs+1] = v.name
+ end
end
- return devices
+ return devs
end
--- Return information about available network interfaces.
-- @return Table containing all current interface names and their information
function net.deviceinfo()
- local devices = {}
- for line in io.lines("/proc/net/dev") do
- local name, data = line:match("^ *(.-): *(.*)$")
- if name and data then
- devices[name] = luci.util.split(data, " +", nil, true)
+ local devs = {}
+ for k, v in ipairs(nixio.getifaddrs()) do
+ if v.family == "packet" then
+ local d = v.data
+ d[1] = d.rx_bytes
+ d[2] = d.rx_packets
+ d[3] = d.rx_errors
+ d[4] = d.rx_dropped
+ d[5] = 0
+ d[6] = 0
+ d[7] = 0
+ d[8] = d.multicast
+ d[9] = d.tx_bytes
+ d[10] = d.tx_packets
+ d[11] = d.tx_errors
+ d[12] = d.tx_dropped
+ d[13] = 0
+ d[14] = d.collisions
+ d[15] = 0
+ d[16] = 0
+ devs[v.name] = d
end
end
- return devices
+ return devs
end
-- @return String containing the MAC address or nil if it cannot be found
function net.ip4mac(ip)
local mac = nil
-
- for i, l in ipairs(net.arptable()) do
- if l["IP address"] == ip then
- mac = l["HW address"]
+ net.arptable(function(e)
+ if e["IP address"] == ip then
+ mac = e["HW address"]
end
- end
-
+ end)
return mac
end
-- The following fields are defined for route entry tables:
-- { "dest", "gateway", "metric", "refcount", "usecount", "irtt",
-- "flags", "device" }
-function net.routes()
+function net.routes(callback)
local routes = { }
for line in io.lines("/proc/net/route") do
dst_ip, dst_mask:prefix(dst_mask), luci.ip.FAMILY_INET4
)
- routes[#routes+1] = {
+ local rt = {
dest = dst_ip,
gateway = gateway,
metric = tonumber(metric),
flags = tonumber(flags, 16),
device = dev
}
+
+ if callback then
+ callback(rt)
+ else
+ routes[#routes+1] = rt
+ end
end
end
-- The following fields are defined for route entry tables:
-- { "source", "dest", "nexthop", "metric", "refcount", "usecount",
-- "flags", "device" }
-function net.routes6()
- if luci.fs.access("/proc/net/ipv6_route", "r") then
+function net.routes6(callback)
+ if fs.access("/proc/net/ipv6_route", "r") then
local routes = { }
for line in io.lines("/proc/net/ipv6_route") do
nexthop = luci.ip.Hex( nexthop, 128, luci.ip.FAMILY_INET6, false )
- routes[#routes+1] = {
+ local rt = {
source = src_ip,
dest = dst_ip,
nexthop = nexthop,
flags = tonumber(flags, 16),
device = dev
}
+
+ if callback then
+ callback(rt)
+ else
+ routes[#routes+1] = rt
+ end
end
return routes
-- @class function
-- @name process.info
-- @return Number containing the current pid
-process.info = posix.getpid
+function process.info(key)
+ local s = {uid = nixio.getuid(), gid = nixio.getgid()}
+ return not key and s or s[key]
+end
--- Retrieve information about currently running processes.
-- @return Table containing process information
end
--- Set the gid of a process identified by given pid.
--- @param pid Number containing the process id
-- @param gid Number containing the Unix group id
-- @return Boolean indicating successful operation
-- @return String containing the error message if failed
-- @return Number containing the error code if failed
-function process.setgroup(pid, gid)
- return posix.setpid("g", pid, gid)
+function process.setgroup(gid)
+ return nixio.setgid(gid)
end
--- Set the uid of a process identified by given pid.
--- @param pid Number containing the process id
-- @param uid Number containing the Unix user id
-- @return Boolean indicating successful operation
-- @return String containing the error message if failed
-- @return Number containing the error code if failed
-function process.setuser(pid, uid)
- return posix.setpid("u", pid, uid)
+function process.setuser(uid)
+ return nixio.setuid(uid)
end
--- Send a signal to a process identified by given pid.
-- @param sig Signal to send (default: 15 [SIGTERM])
-- @return Boolean indicating successful operation
-- @return Number containing the error code if failed
-process.signal = posix.kill
+process.signal = nixio.kill
--- LuCI system utilities / user related functions.
-- @param uid Number containing the Unix user id
-- @return Table containing the following fields:
-- { "uid", "gid", "name", "passwd", "dir", "shell", "gecos" }
-user.getuser = posix.getpasswd
+user.getuser = nixio.getpw
--- Test whether given string matches the password of a given system user.
-- @param username String containing the Unix user name
--- @param password String containing the password to compare
+-- @param pass String containing the password to compare
-- @return Boolean indicating wheather the passwords are equal
-function user.checkpasswd(username, password)
- local account = user.getuser(username)
-
- if account then
- local pwd = account.passwd
- local shadowpw
- if #pwd == 1 then
- if luci.fs.stat("/etc/shadow") then
- if not pcall(function()
- for l in io.lines("/etc/shadow") do
- shadowpw = l:match("^%s:([^:]+)" % username)
- if shadowpw then
- pwd = shadowpw
- break
- end
- end
- end) then
- return nil, "Unable to access shadow-file"
- end
- end
-
- if pwd == "!" then
- return true
- end
- end
-
- if pwd and #pwd > 0 and password and #password > 0 then
- return (pwd == posix.crypt(password, pwd))
- end
+function user.checkpasswd(username, pass)
+ local pwe = nixio.getsp and nixio.getsp(username) or nixio.getpw(username)
+ local pwh = pwe and (pwe.pwdp or pwe.passwd)
+ if not pwh or #pwh < 1 or pwh ~= "!" and nixio.crypt(pass, pwh) ~= pwh then
+ return false
+ else
+ return true
end
-
- return false
end
--- Change the password of given user.
-- @name luci.sys.wifi
wifi = {}
+--- Get wireless information for given interface.
+-- @param ifname String containing the interface name
+-- @return A wrapped iwinfo object instance
+function wifi.getiwinfo(ifname)
+ local t = iwinfo.type(ifname)
+ if t then
+ local x = iwinfo[t]
+ return setmetatable({}, {
+ __index = function(t, k)
+ if x[k] then return x[k](ifname) end
+ end
+ })
+ end
+end
+
--- Get iwconfig output for all wireless devices.
-- @return Table of tables containing the iwconfing output for each wifi device
function wifi.getiwconfig()
local fd = io.popen(cmd)
if fd then
local ln, c, f
- repeat
- ln = fd:read("*l") or ""
+ while true do
+ ln = fd:read("*l")
+ if not ln then break end
c, f = ln:match("Channel (%d+) : (%d+%.%d+) GHz")
if c and f then
cns[tonumber(c)] = tonumber(f)
end
- until not ( #ln > 0 )
+ end
fd:close()
end
- if not ((pairs(cns))(cns)) then
+ if not next(cns) then
cns = {
2.412, 2.417, 2.422, 2.427, 2.432, 2.437,
2.442, 2.447, 2.452, 2.457, 2.462
-- @return Table containing the names of all inistalled init scripts
function init.names()
local names = { }
- for _, name in ipairs(luci.fs.glob(init.dir.."*")) do
- names[#names+1] = luci.fs.basename(name)
+ for name in fs.glob(init.dir.."*") do
+ names[#names+1] = fs.basename(name)
end
return names
end
-- @param name Name of the init script
-- @return Boolean indicating whether init is enabled
function init.enabled(name)
- if luci.fs.access(init.dir..name) then
+ if fs.access(init.dir..name) then
return ( call(init.dir..name.." enabled") == 0 )
end
return false
-- @param name Name of the init script
-- @return Numeric index value
function init.index(name)
- if luci.fs.access(init.dir..name) then
+ if fs.access(init.dir..name) then
return call("source "..init.dir..name.."; exit $START")
end
end
-- @param name Name of the init script
-- @return Boolean indicating success
function init.enable(name)
- if luci.fs.access(init.dir..name) then
+ if fs.access(init.dir..name) then
return ( call(init.dir..name.." enable") == 1 )
end
end
-- @param name Name of the init script
-- @return Boolean indicating success
function init.disable(name)
- if luci.fs.access(init.dir..name) then
+ if fs.access(init.dir..name) then
return ( call(init.dir..name.." disable") == 0 )
end
end
-- Internal functions
-function _parse_delimited_table(iter, delimiter)
+function _parse_delimited_table(iter, delimiter, callback)
delimiter = delimiter or "%s+"
local data = {}
end
end
end
- table.insert(data, row)
+
+ if callback then
+ callback(row)
+ else
+ data[#data+1] = row
+ end
end
return data