X-Git-Url: https://git.archive.openwrt.org/?p=project%2Fluci.git;a=blobdiff_plain;f=libs%2Fsys%2Fluasrc%2Fsys.lua;h=e8b5e2c3a7e0c9f5e967df3eb14a78e0700a00e9;hp=d9f236e1b4d36fe51fc99dc932835358903a6444;hb=758c06df583f439f625d5a62688d291654234e5b;hpb=a0650b4ca96a184887369e04bc4793579364aeef diff --git a/libs/sys/luasrc/sys.lua b/libs/sys/luasrc/sys.lua index d9f236e1b..e8b5e2c3a 100644 --- a/libs/sys/luasrc/sys.lua +++ b/libs/sys/luasrc/sys.lua @@ -35,12 +35,27 @@ luci.util = require "luci.util" luci.fs = require "luci.fs" luci.ip = require "luci.ip" -local tonumber, ipairs, pairs = tonumber, ipairs, pairs +local tonumber, ipairs, pairs, pcall = tonumber, ipairs, pairs, pcall --- LuCI Linux and POSIX system utilities. 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 @@ -62,27 +77,44 @@ 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 @@ -227,6 +259,38 @@ function net.arptable() return _parse_delimited_table(io.lines("/proc/net/arp"), "%s%s+") end +--- Returns conntrack information +-- @return Table with the currently tracked IP connections +function net.conntrack() + local connt = {} + if luci.fs.access("/proc/net/nf_conntrack") then + for line in io.lines("/proc/net/nf_conntrack") do + local entry, flags = _parse_mixed_record(line, " +") + entry.layer3 = flags[1] + entry.layer4 = flags[2] + for i=1, #entry do + entry[i] = nil + end + + connt[#connt+1] = entry + end + elseif luci.fs.access("/proc/net/ip_conntrack") then + for line in io.lines("/proc/net/ip_conntrack") do + local entry, flags = _parse_mixed_record(line, " +") + entry.layer3 = "ipv4" + entry.layer4 = flags[1] + for i=1, #entry do + entry[i] = nil + end + + connt[#connt+1] = entry + end + else + return nil + end + return connt +end + --- Determine the current default route. -- @return Table with the properties of the current default route. -- The following fields are defined: @@ -309,6 +373,8 @@ end process = {} --- Get the current process id. +-- @class function +-- @name process.info -- @return Number containing the current pid process.info = posix.getpid @@ -318,37 +384,37 @@ 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 @@ -373,6 +439,8 @@ function process.setuser(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 @@ -401,12 +469,34 @@ function user.checkpasswd(username, password) local account = user.getuser(username) if account then - if account.passwd == "!" then - return true - else - return (account.passwd == posix.crypt(password, account.passwd)) + 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 end + + return false end --- Change the password of given user. @@ -443,7 +533,11 @@ function wifi.getiwconfig() local k = l:match("^(.-) ") l = l:gsub("^(.-) +", "", 1) if k then - iwc[k] = _parse_mixed_record(l) + local entry, flags = _parse_mixed_record(l) + if entry then + entry.flags = flags + end + iwc[k] = entry end end @@ -467,7 +561,11 @@ function wifi.iwscan(iface) c = c:gsub("^(.-)- ", "", 1) c = luci.util.split(c, "\n", 7) c = table.concat(c, "\n", 1) - table.insert(iws[k], _parse_mixed_record(c)) + local entry, flags = _parse_mixed_record(c) + if entry then + entry.flags = flags + end + table.insert(iws[k], entry) end end end @@ -476,6 +574,60 @@ function wifi.iwscan(iface) end +--- LuCI system utilities / init related functions. +-- @class module +-- @name luci.sys.init +init = {} +init.dir = "/etc/init.d/" + +--- Get the names of all installed init scripts +-- @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) + end + return names +end + +--- Test whether the given init script is enabled +-- @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 + return ( call(init.dir..name.." enabled") == 0 ) + end + return false +end + +--- Get the index of he given init script +-- @param name Name of the init script +-- @return Numeric index value +function init.index(name) + if luci.fs.access(init.dir..name) then + return call("source "..init.dir..name.."; exit $START") + end +end + +--- Enable the given init script +-- @param name Name of the init script +-- @return Boolean indicating success +function init.enable(name) + if luci.fs.access(init.dir..name) then + return ( call(init.dir..name.." enable") == 1 ) + end +end + +--- Disable the given init script +-- @param name Name of the init script +-- @return Boolean indicating success +function init.disable(name) + if luci.fs.access(init.dir..name) then + return ( call(init.dir..name.." disable") == 0 ) + end +end + + -- Internal functions function _parse_delimited_table(iter, delimiter) @@ -506,16 +658,18 @@ function _parse_delimited_table(iter, delimiter) return data end -function _parse_mixed_record(cnt) +function _parse_mixed_record(cnt, delimiter) + delimiter = delimiter or " " local data = {} + local flags = {} for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n")) do - for j, f in pairs(luci.util.split(luci.util.trim(l), " ")) do + for j, f in pairs(luci.util.split(luci.util.trim(l), delimiter, nil, true)) do local k, x, v = f:match('([^%s][^:=]+) *([:=]*) *"*([^\n"]*)"*') if k then if x == "" then - table.insert(data, k) + table.insert(flags, k) else data[k] = v end @@ -523,5 +677,5 @@ function _parse_mixed_record(cnt) end end - return data + return data, flags end