* ffluci: fix internal property in sys/iptparser.lua
[project/luci.git] / core / src / sys.lua
1 --[[
2 FFLuCI - System library
3
4 Description:
5 Utilities for interaction with the Linux system
6
7 FileId:
8 $Id$
9
10 License:
11 Copyright 2008 Steven Barth <steven@midlink.org>
12
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
16
17 http://www.apache.org/licenses/LICENSE-2.0
18
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.
24
25 ]]--
26
27 module("ffluci.sys", package.seeall)
28 require("posix")
29 require("ffluci.bits")
30 require("ffluci.util")
31
32 -- Returns whether a system is bigendian
33 function bigendian()
34 local fp = io.open("/bin/sh")
35 fp:seek("set", 5)
36 return (fp:read(1):byte() ~= 1)
37 end
38
39 -- Runs "command" and returns its output
40 function exec(command)
41 local pp = io.popen(command)
42 local data = pp:read("*a")
43 pp:close()
44
45 return data
46 end
47
48 -- Runs "command" and returns its output as a array of lines
49 function execl(command)
50 local pp = io.popen(command)
51 local line = ""
52 local data = {}
53
54 while true do
55 line = pp:read()
56 if (line == nil) then break end
57 table.insert(data, line)
58 end
59 pp:close()
60
61 return data
62 end
63
64 -- Uses "ffluci-flash" to flash a new image file to the system
65 function flash(image, kpattern)
66 local cmd = "ffluci-flash "
67 if kpattern then
68 cmd = cmd .. "-k '" .. kpattern:gsub("'", "") .. "' "
69 end
70 cmd = cmd .. "'" .. image:gsub("'", "") .. "' >/dev/null 2>&1"
71
72 return os.execute(cmd)
73 end
74
75 -- Returns the hostname
76 function hostname()
77 return io.lines("/proc/sys/kernel/hostname")()
78 end
79
80 -- Returns the contents of a documented referred by an URL
81 function httpget(url)
82 return exec("wget -qO- '"..url:gsub("'", "").."'")
83 end
84
85 -- Returns the FFLuci-Basedir
86 function libpath()
87 return ffluci.fs.dirname(require("ffluci.debug").__file__)
88 end
89
90 -- Returns the load average
91 function loadavg()
92 local loadavg = io.lines("/proc/loadavg")()
93 return loadavg:match("^(.-) (.-) (.-) (.-) (.-)$")
94 end
95
96 -- Reboots the system
97 function reboot()
98 return os.execute("reboot >/dev/null 2>&1")
99 end
100
101 -- Returns the system type, cpu name, and installed physical memory
102 function sysinfo()
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"
108
109 local s = ffluci.util.trim(exec(c1))
110 local m = ""
111 local r = ""
112
113 if s == "" then
114 s = ffluci.util.trim(exec(c2))
115 m = ffluci.util.trim(exec(c3))
116 else
117 m = ffluci.util.trim(exec(c4))
118 end
119
120 r = ffluci.util.trim(exec(c5))
121
122 return s, m, r
123 end
124
125 -- Reads the syslog
126 function syslog()
127 return exec("logread")
128 end
129
130
131 group = {}
132 group.getgroup = posix.getgroup
133
134 net = {}
135 -- Returns the ARP-Table
136 function net.arptable()
137 return _parse_delimited_table(io.lines("/proc/net/arp"), "%s%s+")
138 end
139
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))
143 end
144
145 -- Detect the default route
146 function net.defaultroute()
147 local routes = net.routes()
148 local route = nil
149
150 for i, r in pairs(ffluci.sys.net.routes()) do
151 if r.Destination == "00000000" and (not route or route.Metric > r.Metric) then
152 route = r
153 end
154 end
155
156 return route
157 end
158
159 -- Returns all available network interfaces
160 function net.devices()
161 local devices = {}
162 for line in io.lines("/proc/net/dev") do
163 table.insert(devices, line:match(" *(.-):"))
164 end
165 return devices
166 end
167
168 -- Returns the MAC-Address belonging to the given IP-Address
169 function net.ip4mac(ip)
170 local mac = nil
171
172 for i, l in ipairs(net.arptable()) do
173 if l["IP address"] == ip then
174 mac = l["HW address"]
175 end
176 end
177
178 return mac
179 end
180
181 -- Returns the prefix to a given netmask
182 function net.mask4prefix(mask)
183 local bin = net.ip4bin(mask)
184
185 if not bin then
186 return nil
187 end
188
189 return #ffluci.util.split(bin, "1")-1
190 end
191
192 -- Returns the kernel routing table
193 function net.routes()
194 return _parse_delimited_table(io.lines("/proc/net/route"))
195 end
196
197 -- Returns the numeric IP to a given hexstring
198 function net.hexip4(hex, be)
199 if #hex ~= 8 then
200 return nil
201 end
202
203 be = be or bigendian()
204
205 local hexdec = ffluci.bits.Hex2Dec
206
207 local ip = ""
208 if be then
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)))
213 else
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)))
218 end
219
220 return ip
221 end
222
223 -- Returns the binary IP to a given IP
224 function net.ip4bin(ip)
225 local parts = ffluci.util.split(ip, '.')
226 if #parts ~= 4 then
227 return nil
228 end
229
230 local decbin = ffluci.bits.Dec2Bin
231
232 local bin = ""
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)
237
238 return bin
239 end
240
241 -- Tests whether a host is pingable
242 function net.pingtest(host)
243 return os.execute("ping -c1 '"..host:gsub("'", '').."' >/dev/null 2>&1")
244 end
245
246
247 process = {}
248 process.info = posix.getpid
249
250 -- Sets the gid of a process
251 function process.setgroup(pid, gid)
252 return posix.setpid("g", pid, gid)
253 end
254
255 -- Sets the uid of a process
256 function process.setuser(pid, uid)
257 return posix.setpid("u", pid, uid)
258 end
259
260 user = {}
261 -- returns user information to a given uid
262 user.getuser = posix.getpasswd
263
264 -- Changes the user password of given user
265 function user.setpasswd(user, pwd)
266 if pwd then
267 pwd = pwd:gsub("'", "")
268 end
269
270 if user then
271 user = user:gsub("'", "")
272 end
273
274 local cmd = "(echo '"..pwd.."';sleep 1;echo '"..pwd.."')|"
275 cmd = cmd .. "passwd '"..user.."' >/dev/null 2>&1"
276 return os.execute(cmd)
277 end
278
279
280 wifi = {}
281
282 function wifi.getiwconfig()
283 local cnt = exec("/usr/sbin/iwconfig 2>/dev/null")
284 local iwc = {}
285
286 for i, l in pairs(ffluci.util.split(ffluci.util.trim(cnt), "\n\n")) do
287 local k = l:match("^(.-) ")
288 l = l:gsub("^(.-) +", "", 1)
289 if k then
290 iwc[k] = _parse_mixed_record(l)
291 end
292 end
293
294 return iwc
295 end
296
297 function wifi.iwscan()
298 local cnt = exec("iwlist scan 2>/dev/null")
299 local iws = {}
300
301 for i, l in pairs(ffluci.util.split(ffluci.util.trim(cnt), "\n\n")) do
302 local k = l:match("^(.-) ")
303 l = l:gsub("^[^\n]+", "", 1)
304 l = ffluci.util.trim(l)
305 if k then
306 iws[k] = {}
307 for j, c in pairs(ffluci.util.split(l, "\n Cell")) do
308 c = c:gsub("^(.-)- ", "", 1)
309 c = ffluci.util.split(c, "\n", 7)
310 c = table.concat(c, "\n", 1)
311 table.insert(iws[k], _parse_mixed_record(c))
312 end
313 end
314 end
315
316 return iws
317 end
318
319
320 -- Internal functions
321
322 function _parse_delimited_table(iter, delimiter)
323 delimiter = delimiter or "%s+"
324
325 local data = {}
326 local trim = ffluci.util.trim
327 local split = ffluci.util.split
328
329 local keys = split(trim(iter()), delimiter, nil, true)
330 for i, j in pairs(keys) do
331 keys[i] = trim(keys[i])
332 end
333
334 for line in iter do
335 local row = {}
336 line = trim(line)
337 if #line > 0 then
338 for i, j in pairs(split(line, delimiter, nil, true)) do
339 if keys[i] then
340 row[keys[i]] = j
341 end
342 end
343 end
344 table.insert(data, row)
345 end
346
347 return data
348 end
349
350 function _parse_mixed_record(cnt)
351 local data = {}
352
353 for i, l in pairs(ffluci.util.split(ffluci.util.trim(cnt), "\n")) do
354 for j, f in pairs(ffluci.util.split(ffluci.util.trim(l), " ")) do
355 local k, x, v = f:match('([^%s][^:=]+) *([:=]*) *"*([^\n"]*)"*')
356
357 if k then
358 if x == "" then
359 table.insert(data, k)
360 else
361 data[k] = v
362 end
363 end
364 end
365 end
366
367 return data
368 end