luci.util = require "luci.util"
luci.ip = require "luci.ip"
-local tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select =
- tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select
+local tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select, unpack =
+ tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select, unpack
module "luci.sys"
exec = luci.util.exec
-function mounts()
- local data = {}
- local k = {"fs", "blocks", "used", "available", "percent", "mountpoint"}
- local ps = luci.util.execi("df")
-
- if not ps then
- return
- else
- ps()
- end
-
- for line in ps do
- local row = {}
-
- local j = 1
- for value in line:gmatch("[^%s]+") do
- row[k[j]] = value
- j = j + 1
- end
-
- if row[k[1]] then
-
- -- this is a rather ugly workaround to cope with wrapped lines in
- -- the df output:
- --
- -- /dev/scsi/host0/bus0/target0/lun0/part3
- -- 114382024 93566472 15005244 86% /mnt/usb
- --
-
- if not row[k[2]] then
- j = 2
- line = ps()
- for value in line:gmatch("[^%s]+") do
- row[k[j]] = value
- j = j + 1
- end
- end
-
- table.insert(data, row)
- end
- end
-
- return data
-end
-
-- containing the whole environment is returned otherwise this function returns
-- the corresponding string value for the given name or nil if no such variable
-- exists.
function httpget(url, stream, target)
if not target then
local source = stream and io.popen or luci.util.exec
- return source("wget -qO- '"..url:gsub("'", "").."'")
+ return source("wget -qO- %s" % luci.util.shellquote(url))
else
- return os.execute("wget -qO '%s' '%s'" %
- {target:gsub("'", ""), url:gsub("'", "")})
+ return os.execute("wget -qO %s %s" %
+ {luci.util.shellquote(target), luci.util.shellquote(url)})
end
end
net = {}
local function _nethints(what, callback)
- local _, k, e, mac, ip, name
+ local _, k, e, mac, ip, name, duid, iaid
local cur = uci.cursor()
local ifn = { }
local hosts = { }
+ local lookup = { }
local function _add(i, ...)
local k = select(i, ...)
luci.ip.neighbors(nil, function(neigh)
if neigh.mac and neigh.family == 4 then
- _add(what, neigh.mac:upper(), neigh.dest:string(), nil, nil)
+ _add(what, neigh.mac:string(), neigh.dest:string(), nil, nil)
elseif neigh.mac and neigh.family == 6 then
- _add(what, neigh.mac:upper(), nil, neigh.dest:string(), nil)
+ _add(what, neigh.mac:string(), nil, neigh.dest:string(), nil)
end
end)
if fs.access("/etc/ethers") then
for e in io.lines("/etc/ethers") do
- mac, ip = e:match("^([a-f0-9]%S+) (%S+)")
- if mac and ip then
- _add(what, mac:upper(), ip, nil, nil)
+ mac, name = e:match("^([a-fA-F0-9:-]+)%s+(%S+)")
+ mac = luci.ip.checkmac(mac)
+ if mac and name then
+ if luci.ip.checkip4(name) then
+ _add(what, mac, name, nil, nil)
+ else
+ _add(what, mac, nil, nil, name)
+ end
end
end
end
if s.leasefile and fs.access(s.leasefile) then
for e in io.lines(s.leasefile) do
mac, ip, name = e:match("^%d+ (%S+) (%S+) (%S+)")
+ mac = luci.ip.checkmac(mac)
if mac and ip then
- _add(what, mac:upper(), ip, nil, name ~= "*" and name)
+ _add(what, mac, ip, nil, name ~= "*" and name)
+ end
+ end
+ end
+ end
+ )
+
+ cur:foreach("dhcp", "odhcpd",
+ function(s)
+ if type(s.leasefile) == "string" and fs.access(s.leasefile) then
+ for e in io.lines(s.leasefile) do
+ duid, iaid, name, _, ip = e:match("^# %S+ (%S+) (%S+) (%S+) (-?%d+) %S+ %S+ ([0-9a-f:.]+)/[0-9]+")
+ mac = net.duid_to_mac(duid)
+ if mac then
+ if ip and iaid == "ipv4" then
+ _add(what, mac, ip, nil, name ~= "*" and name)
+ elseif ip then
+ _add(what, mac, nil, ip, name ~= "*" and name)
+ end
end
end
end
cur:foreach("dhcp", "host",
function(s)
for mac in luci.util.imatch(s.mac) do
- _add(what, mac:upper(), s.ip, nil, s.name)
+ mac = luci.ip.checkmac(mac)
+ if mac then
+ _add(what, mac, s.ip, nil, s.name)
+ end
end
end)
end
end
+ for _, e in pairs(hosts) do
+ lookup[#lookup+1] = (what > 1) and e[what] or (e[2] or e[3])
+ end
+
+ if #lookup > 0 then
+ lookup = luci.util.ubus("network.rrdns", "lookup", {
+ addrs = lookup,
+ timeout = 250,
+ limit = 1000
+ }) or { }
+ end
+
for _, e in luci.util.kspairs(hosts) do
- callback(e[1], e[2], e[3], e[4])
+ callback(e[1], e[2], e[3], lookup[e[2]] or lookup[e[3]] or e[4])
end
end
function net.mac_hints(callback)
if callback then
_nethints(1, function(mac, v4, v6, name)
- name = name or nixio.getnameinfo(v4 or v6, nil, 100) or v4
+ name = name or v4
if name and name ~= mac then
- callback(mac, name or nixio.getnameinfo(v4 or v6, nil, 100) or v4)
+ callback(mac, name or v4)
end
end)
else
local rv = { }
_nethints(1, function(mac, v4, v6, name)
- name = name or nixio.getnameinfo(v4 or v6, nil, 100) or v4
+ name = name or v4
if name and name ~= mac then
- rv[#rv+1] = { mac, name or nixio.getnameinfo(v4 or v6, nil, 100) or v4 }
+ rv[#rv+1] = { mac, name or v4 }
end
end)
return rv
function net.ipv4_hints(callback)
if callback then
_nethints(2, function(mac, v4, v6, name)
- name = name or nixio.getnameinfo(v4, nil, 100) or mac
+ name = name or mac
if name and name ~= v4 then
callback(v4, name)
end
else
local rv = { }
_nethints(2, function(mac, v4, v6, name)
- name = name or nixio.getnameinfo(v4, nil, 100) or mac
+ name = name or mac
if name and name ~= v4 then
rv[#rv+1] = { v4, name }
end
function net.ipv6_hints(callback)
if callback then
_nethints(3, function(mac, v4, v6, name)
- name = name or nixio.getnameinfo(v6, nil, 100) or mac
+ name = name or mac
if name and name ~= v6 then
callback(v6, name)
end
else
local rv = { }
_nethints(3, function(mac, v4, v6, name)
- name = name or nixio.getnameinfo(v6, nil, 100) or mac
+ name = name or mac
if name and name ~= v6 then
rv[#rv+1] = { v6, name }
end
function net.devices()
local devs = {}
+ local seen = {}
for k, v in ipairs(nixio.getifaddrs()) do
- if v.family == "packet" then
+ if v.name and not seen[v.name] then
+ seen[v.name] = true
devs[#devs+1] = v.name
end
end
return devs
end
+function net.duid_to_mac(duid)
+ local b1, b2, b3, b4, b5, b6
+
+ if type(duid) == "string" then
+ -- DUID-LLT / Ethernet
+ if #duid == 28 then
+ b1, b2, b3, b4, b5, b6 = duid:match("^00010001(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)%x%x%x%x%x%x%x%x$")
+
+ -- DUID-LL / Ethernet
+ elseif #duid == 20 then
+ b1, b2, b3, b4, b5, b6 = duid:match("^00030001(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)$")
+
+ -- DUID-LL / Ethernet (Without Header)
+ elseif #duid == 12 then
+ b1, b2, b3, b4, b5, b6 = duid:match("^(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)$")
+ end
+ end
+
+ return b1 and luci.ip.checkmac(table.concat({ b1, b2, b3, b4, b5, b6 }, ":"))
+end
process = {}
for line in ps do
local pid, ppid, user, stat, vsz, mem, cpu, cmd = line:match(
- "^ *(%d+) +(%d+) +(%S.-%S) +([RSDZTW][W ][<N ]) +(%d+) +(%d+%%) +(%d+%%) +(.+)"
+ "^ *(%d+) +(%d+) +(%S.-%S) +([RSDZTW][<NW ][<N ]) +(%d+) +(%d+%%) +(%d+%%) +(.+)"
)
local idx = tonumber(pid)
- if idx then
+ if idx and not cmd:match("top %-bn1") then
data[idx] = {
['PID'] = pid,
['PPID'] = ppid,
process.signal = nixio.kill
+local function xclose(fd)
+ if fd and fd:fileno() > 2 then
+ fd:close()
+ end
+end
+
+function process.exec(command, stdout, stderr, nowait)
+ local out_r, out_w, err_r, err_w
+ if stdout then out_r, out_w = nixio.pipe() end
+ if stderr then err_r, err_w = nixio.pipe() end
+
+ local pid = nixio.fork()
+ if pid == 0 then
+ nixio.chdir("/")
+
+ local null = nixio.open("/dev/null", "w+")
+ if null then
+ nixio.dup(out_w or null, nixio.stdout)
+ nixio.dup(err_w or null, nixio.stderr)
+ nixio.dup(null, nixio.stdin)
+ xclose(out_w)
+ xclose(out_r)
+ xclose(err_w)
+ xclose(err_r)
+ xclose(null)
+ end
+
+ nixio.exec(unpack(command))
+ os.exit(-1)
+ end
+
+ local _, pfds, rv = nil, {}, { code = -1, pid = pid }
+
+ xclose(out_w)
+ xclose(err_w)
+
+ if out_r then
+ pfds[#pfds+1] = {
+ fd = out_r,
+ cb = type(stdout) == "function" and stdout,
+ name = "stdout",
+ events = nixio.poll_flags("in", "err", "hup")
+ }
+ end
+
+ if err_r then
+ pfds[#pfds+1] = {
+ fd = err_r,
+ cb = type(stderr) == "function" and stderr,
+ name = "stderr",
+ events = nixio.poll_flags("in", "err", "hup")
+ }
+ end
+
+ while #pfds > 0 do
+ local nfds, err = nixio.poll(pfds, -1)
+ if not nfds and err ~= nixio.const.EINTR then
+ break
+ end
+
+ local i
+ for i = #pfds, 1, -1 do
+ local rfd = pfds[i]
+ if rfd.revents > 0 then
+ local chunk, err = rfd.fd:read(4096)
+ if chunk and #chunk > 0 then
+ if rfd.cb then
+ rfd.cb(chunk)
+ else
+ rfd.buf = rfd.buf or {}
+ rfd.buf[#rfd.buf + 1] = chunk
+ end
+ else
+ table.remove(pfds, i)
+ if rfd.buf then
+ rv[rfd.name] = table.concat(rfd.buf, "")
+ end
+ rfd.fd:close()
+ end
+ end
+ end
+ end
+
+ if not nowait then
+ _, _, rv.code = nixio.waitpid(pid)
+ end
+
+ return rv
+end
+
user = {}
end
function user.setpasswd(username, password)
- if password then
- password = password:gsub("'", [['"'"']])
- end
-
- if username then
- username = username:gsub("'", [['"'"']])
- end
-
- return os.execute(
- "(echo '" .. password .. "'; sleep 1; echo '" .. password .. "') | " ..
- "passwd '" .. username .. "' >/dev/null 2>&1"
- )
+ return os.execute("(echo %s; sleep 1; echo %s) | passwd %s >/dev/null 2>&1" %{
+ luci.util.shellquote(password),
+ luci.util.shellquote(password),
+ luci.util.shellquote(username)
+ })
end
wifi = {}
function wifi.getiwinfo(ifname)
- local stat, iwinfo = pcall(require, "iwinfo")
-
- if ifname then
- local d, n = ifname:match("^(%w+)%.network(%d+)")
- local wstate = luci.util.ubus("network.wireless", "status") or { }
-
- d = d or ifname
- n = n and tonumber(n) or 1
-
- if type(wstate[d]) == "table" and
- type(wstate[d].interfaces) == "table" and
- type(wstate[d].interfaces[n]) == "table" and
- type(wstate[d].interfaces[n].ifname) == "string"
- then
- ifname = wstate[d].interfaces[n].ifname
- else
- ifname = d
- end
+ local ntm = require "luci.model.network"
- local t = stat and iwinfo.type(ifname)
- local x = t and iwinfo[t] or { }
- return setmetatable({}, {
- __index = function(t, k)
- if k == "ifname" then
- return ifname
- elseif x[k] then
- return x[k](ifname)
- end
- end
- })
+ ntm.init()
+
+ local wnet = ntm:get_wifinet(ifname)
+ if wnet and wnet.iwinfo then
+ return wnet.iwinfo
+ end
+
+ local wdev = ntm:get_wifidev(ifname)
+ if wdev and wdev.iwinfo then
+ return wdev.iwinfo
end
+
+ return { ifname = ifname }
end
end
function init.enable(name)
- return (init_action("enable", name) == 1)
+ return (init_action("enable", name) == 0)
end
function init.disable(name)
function init.stop(name)
return (init_action("stop", name) == 0)
end
+
+function init.restart(name)
+ return (init_action("restart", name) == 0)
+end
+
+function init.reload(name)
+ return (init_action("reload", name) == 0)
+end