libs/sys: remove luci.sys.flash()
[project/luci.git] / libs / sys / luasrc / sys.lua
index 68ddd8a..c0ee4a1 100644 (file)
@@ -25,18 +25,20 @@ limitations under the License.
 ]]--
 
 
-local io    = require "io"
-local os    = require "os"
-local nixio = require "nixio"
-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 uci    = require "luci.model.uci"
 
 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.
@@ -58,20 +60,6 @@ end
 -- @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()
-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"
-
-       return os.execute(cmd)
-end
-
 --- Retrieve information about currently mounted file systems.
 -- @return     Table containing mount information
 function mounts()
@@ -135,7 +123,7 @@ getenv = nixio.getenv
 -- @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 nixio.uname().nodename
@@ -180,8 +168,8 @@ end
 -- @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 = ""
@@ -219,7 +207,7 @@ end
 -- @param bytes        Number of bytes for the unique id
 -- @return             String containing hex encoded id
 function uniqueid(bytes)
-       local rand = luci.fs.readfile("/dev/urandom", bytes)
+       local rand = fs.readfile("/dev/urandom", bytes)
        return rand and nixio.bin.hexlify(rand)
 end
 
@@ -239,15 +227,15 @@ net = {}
 -- @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, " +")
@@ -257,9 +245,13 @@ function net.conntrack()
                                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, " +")
@@ -269,7 +261,11 @@ function net.conntrack()
                                entry[i] = nil
                        end
 
-                       connt[#connt+1] = entry
+                       if callback then
+                               callback(entry)
+                       else
+                               connt[#connt+1] = entry
+                       end
                end
        else
                return nil
@@ -361,13 +357,11 @@ 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
 
@@ -424,7 +418,7 @@ end
 --                     { "source", "dest", "nexthop", "metric", "refcount", "usecount",
 --                       "flags", "device" }
 function net.routes6(callback)
-       if luci.fs.access("/proc/net/ipv6_route", "r") then
+       if fs.access("/proc/net/ipv6_route", "r") then
                local routes = { }
 
                for line in io.lines("/proc/net/ipv6_route") do
@@ -456,7 +450,11 @@ function net.routes6(callback)
                                refcount = tonumber(refcnt, 16),
                                usecount = tonumber(usecnt, 16),
                                flags    = tonumber(flags, 16),
-                               device   = dev
+                               device   = dev,
+
+                               -- lua number is too small for storing the metric
+                               -- add a metric_raw field with the original content
+                               metric_raw = metric
                        }
 
                        if callback then
@@ -573,14 +571,26 @@ user = {}
 --                             { "uid", "gid", "name", "passwd", "dir", "shell", "gecos" }
 user.getuser = nixio.getpw
 
+--- Retrieve the current user password hash.
+-- @param username     String containing the username to retrieve the password for
+-- @return                     String containing the hash or nil if no password is set.
+function user.getpasswd(username)
+       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 == "!" or pwh == "x" then
+               return nil
+       else
+               return pwh
+       end
+end
+
 --- Test whether given string matches the password of a given system user.
 -- @param username     String containing the Unix user name
 -- @param pass         String containing the password to compare
 -- @return                     Boolean indicating wheather the passwords are equal
 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
+       local pwh = user.getpasswd(username)
+       if pwh and nixio.crypt(pass, pwh) ~= pwh then
                return false
        else
                return true
@@ -611,6 +621,52 @@ end
 -- @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)
+       if ifname then
+               local c = 0
+               local u = uci.cursor_state()
+               local d, n = ifname:match("^(%w+)%.network(%d+)")
+               if d and n then
+                       n = tonumber(n)
+                       u:foreach("wireless", "wifi-iface",
+                               function(s)
+                                       if s.device == d then
+                                               c = c + 1
+                                               if c == n then
+                                                       ifname = s.ifname or s.device
+                                                       return false
+                                               end
+                                       end
+                               end)
+               elseif u:get("wireless", ifname) == "wifi-device" then
+                       u:foreach("wireless", "wifi-iface",
+                               function(s)
+                                       if s.device == ifname and s.ifname then
+                                               ifname = s.ifname
+                                               return false
+                                       end
+                               end)
+               end
+
+               local t = iwinfo.type(ifname)
+               if t then
+                       local x = iwinfo[t]
+                       return setmetatable({}, {
+                               __index = function(t, k)
+                                       if k == "ifname" then
+                                               return ifname
+                                       elseif x[k] then
+                                               return x[k](ifname)
+                                       end
+                               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()
@@ -665,27 +721,25 @@ end
 -- @param iface        Wireless interface (optional)
 -- @return             Table of available channels
 function wifi.channels(iface)
-       local cmd = "iwlist " .. ( iface or "" ) .. " freq 2>/dev/null"
-       local cns = { }
-
-       local fd = io.popen(cmd)
-       if fd then
-               local ln, c, f
-               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
-               end
-               fd:close()
+       local t = iwinfo.type(iface or "")
+       local cns
+       if iface and t and iwinfo[t] then
+               cns = iwinfo[t].freqlist(iface)
        end
 
-       if not ((pairs(cns))(cns)) then
+       if not cns or #cns == 0 then
                cns = {
-                       2.412, 2.417, 2.422, 2.427, 2.432, 2.437,
-                       2.442, 2.447, 2.452, 2.457, 2.462
+                       {channel =  1, mhz = 2412},
+                       {channel =  2, mhz = 2417},
+                       {channel =  3, mhz = 2422},
+                       {channel =  4, mhz = 2427},
+                       {channel =  5, mhz = 2432},
+                       {channel =  6, mhz = 2437},
+                       {channel =  7, mhz = 2442},
+                       {channel =  8, mhz = 2447},
+                       {channel =  9, mhz = 2452},
+                       {channel = 10, mhz = 2457},
+                       {channel = 11, mhz = 2462}
                }
        end
 
@@ -703,8 +757,8 @@ init.dir = "/etc/init.d/"
 -- @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
@@ -713,7 +767,7 @@ 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
@@ -723,8 +777,8 @@ end
 -- @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")
+       if fs.access(init.dir..name) then
+               return call("source "..init.dir..name.." enabled; exit $START")
        end
 end
 
@@ -732,7 +786,7 @@ 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
@@ -741,7 +795,7 @@ 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
@@ -749,7 +803,7 @@ end
 
 -- Internal functions
 
-function _parse_delimited_table(iter, delimiter)
+function _parse_delimited_table(iter, delimiter, callback)
        delimiter = delimiter or "%s+"
 
        local data  = {}
@@ -771,7 +825,12 @@ function _parse_delimited_table(iter, delimiter)
                                end
                        end
                end
-               table.insert(data, row)
+
+               if callback then
+                       callback(row)
+               else
+                       data[#data+1] = row
+               end
        end
 
        return data