5 Utilities for interaction with the Linux system
11 Copyright 2008 Steven Barth <steven@midlink.org>
13 Licensed under the Apache License, Version 2.0 (the "License");
14 you may not use this file except in compliance with the License.
15 You may obtain a copy of the License at
17 http://www.apache.org/licenses/LICENSE-2.0
19 Unless required by applicable law or agreed to in writing, software
20 distributed under the License is distributed on an "AS IS" BASIS,
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 See the License for the specific language governing permissions and
23 limitations under the License.
27 module("luci.sys", package.seeall)
32 -- Returns whether a system is bigendian
34 local fp = io.open("/bin/sh")
36 return (fp:read(1):byte() ~= 1)
39 -- Runs "command" and returns its output
40 function exec(command)
41 local pp = io.popen(command)
42 local data = pp:read("*a")
48 -- Runs "command" and returns its output as a array of lines
49 function execl(command)
50 local pp = io.popen(command)
56 if (line == nil) then break end
57 table.insert(data, line)
64 -- Uses "luci-flash" to flash a new image file to the system
65 function flash(image, kpattern)
66 local cmd = "luci-flash "
68 cmd = cmd .. "-k '" .. kpattern:gsub("'", "") .. "' "
70 cmd = cmd .. "'" .. image:gsub("'", "") .. "' >/dev/null 2>&1"
72 return os.execute(cmd)
75 -- Returns the hostname
77 return io.lines("/proc/sys/kernel/hostname")()
80 -- Returns the contents of a documented referred by an URL
82 return exec("wget -qO- '"..url:gsub("'", "").."'")
85 -- Returns the FFLuci-Basedir
87 return luci.fs.dirname(require("luci.debug").__file__)
90 -- Returns the load average
92 local loadavg = io.lines("/proc/loadavg")()
93 return loadavg:match("^(.-) (.-) (.-) (.-) (.-)$")
98 return os.execute("reboot >/dev/null 2>&1")
101 -- Returns the system type, cpu name, and installed physical memory
103 local c1 = "cat /proc/cpuinfo|grep system\\ typ|cut -d: -f2 2>/dev/null"
104 local c2 = "uname -m 2>/dev/null"
105 local c3 = "cat /proc/cpuinfo|grep model\\ name|cut -d: -f2 2>/dev/null"
106 local c4 = "cat /proc/cpuinfo|grep cpu\\ model|cut -d: -f2 2>/dev/null"
107 local c5 = "cat /proc/meminfo|grep MemTotal|cut -d: -f2 2>/dev/null"
109 local s = luci.util.trim(exec(c1))
114 s = luci.util.trim(exec(c2))
115 m = luci.util.trim(exec(c3))
117 m = luci.util.trim(exec(c4))
120 r = luci.util.trim(exec(c5))
127 return exec("logread")
132 group.getgroup = posix.getgroup
135 -- Returns the ARP-Table
136 function net.arptable()
137 return _parse_delimited_table(io.lines("/proc/net/arp"), "%s%s+")
140 -- Returns whether an IP-Adress belongs to a certain net
141 function net.belongs(ip, ipnet, prefix)
142 return (net.ip4bin(ip):sub(1, prefix) == net.ip4bin(ipnet):sub(1, prefix))
145 -- Detect the default route
146 function net.defaultroute()
147 local routes = net.routes()
150 for i, r in pairs(luci.sys.net.routes()) do
151 if r.Destination == "00000000" and (not route or route.Metric > r.Metric) then
159 -- Returns all available network interfaces
160 function net.devices()
162 for line in io.lines("/proc/net/dev") do
163 table.insert(devices, line:match(" *(.-):"))
168 -- Returns the MAC-Address belonging to the given IP-Address
169 function net.ip4mac(ip)
172 for i, l in ipairs(net.arptable()) do
173 if l["IP address"] == ip then
174 mac = l["HW address"]
181 -- Returns the prefix to a given netmask
182 function net.mask4prefix(mask)
183 local bin = net.ip4bin(mask)
189 return #luci.util.split(bin, "1")-1
192 -- Returns the kernel routing table
193 function net.routes()
194 return _parse_delimited_table(io.lines("/proc/net/route"))
197 -- Returns the numeric IP to a given hexstring
198 function net.hexip4(hex, be)
203 be = be or bigendian()
205 local hexdec = luci.bits.Hex2Dec
209 ip = ip .. tostring(hexdec(hex:sub(1,2))) .. "."
210 ip = ip .. tostring(hexdec(hex:sub(3,4))) .. "."
211 ip = ip .. tostring(hexdec(hex:sub(5,6))) .. "."
212 ip = ip .. tostring(hexdec(hex:sub(7,8)))
214 ip = ip .. tostring(hexdec(hex:sub(7,8))) .. "."
215 ip = ip .. tostring(hexdec(hex:sub(5,6))) .. "."
216 ip = ip .. tostring(hexdec(hex:sub(3,4))) .. "."
217 ip = ip .. tostring(hexdec(hex:sub(1,2)))
223 -- Returns the binary IP to a given IP
224 function net.ip4bin(ip)
225 local parts = luci.util.split(ip, '.')
230 local decbin = luci.bits.Dec2Bin
233 bin = bin .. decbin(parts[1], 8)
234 bin = bin .. decbin(parts[2], 8)
235 bin = bin .. decbin(parts[3], 8)
236 bin = bin .. decbin(parts[4], 8)
241 -- Tests whether a host is pingable
242 function net.pingtest(host)
243 return os.execute("ping -c1 '"..host:gsub("'", '').."' >/dev/null 2>&1")
248 process.info = posix.getpid
250 -- Sets the gid of a process
251 function process.setgroup(pid, gid)
252 return posix.setpid("g", pid, gid)
255 -- Sets the uid of a process
256 function process.setuser(pid, uid)
257 return posix.setpid("u", pid, uid)
261 -- returns user information to a given uid
262 user.getuser = posix.getpasswd
264 -- Changes the user password of given user
265 function user.setpasswd(user, pwd)
267 pwd = pwd:gsub("'", "")
271 user = user:gsub("'", "")
274 local cmd = "(echo '"..pwd.."';sleep 1;echo '"..pwd.."')|"
275 cmd = cmd .. "passwd '"..user.."' >/dev/null 2>&1"
276 return os.execute(cmd)
282 function wifi.getiwconfig()
283 local cnt = exec("/usr/sbin/iwconfig 2>/dev/null")
286 for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n\n")) do
287 local k = l:match("^(.-) ")
288 l = l:gsub("^(.-) +", "", 1)
290 iwc[k] = _parse_mixed_record(l)
297 function wifi.iwscan()
298 local cnt = exec("iwlist scan 2>/dev/null")
301 for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n\n")) do
302 local k = l:match("^(.-) ")
303 l = l:gsub("^[^\n]+", "", 1)
304 l = luci.util.trim(l)
307 for j, c in pairs(luci.util.split(l, "\n Cell")) do
308 c = c:gsub("^(.-)- ", "", 1)
309 c = luci.util.split(c, "\n", 7)
310 c = table.concat(c, "\n", 1)
311 table.insert(iws[k], _parse_mixed_record(c))
320 -- Internal functions
322 function _parse_delimited_table(iter, delimiter)
323 delimiter = delimiter or "%s+"
326 local trim = luci.util.trim
327 local split = luci.util.split
329 local keys = split(trim(iter()), delimiter, nil, true)
330 for i, j in pairs(keys) do
331 keys[i] = trim(keys[i])
338 for i, j in pairs(split(line, delimiter, nil, true)) do
344 table.insert(data, row)
350 function _parse_mixed_record(cnt)
353 for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n")) do
354 for j, f in pairs(luci.util.split(luci.util.trim(l), " ")) do
355 local k, x, v = f:match('([^%s][^:=]+) *([:=]*) *"*([^\n"]*)"*')
359 table.insert(data, k)