libs/sys: extend luci.sys.hostname() to allow setting a new name
[project/luci.git] / libs / sys / luasrc / sys.lua
index bc872c9..3e2ce7f 100644 (file)
@@ -129,10 +129,16 @@ end
 -- @return             Table containing all variables if no variable name is given
 getenv = posix.getenv
 
---- Determine the current hostname.
+--- Get or set the current hostname.
+-- @param              String containing a new hostname to set (optional)
 -- @return             String containing the system hostname
-function hostname()
-       return posix.uname("%n")
+function hostname(newname)
+       if type(newname) == "string" and #newname > 0 then
+               luci.fs.writefile( "/proc/sys/kernel/hostname", newname .. "\n" )
+               return newname
+       else
+               return posix.uname("%n")
+       end
 end
 
 --- Returns the contents of a documented referred by an URL.
@@ -266,19 +272,21 @@ end
 -- @return     Table with the currently tracked IP connections
 function net.conntrack()
        local connt = {}
-       if luci.fs.access("/proc/net/nf_conntrack") then
+       if luci.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.layer3 = flags[1]
-                       entry.layer4 = flags[2]
+                       entry.layer4 = flags[3]
                        for i=1, #entry do
                                entry[i] = nil
                        end
 
                        connt[#connt+1] = entry
                end
-       elseif luci.fs.access("/proc/net/ip_conntrack") then
+       elseif luci.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.layer3 = "ipv4"
                        entry.layer4 = flags[1]
@@ -294,21 +302,40 @@ function net.conntrack()
        return connt
 end
 
---- Determine the current default route.
+--- Determine the current IPv4 default route. If multiple default routes exist,
+-- return the one with the lowest metric.
 -- @return     Table with the properties of the current default route.
 --                     The following fields are defined:
---                     { "Mask", "RefCnt", "Iface", "Flags", "Window", "IRTT",
---                       "MTU", "Gateway", "Destination", "Metric", "Use" }
+--                     { "dest", "gateway", "metric", "refcount", "usecount", "irtt",
+--                       "flags", "device" }
 function net.defaultroute()
-       local routes = net.routes()
        local route = nil
-
-       for i, r in pairs(luci.sys.net.routes()) do
-               if r.Destination == "00000000" and (not route or route.Metric > r.Metric) then
+       for _, r in pairs(net.routes()) do
+               if r.dest:prefix() == 0 and (not route or route.metric > r.metric) then
                        route = r
                end
        end
+       return route
+end
 
+--- Determine the current IPv6 default route. If multiple default routes exist,
+-- return the one with the lowest metric.
+-- @return     Table with the properties of the current default route.
+--                     The following fields are defined:
+--                     { "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
+               end
+       end
        return route
 end
 
@@ -355,60 +382,90 @@ end
 --- Returns the current kernel routing table entries.
 -- @return     Table of tables with properties of the corresponding routes.
 --                     The following fields are defined for route entry tables:
---                     { "Mask", "RefCnt", "Iface", "Flags", "Window", "IRTT",
---                       "MTU", "Gateway", "Destination", "Metric", "Use" }
+--                     { "dest", "gateway", "metric", "refcount", "usecount", "irtt",
+--                       "flags", "device" }
 function net.routes()
-       return _parse_delimited_table(io.lines("/proc/net/route"))
-end
-
---- Returns the current ipv6 kernel routing table entries.
--- @return     Table of tables with properties of the corresponding routes.
---                     The following fields are defined for route entry tables:
---                     { "src_ip", "src_prefix", "dst_ip", "dst_prefix", "nexthop_ip",
---            "metric", "refcount", "usecount", "flags", "device" }
-function net.routes6()
        local routes = { }
 
-       for line in io.lines("/proc/net/ipv6_route") do
+       for line in io.lines("/proc/net/route") do
 
-               local dst_ip, dst_prefix, src_ip, src_prefix, nexthop,
-                         metric, refcnt, usecnt, flags, dev = line:match(
-                       "([a-f0-9]+) ([a-f0-9]+) " ..
-                       "([a-f0-9]+) ([a-f0-9]+) " ..
-                       "([a-f0-9]+) ([a-f0-9]+) " ..
-                       "([a-f0-9]+) ([a-f0-9]+) " ..
-            "([^%s]+) +([^%s]+)"
+               local dev, dst_ip, gateway, flags, refcnt, usecnt, metric,
+                         dst_mask, mtu, win, irtt = line:match(
+                       "([^%s]+)\t([A-F0-9]+)\t([A-F0-9]+)\t([A-F0-9]+)\t" ..
+                       "(%d+)\t(%d+)\t(%d+)\t([A-F0-9]+)\t(%d+)\t(%d+)\t(%d+)"
                )
 
-               src_ip = luci.ip.Hex(
-                       src_ip, tonumber(src_prefix, 16),
-                       luci.ip.FAMILY_INET6, false
-               )
-
-               dst_ip = luci.ip.Hex(
-                       dst_ip, tonumber(dst_prefix, 16),
-                       luci.ip.FAMILY_INET6, false
-               )
-
-               nexthop = luci.ip.Hex( nexthop, 128, luci.ip.FAMILY_INET6, false )
-
-               routes[#routes+1] = {
-                       src_ip     = src_ip:host():string(),
-                       src_prefix = src_ip:prefix(),
-                       dst_ip     = dst_ip:host():string(),
-                       dst_prefix = dst_ip:prefix(),
-                       nexthop_ip = nexthop:string(),
-                       metric     = tonumber(metric, 16),
-                       refcount   = tonumber(refcnt, 16),
-                       usecount   = tonumber(usecnt, 16),
-                       flags      = tonumber(flags), -- hex?
-                       device     = dev
-               }
+               if dev then
+                       gateway  = luci.ip.Hex( gateway,  32, luci.ip.FAMILY_INET4 )
+                       dst_mask = luci.ip.Hex( dst_mask, 32, luci.ip.FAMILY_INET4 )
+                       dst_ip   = luci.ip.Hex(
+                               dst_ip, dst_mask:prefix(dst_mask), luci.ip.FAMILY_INET4
+                       )
+
+                       routes[#routes+1] = {
+                               dest     = dst_ip,
+                               gateway  = gateway,
+                               metric   = tonumber(metric),
+                               refcount = tonumber(refcnt),
+                               usecount = tonumber(usecnt),
+                               mtu      = tonumber(mtu),
+                               window   = tonumber(window),
+                               irtt     = tonumber(irtt),
+                               flags    = tonumber(flags, 16),
+                               device   = dev
+                       }
+               end
        end
 
        return routes
 end
 
+--- Returns the current ipv6 kernel routing table entries.
+-- @return     Table of tables with properties of the corresponding routes.
+--                     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
+               local routes = { }
+
+               for line in io.lines("/proc/net/ipv6_route") do
+
+                       local dst_ip, dst_prefix, src_ip, src_prefix, nexthop,
+                                 metric, refcnt, usecnt, flags, dev = line:match(
+                               "([a-f0-9]+) ([a-f0-9]+) " ..
+                               "([a-f0-9]+) ([a-f0-9]+) " ..
+                               "([a-f0-9]+) ([a-f0-9]+) " ..
+                               "([a-f0-9]+) ([a-f0-9]+) " ..
+                               "([a-f0-9]+) +([^%s]+)"
+                       )
+
+                       src_ip = luci.ip.Hex(
+                               src_ip, tonumber(src_prefix, 16), luci.ip.FAMILY_INET6, false
+                       )
+
+                       dst_ip = luci.ip.Hex(
+                               dst_ip, tonumber(dst_prefix, 16), luci.ip.FAMILY_INET6, false
+                       )
+
+                       nexthop = luci.ip.Hex( nexthop, 128, luci.ip.FAMILY_INET6, false )
+
+                       routes[#routes+1] = {
+                               source   = src_ip,
+                               dest     = dst_ip,
+                               nexthop  = nexthop,
+                               metric   = tonumber(metric, 16),
+                               refcount = tonumber(refcnt, 16),
+                               usecount = tonumber(usecnt, 16),
+                               flags    = tonumber(flags, 16),
+                               device   = dev
+                       }
+               end
+
+               return routes
+       end
+end
+
 --- Tests whether the given host responds to ping probes.
 -- @param host String containing a hostname or IPv4 address
 -- @return             Number containing 0 on success and >= 1 on error
@@ -576,7 +633,7 @@ wifi = {}
 --- Get iwconfig output for all wireless devices.
 -- @return     Table of tables containing the iwconfing output for each wifi device
 function wifi.getiwconfig()
-       local cnt = luci.util.exec("/usr/sbin/iwconfig 2>/dev/null")
+       local cnt = luci.util.exec("PATH=/sbin:/usr/sbin iwconfig 2>/dev/null")
        local iwc = {}
 
        for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n\n")) do
@@ -715,17 +772,17 @@ function _parse_mixed_record(cnt, delimiter)
 
        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), delimiter, nil, true)) do
-               local k, x, v = f:match('([^%s][^:=]+) *([:=]*) *"*([^\n"]*)"*')
+                       local k, x, v = f:match('([^%s][^:=]*) *([:=]*) *"*([^\n"]*)"*')
 
-            if k then
+                       if k then
                                if x == "" then
                                        table.insert(flags, k)
                                else
-                       data[k] = v
+                                       data[k] = v
                                end
-            end
-       end
+                       end
+               end
        end
 
-    return data, flags
+       return data, flags
 end