]]--
+
+local io = require "io"
+local os = require "os"
+local posix = require "posix"
+local table = require "table"
+
+local luci = {}
+luci.util = require "luci.util"
+luci.fs = require "luci.fs"
+luci.ip = require "luci.ip"
+
+local tonumber, ipairs, pairs = tonumber, ipairs, pairs
+
+
--- LuCI Linux and POSIX system utilities.
-module("luci.sys", package.seeall)
-require("posix")
-require("luci.bits")
-require("luci.util")
-require("luci.fs")
-require("luci.ip")
+module "luci.sys"
+
+--- Execute a given shell command and return the error code
+-- @class function
+-- @name call
+-- @param ... Command to call
+-- @return Error code of the command
+function call(...)
+ return os.execute(...) / 256
+end
+
+--- Execute a given shell command and capture its standard output
+-- @class function
+-- @name exec
+-- @param command Command to call
+-- @return String containg the return the output of the command
+exec = luci.util.exec
--- Invoke the luci-flash executable to write an image to the flash memory.
+-- @param image Local path or URL to image file
-- @param kpattern Pattern of files to keep over flash process
--- @return Return value of os.execute()
+-- @return boolean indicating status
+-- @return error message if any
function flash(image, kpattern)
local cmd = "luci-flash "
if kpattern then
cmd = cmd .. "-k '" .. kpattern:gsub("'", "") .. "' "
end
- cmd = cmd .. "'" .. image:gsub("'", "") .. "' >/dev/null 2>&1"
+ cmd = cmd .. "'" .. image:gsub("'", "") .. "' 2>/dev/null"
+
+ local fp = io.popen(cmd)
+ fp:setvbuf("no")
+
+ local line = fp:read()
+
+ if line == "Invalid image type" then
+ fp:close()
+ return false, line
+ else
+ line = fp:read()
+ if line == "Performing system upgrade..." then
+ return true
+ end
+
+ line = fp:read()
+ if line == "Performing system upgrade..." then
+ return true
+ end
+
+ fp:close()
+ return false, line
+ end
+end
- return os.execute(cmd)
+--- Retrieve information about currently mounted file systems.
+-- @return Table containing mount information
+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
+ table.insert(data, row)
+ end
+ end
+
+ return data
end
--- Retrieve environment variables. If no variable is given then a table
--- Returns the contents of a documented referred by an URL.
-- @param url The URL to retrieve
-- @param stream Return a stream instead of a buffer
+-- @param target Directly write to target file name
-- @return String containing the contents of given the URL
-function httpget(url, stream)
- local source = stream and io.open or luci.util.exec
- return source("wget -qO- '"..url:gsub("'", "").."'")
+function httpget(url, stream, target)
+ if not target then
+ local source = stream and io.open or luci.util.exec
+ return source("wget -qO- '"..url:gsub("'", "").."'")
+ else
+ return os.execute("wget -qO '%s' '%s'" %
+ {target:gsub("'", ""), url:gsub("'", "")})
+ end
end
--- Returns the system load average values.
-- @return String containing the memory used for caching in kB
-- @return String containing the memory used for buffering in kB
-- @return String containing the free memory amount in kB
--- @return Number containing free memory in percent
--- @return Number containing buffer memory in percent
--- @return Number containing cache memory in percent
function sysinfo()
local c1 = "cat /proc/cpuinfo|grep system\\ typ|cut -d: -f2 2>/dev/null"
local c2 = "uname -m 2>/dev/null"
local system = luci.util.trim(luci.util.exec(c1))
local model = ""
- local memtotal = luci.util.trim(luci.util.exec(c5))
- local memcached = luci.util.trim(luci.util.exec(c6))
- local memfree = luci.util.trim(luci.util.exec(c7))
- local membuffers = luci.util.trim(luci.util.exec(c8))
- local perc_memfree = math.floor((memfree/memtotal)*100)
- local perc_membuffers = math.floor((membuffers/memtotal)*100)
- local perc_memcached = math.floor((memcached/memtotal)*100)
+ local memtotal = tonumber(luci.util.trim(luci.util.exec(c5)))
+ local memcached = tonumber(luci.util.trim(luci.util.exec(c6)))
+ local memfree = tonumber(luci.util.trim(luci.util.exec(c7)))
+ local membuffers = tonumber(luci.util.trim(luci.util.exec(c8)))
if system == "" then
system = luci.util.trim(luci.util.exec(c2))
model = luci.util.trim(luci.util.exec(c4))
end
- return system, model, memtotal, memcached, membuffers, memfree, perc_memfree, perc_membuffers, perc_memcached
+ return system, model, memtotal, memcached, membuffers, memfree
end
--- Retrieves the output of the "logread" command.
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
return devices
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)
+ end
+ end
+ return devices
+end
+
+
-- Determine the MAC address belonging to the given IP address.
-- @param ip IPv4 address
-- @return String containing the MAC address or nil if it cannot be found
process = {}
--- Get the current process id.
+-- @class function
+-- @name process.info
-- @return Number containing the current pid
process.info = posix.getpid
+--- Retrieve information about currently running processes.
+-- @return Table containing process information
+function process.list()
+ local data = {}
+ local k
+ local ps = luci.util.execi("top -bn1")
+
+ if not ps then
+ return
+ end
+
+ while true do
+ local line = ps()
+ if not line then
+ return
+ end
+
+ k = luci.util.split(luci.util.trim(line), "%s+", nil, true)
+ if k[1] == "PID" then
+ break
+ end
+ end
+
+ for line in ps do
+ local row = {}
+
+ line = luci.util.trim(line)
+ for i, value in ipairs(luci.util.split(line, "%s+", #k-1, true)) do
+ row[k[i]] = value
+ end
+
+ local pid = tonumber(row[k[1]])
+ if pid then
+ data[pid] = row
+ end
+ end
+
+ return data
+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 posix.setpid("u", pid, uid)
end
+--- Send a signal to a process identified by given pid.
+-- @class function
+-- @name process.signal
+-- @param pid Number containing the process id
+-- @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
+
--- LuCI system utilities / user related functions.
-- @class module
function user.checkpasswd(username, password)
local account = user.getuser(username)
- -- FIXME: detect testing environment
- if luci.fs.stat("/etc/shadow") and not luci.fs.access("/etc/shadow", "r") then
- return true
- elseif account then
+ if account then
if account.passwd == "!" then
return true
else
--- Get iwlist scan output from all wireless devices.
-- @return Table of tables contaiing all scan results
-function wifi.iwscan()
- local cnt = luci.util.exec("iwlist scan 2>/dev/null")
+function wifi.iwscan(iface)
+ local siface = iface or ""
+ local cnt = luci.util.exec("iwlist "..siface.." scan 2>/dev/null")
local iws = {}
for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n\n")) do
end
end
- return iws
+ return iface and (iws[iface] or {}) or iws
end