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 enivornment
81 -- Returns the hostname
83 return io.lines("/proc/sys/kernel/hostname")()
86 -- Returns the contents of a documented referred by an URL
88 return exec("wget -qO- '"..url:gsub("'", "").."'")
91 -- Returns the FFLuci-Basedir
93 return luci.fs.dirname(require("luci.debug").__file__)
96 -- Returns the load average
98 local loadavg = io.lines("/proc/loadavg")()
99 return loadavg:match("^(.-) (.-) (.-) (.-) (.-)$")
102 -- Reboots the system
104 return os.execute("reboot >/dev/null 2>&1")
107 -- Returns the system type, cpu name, and installed physical memory
109 local c1 = "cat /proc/cpuinfo|grep system\\ typ|cut -d: -f2 2>/dev/null"
110 local c2 = "uname -m 2>/dev/null"
111 local c3 = "cat /proc/cpuinfo|grep model\\ name|cut -d: -f2 2>/dev/null"
112 local c4 = "cat /proc/cpuinfo|grep cpu\\ model|cut -d: -f2 2>/dev/null"
113 local c5 = "cat /proc/meminfo|grep MemTotal|cut -d: -f2 2>/dev/null"
115 local s = luci.util.trim(exec(c1))
120 s = luci.util.trim(exec(c2))
121 m = luci.util.trim(exec(c3))
123 m = luci.util.trim(exec(c4))
126 r = luci.util.trim(exec(c5))
133 return exec("logread")
138 group.getgroup = posix.getgroup
141 -- Returns the ARP-Table
142 function net.arptable()
143 return _parse_delimited_table(io.lines("/proc/net/arp"), "%s%s+")
146 -- Returns whether an IP-Adress belongs to a certain net
147 function net.belongs(ip, ipnet, prefix)
148 return (net.ip4bin(ip):sub(1, prefix) == net.ip4bin(ipnet):sub(1, prefix))
151 -- Detect the default route
152 function net.defaultroute()
153 local routes = net.routes()
156 for i, r in pairs(luci.sys.net.routes()) do
157 if r.Destination == "00000000" and (not route or route.Metric > r.Metric) then
165 -- Returns all available network interfaces
166 function net.devices()
168 for line in io.lines("/proc/net/dev") do
169 table.insert(devices, line:match(" *(.-):"))
174 -- Returns the MAC-Address belonging to the given IP-Address
175 function net.ip4mac(ip)
178 for i, l in ipairs(net.arptable()) do
179 if l["IP address"] == ip then
180 mac = l["HW address"]
187 -- Returns the prefix to a given netmask
188 function net.mask4prefix(mask)
189 local bin = net.ip4bin(mask)
195 return #luci.util.split(bin, "1")-1
198 -- Returns the kernel routing table
199 function net.routes()
200 return _parse_delimited_table(io.lines("/proc/net/route"))
203 -- Returns the numeric IP to a given hexstring
204 function net.hexip4(hex, be)
209 be = be or bigendian()
211 local hexdec = luci.bits.Hex2Dec
215 ip = ip .. tostring(hexdec(hex:sub(1,2))) .. "."
216 ip = ip .. tostring(hexdec(hex:sub(3,4))) .. "."
217 ip = ip .. tostring(hexdec(hex:sub(5,6))) .. "."
218 ip = ip .. tostring(hexdec(hex:sub(7,8)))
220 ip = ip .. tostring(hexdec(hex:sub(7,8))) .. "."
221 ip = ip .. tostring(hexdec(hex:sub(5,6))) .. "."
222 ip = ip .. tostring(hexdec(hex:sub(3,4))) .. "."
223 ip = ip .. tostring(hexdec(hex:sub(1,2)))
229 -- Returns the binary IP to a given IP
230 function net.ip4bin(ip)
231 local parts = luci.util.split(ip, '.')
236 local decbin = luci.bits.Dec2Bin
239 bin = bin .. decbin(parts[1], 8)
240 bin = bin .. decbin(parts[2], 8)
241 bin = bin .. decbin(parts[3], 8)
242 bin = bin .. decbin(parts[4], 8)
247 -- Tests whether a host is pingable
248 function net.pingtest(host)
249 return os.execute("ping -c1 '"..host:gsub("'", '').."' >/dev/null 2>&1")
254 process.info = posix.getpid
256 -- Sets the gid of a process
257 function process.setgroup(pid, gid)
258 return posix.setpid("g", pid, gid)
261 -- Sets the uid of a process
262 function process.setuser(pid, uid)
263 return posix.setpid("u", pid, uid)
267 -- returns user information to a given uid
268 user.getuser = posix.getpasswd
270 -- checks whether a string matches the password of a certain system user
271 function user.checkpasswd(user, password)
272 local account = user.getuser(user)
273 if posix.crypt and account then
274 return (account.passwd == posix.crypt(account.passwd, password))
278 -- Changes the user password of given user
279 function user.setpasswd(user, pwd)
281 pwd = pwd:gsub("'", "")
285 user = user:gsub("'", "")
288 local cmd = "(echo '"..pwd.."';sleep 1;echo '"..pwd.."')|"
289 cmd = cmd .. "passwd '"..user.."' >/dev/null 2>&1"
290 return os.execute(cmd)
296 function wifi.getiwconfig()
297 local cnt = exec("/usr/sbin/iwconfig 2>/dev/null")
300 for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n\n")) do
301 local k = l:match("^(.-) ")
302 l = l:gsub("^(.-) +", "", 1)
304 iwc[k] = _parse_mixed_record(l)
311 function wifi.iwscan()
312 local cnt = exec("iwlist scan 2>/dev/null")
315 for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n\n")) do
316 local k = l:match("^(.-) ")
317 l = l:gsub("^[^\n]+", "", 1)
318 l = luci.util.trim(l)
321 for j, c in pairs(luci.util.split(l, "\n Cell")) do
322 c = c:gsub("^(.-)- ", "", 1)
323 c = luci.util.split(c, "\n", 7)
324 c = table.concat(c, "\n", 1)
325 table.insert(iws[k], _parse_mixed_record(c))
334 -- Internal functions
336 function _parse_delimited_table(iter, delimiter)
337 delimiter = delimiter or "%s+"
340 local trim = luci.util.trim
341 local split = luci.util.split
343 local keys = split(trim(iter()), delimiter, nil, true)
344 for i, j in pairs(keys) do
345 keys[i] = trim(keys[i])
352 for i, j in pairs(split(line, delimiter, nil, true)) do
358 table.insert(data, row)
364 function _parse_mixed_record(cnt)
367 for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n")) do
368 for j, f in pairs(luci.util.split(luci.util.trim(l), " ")) do
369 local k, x, v = f:match('([^%s][^:=]+) *([:=]*) *"*([^\n"]*)"*')
373 table.insert(data, k)