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