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)
33 -- Returns whether a system is bigendian
35 local fp = io.open("/bin/sh")
37 local be = (fp:read(1):byte() ~= 1)
42 -- Runs "command" and returns its output
43 function exec(command)
44 local pp = io.popen(command)
45 local data = pp:read("*a")
51 -- Runs "command" and returns its output as a array of lines
52 function execl(command)
53 local pp = io.popen(command)
59 if (line == nil) then break end
60 table.insert(data, line)
67 -- Uses "luci-flash" to flash a new image file to the system
68 function flash(image, kpattern)
69 local cmd = "luci-flash "
71 cmd = cmd .. "-k '" .. kpattern:gsub("'", "") .. "' "
73 cmd = cmd .. "'" .. image:gsub("'", "") .. "' >/dev/null 2>&1"
75 return os.execute(cmd)
78 -- Returns the hostname
80 return io.lines("/proc/sys/kernel/hostname")()
83 -- Returns the contents of a documented referred by an URL
85 return exec("wget -qO- '"..url:gsub("'", "").."'")
88 -- Returns the FFLuci-Basedir
90 return luci.fs.dirname(require("luci.debug").__file__)
93 -- Returns the load average
95 local loadavg = io.lines("/proc/loadavg")()
96 return loadavg:match("^(.-) (.-) (.-) (.-) (.-)$")
101 return os.execute("reboot >/dev/null 2>&1")
104 -- Returns the system type, cpu name, and installed physical memory
106 local c1 = "cat /proc/cpuinfo|grep system\\ typ|cut -d: -f2 2>/dev/null"
107 local c2 = "uname -m 2>/dev/null"
108 local c3 = "cat /proc/cpuinfo|grep model\\ name|cut -d: -f2 2>/dev/null"
109 local c4 = "cat /proc/cpuinfo|grep cpu\\ model|cut -d: -f2 2>/dev/null"
110 local c5 = "cat /proc/meminfo|grep MemTotal|cut -d: -f2 2>/dev/null"
112 local s = luci.util.trim(exec(c1))
117 s = luci.util.trim(exec(c2))
118 m = luci.util.trim(exec(c3))
120 m = luci.util.trim(exec(c4))
123 r = luci.util.trim(exec(c5))
130 return exec("logread")
135 group.getgroup = posix.getgroup
138 -- Returns the ARP-Table
139 function net.arptable()
140 return _parse_delimited_table(io.lines("/proc/net/arp"), "%s%s+")
143 -- Returns whether an IP-Adress belongs to a certain net
144 function net.belongs(ip, ipnet, prefix)
145 return (net.ip4bin(ip):sub(1, prefix) == net.ip4bin(ipnet):sub(1, prefix))
148 -- Detect the default route
149 function net.defaultroute()
150 local routes = net.routes()
153 for i, r in pairs(luci.sys.net.routes()) do
154 if r.Destination == "00000000" and (not route or route.Metric > r.Metric) then
162 -- Returns all available network interfaces
163 function net.devices()
165 for line in io.lines("/proc/net/dev") do
166 table.insert(devices, line:match(" *(.-):"))
171 -- Returns the MAC-Address belonging to the given IP-Address
172 function net.ip4mac(ip)
175 for i, l in ipairs(net.arptable()) do
176 if l["IP address"] == ip then
177 mac = l["HW address"]
184 -- Returns the prefix to a given netmask
185 function net.mask4prefix(mask)
186 local bin = net.ip4bin(mask)
192 return #luci.util.split(bin, "1")-1
195 -- Returns the kernel routing table
196 function net.routes()
197 return _parse_delimited_table(io.lines("/proc/net/route"))
200 -- Returns the numeric IP to a given hexstring
201 function net.hexip4(hex, be)
206 be = be or bigendian()
208 local hexdec = luci.bits.Hex2Dec
212 ip = ip .. tostring(hexdec(hex:sub(1,2))) .. "."
213 ip = ip .. tostring(hexdec(hex:sub(3,4))) .. "."
214 ip = ip .. tostring(hexdec(hex:sub(5,6))) .. "."
215 ip = ip .. tostring(hexdec(hex:sub(7,8)))
217 ip = ip .. tostring(hexdec(hex:sub(7,8))) .. "."
218 ip = ip .. tostring(hexdec(hex:sub(5,6))) .. "."
219 ip = ip .. tostring(hexdec(hex:sub(3,4))) .. "."
220 ip = ip .. tostring(hexdec(hex:sub(1,2)))
226 -- Returns the binary IP to a given IP
227 function net.ip4bin(ip)
228 local parts = luci.util.split(ip, '.')
233 local decbin = luci.bits.Dec2Bin
236 bin = bin .. decbin(parts[1], 8)
237 bin = bin .. decbin(parts[2], 8)
238 bin = bin .. decbin(parts[3], 8)
239 bin = bin .. decbin(parts[4], 8)
244 -- Tests whether a host is pingable
245 function net.pingtest(host)
246 return os.execute("ping -c1 '"..host:gsub("'", '').."' >/dev/null 2>&1")
251 process.info = posix.getpid
253 -- Sets the gid of a process
254 function process.setgroup(pid, gid)
255 return posix.setpid("g", pid, gid)
258 -- Sets the uid of a process
259 function process.setuser(pid, uid)
260 return posix.setpid("u", pid, uid)
264 -- returns user information to a given uid
265 user.getuser = posix.getpasswd
267 -- Changes the user password of given user
268 function user.setpasswd(user, pwd)
270 pwd = pwd:gsub("'", "")
274 user = user:gsub("'", "")
277 local cmd = "(echo '"..pwd.."';sleep 1;echo '"..pwd.."')|"
278 cmd = cmd .. "passwd '"..user.."' >/dev/null 2>&1"
279 return os.execute(cmd)
285 function wifi.getiwconfig()
286 local cnt = exec("/usr/sbin/iwconfig 2>/dev/null")
289 for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n\n")) do
290 local k = l:match("^(.-) ")
291 l = l:gsub("^(.-) +", "", 1)
293 iwc[k] = _parse_mixed_record(l)
300 function wifi.iwscan()
301 local cnt = exec("iwlist scan 2>/dev/null")
304 for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n\n")) do
305 local k = l:match("^(.-) ")
306 l = l:gsub("^[^\n]+", "", 1)
307 l = luci.util.trim(l)
310 for j, c in pairs(luci.util.split(l, "\n Cell")) do
311 c = c:gsub("^(.-)- ", "", 1)
312 c = luci.util.split(c, "\n", 7)
313 c = table.concat(c, "\n", 1)
314 table.insert(iws[k], _parse_mixed_record(c))
323 -- Internal functions
325 function _parse_delimited_table(iter, delimiter)
326 delimiter = delimiter or "%s+"
329 local trim = luci.util.trim
330 local split = luci.util.split
332 local keys = split(trim(iter()), delimiter, nil, true)
333 for i, j in pairs(keys) do
334 keys[i] = trim(keys[i])
341 for i, j in pairs(split(line, delimiter, nil, true)) do
347 table.insert(data, row)
353 function _parse_mixed_record(cnt)
356 for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n")) do
357 for j, f in pairs(luci.util.split(luci.util.trim(l), " ")) do
358 local k, x, v = f:match('([^%s][^:=]+) *([:=]*) *"*([^\n"]*)"*')
362 table.insert(data, k)