2 FFLuCI - System library
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("ffluci.sys", package.seeall)
29 require("ffluci.bits")
30 require("ffluci.util")
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 "ffluci-flash" to flash a new image file to the system
65 function flash(image, kpattern)
66 local cmd = "ffluci-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 ffluci.fs.dirname(require("ffluci.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 = ffluci.util.trim(exec(c1))
114 s = ffluci.util.trim(exec(c2))
115 m = ffluci.util.trim(exec(c3))
117 m = ffluci.util.trim(exec(c4))
120 r = ffluci.util.trim(exec(c5))
127 group.getgroup = posix.getgroup
130 -- Returns the ARP-Table
131 function net.arptable()
132 return _parse_delimited_table(io.lines("/proc/net/arp"), "%s%s+")
135 -- Returns whether an IP-Adress belongs to a certain net
136 function net.belongs(ip, ipnet, prefix)
137 return (net.ip4bin(ip):sub(1, prefix) == net.ip4bin(ipnet):sub(1, prefix))
140 -- Detect the default route
141 function net.defaultroute()
142 local routes = net.routes()
145 for i, r in pairs(ffluci.sys.net.routes()) do
146 if r.Destination == "00000000" and (not route or route.Metric > r.Metric) then
154 -- Returns all available network interfaces
155 function net.devices()
157 for line in io.lines("/proc/net/dev") do
158 table.insert(devices, line:match(" *(.-):"))
163 -- Returns the MAC-Address belonging to the given IP-Address
164 function net.ip4mac(ip)
167 for i, l in ipairs(net.arptable()) do
168 if l["IP address"] == ip then
169 mac = l["HW address"]
176 -- Returns the prefix to a given netmask
177 function net.mask4prefix(mask)
178 local bin = net.ip4bin(mask)
184 return #ffluci.util.split(bin, "1")-1
187 -- Returns the kernel routing table
188 function net.routes()
189 return _parse_delimited_table(io.lines("/proc/net/route"))
192 -- Returns the numeric IP to a given hexstring
193 function net.hexip4(hex, be)
198 be = be or bigendian()
200 local hexdec = ffluci.bits.Hex2Dec
204 ip = ip .. tostring(hexdec(hex:sub(1,2))) .. "."
205 ip = ip .. tostring(hexdec(hex:sub(3,4))) .. "."
206 ip = ip .. tostring(hexdec(hex:sub(5,6))) .. "."
207 ip = ip .. tostring(hexdec(hex:sub(7,8)))
209 ip = ip .. tostring(hexdec(hex:sub(7,8))) .. "."
210 ip = ip .. tostring(hexdec(hex:sub(5,6))) .. "."
211 ip = ip .. tostring(hexdec(hex:sub(3,4))) .. "."
212 ip = ip .. tostring(hexdec(hex:sub(1,2)))
218 -- Returns the binary IP to a given IP
219 function net.ip4bin(ip)
220 local parts = ffluci.util.split(ip, '.')
225 local decbin = ffluci.bits.Dec2Bin
228 bin = bin .. decbin(parts[1], 8)
229 bin = bin .. decbin(parts[2], 8)
230 bin = bin .. decbin(parts[3], 8)
231 bin = bin .. decbin(parts[4], 8)
236 -- Tests whether a host is pingable
237 function net.pingtest(host)
238 return os.execute("ping -c1 '"..host:gsub("'", '').."' >/dev/null 2>&1")
243 process.info = posix.getpid
245 -- Sets the gid of a process
246 function process.setgroup(pid, gid)
247 return posix.setpid("g", pid, gid)
250 -- Sets the uid of a process
251 function process.setuser(pid, uid)
252 return posix.setpid("u", pid, uid)
256 -- returns user information to a given uid
257 user.getuser = posix.getpasswd
259 -- Changes the user password of given user
260 function user.setpasswd(user, pwd)
262 pwd = pwd:gsub("'", "")
266 user = user:gsub("'", "")
269 local cmd = "(echo '"..pwd.."';sleep 1;echo '"..pwd.."')|"
270 cmd = cmd .. "passwd '"..user.."' >/dev/null 2>&1"
271 return os.execute(cmd)
277 function wifi.getiwconfig()
278 local cnt = exec("/usr/sbin/iwconfig 2>/dev/null")
281 for i, l in pairs(ffluci.util.split(ffluci.util.trim(cnt), "\n\n")) do
282 local k = l:match("^(.-) ")
283 l = l:gsub("^(.-) +", "", 1)
285 iwc[k] = _parse_mixed_record(l)
292 function wifi.iwscan()
293 local cnt = exec("iwlist scan 2>/dev/null")
296 for i, l in pairs(ffluci.util.split(ffluci.util.trim(cnt), "\n\n")) do
297 local k = l:match("^(.-) ")
298 l = l:gsub("^[^\n]+", "", 1)
299 l = ffluci.util.trim(l)
302 for j, c in pairs(ffluci.util.split(l, "\n Cell")) do
303 c = c:gsub("^(.-)- ", "", 1)
304 c = ffluci.util.split(c, "\n", 7)
305 c = table.concat(c, "\n", 1)
306 table.insert(iws[k], _parse_mixed_record(c))
315 -- Internal functions
317 function _parse_delimited_table(iter, delimiter)
318 delimiter = delimiter or "%s+"
321 local trim = ffluci.util.trim
322 local split = ffluci.util.split
324 local keys = split(trim(iter()), delimiter, nil, true)
325 for i, j in pairs(keys) do
326 keys[i] = trim(keys[i])
333 for i, j in pairs(split(line, delimiter, nil, true)) do
339 table.insert(data, row)
345 function _parse_mixed_record(cnt)
348 for i, l in pairs(ffluci.util.split(ffluci.util.trim(cnt), "\n")) do
349 for j, f in pairs(ffluci.util.split(ffluci.util.trim(l), " ")) do
350 local k, x, v = f:match('([^%s][^:=]+) *([:=]*) *"*([^\n"]*)"*')
354 table.insert(data, k)