* Added support for CGI SGI
[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