* ffluci.sys.net.hexip4: Added option for big endian support
[project/luci.git] / core / src / ffluci / 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 -- Runs "command" and returns its output
33 function exec(command)
34         local pp   = io.popen(command)
35         local data = pp:read("*a")
36         pp:close()
37         
38         return data
39 end
40
41 -- Runs "command" and returns its output as a array of lines
42 function execl(command)
43         local pp   = io.popen(command)  
44         local line = ""
45         local data = {}
46         
47         while true do
48                 line = pp:read()
49                 if (line == nil) then break end
50                 table.insert(data, line)
51         end 
52         pp:close()      
53         
54         return data
55 end
56
57 -- Uses "ffluci-flash" to flash a new image file to the system
58 function flash(image, kpattern)
59         local cmd = "ffluci-flash "
60         if kpattern then
61                 cmd = cmd .. "-k '" .. kpattern:gsub("'", "") .. "' "
62         end
63         cmd = cmd .. "'" .. image:gsub("'", "") .. "' >/dev/null 2>&1"
64         
65         return os.execute(cmd)
66 end
67
68 -- Returns the hostname
69 function hostname()
70         return io.lines("/proc/sys/kernel/hostname")()
71 end
72
73 -- Returns the contents of a documented referred by an URL
74 function httpget(url)
75         return exec("wget -qO- '"..url:gsub("'", "").."'")
76 end
77
78 -- Returns the load average
79 function loadavg()
80         local loadavg = io.lines("/proc/loadavg")()
81         return loadavg:match("^(.-) (.-) (.-) (.-) (.-)$")
82 end
83
84 -- Reboots the system
85 function reboot()
86         return os.execute("reboot >/dev/null 2>&1")
87 end
88
89 -- Returns the system type, cpu name, and installed physical memory
90 function sysinfo()
91         local c1 = "cat /proc/cpuinfo|grep system\\ typ|cut -d: -f2 2>/dev/null"
92         local c2 = "uname -m 2>/dev/null"
93         local c3 = "cat /proc/cpuinfo|grep model\\ name|cut -d: -f2 2>/dev/null"
94         local c4 = "cat /proc/cpuinfo|grep cpu\\ model|cut -d: -f2 2>/dev/null"
95         local c5 = "cat /proc/meminfo|grep MemTotal|cut -d: -f2 2>/dev/null"
96         
97         local s = ffluci.util.trim(exec(c1))
98         local m = ""
99         local r = ""
100         
101         if s == "" then
102                 s = ffluci.util.trim(exec(c2))
103                 m = ffluci.util.trim(exec(c3))
104         else
105                 m = ffluci.util.trim(exec(c4))
106         end
107         
108         r = ffluci.util.trim(exec(c5))
109         
110         return s, m, r
111 end
112
113
114 group = {}
115 group.getgroup = posix.getgroup
116
117 net = {}
118 -- Returns whether an IP-Adress belongs to a certain net
119 function net.belongs(ip, net)
120         local netparts = ffluci.util.split(net, "/")
121         
122         if #netparts ~= 2 then
123                 return nil
124         end
125         
126         local binadr = net.ip4bin(ip)
127         local binnet = net.ip4bin(netparts[1])
128         
129         return (binadr:sub(1, netparts[2]) == binnet:sub(1, netparts[2]))
130 end
131
132 -- Returns all available network interfaces
133 function net.devices()
134         local devices = {}
135         for line in io.lines("/proc/net/dev") do
136                 table.insert(devices, line:match(" *(.-):"))
137         end
138         return devices
139 end
140
141 -- Returns the kernel routing table
142 function net.routes()
143         return _parse_delimited_table(io.lines("/proc/net/route"))
144 end
145
146 -- Returns the numeric IP to a given hexstring (little endian)
147 function net.hexip4(hex, bigendian)
148         if #hex ~= 8 then
149                 return nil
150         end
151         
152         local hexdec = ffluci.bits.Hex2Dec
153         
154         local ip = ""
155         if bigendian then
156                 ip = ip .. tostring(hexdec(hex:sub(1,2))) .. "."
157                 ip = ip .. tostring(hexdec(hex:sub(3,4))) .. "."
158                 ip = ip .. tostring(hexdec(hex:sub(5,6))) .. "."
159                 ip = ip .. tostring(hexdec(hex:sub(7,8)))
160         else
161                 ip = ip .. tostring(hexdec(hex:sub(7,8))) .. "."
162                 ip = ip .. tostring(hexdec(hex:sub(5,6))) .. "."
163                 ip = ip .. tostring(hexdec(hex:sub(3,4))) .. "."
164                 ip = ip .. tostring(hexdec(hex:sub(1,2)))
165         end
166         
167         return ip
168 end
169
170 -- Returns the binary IP to a given IP
171 function net.ip4bin(ip)
172         local parts = ffluci.util.split(ip, '.')
173         if #parts ~= 4 then
174                 return nil
175         end
176         
177         local decbin = ffluci.bits.Dec2Bin
178         
179         local bin = ""
180         bin = bin .. decbin(parts[1], 8)
181         bin = bin .. decbin(parts[2], 8)
182         bin = bin .. decbin(parts[3], 8)
183         bin = bin .. decbin(parts[4], 8)
184         
185         return bin
186 end
187
188 -- Tests whether a host is pingable
189 function net.pingtest(host)
190         return os.execute("ping -c1 '"..host:gsub("'", '').."' >/dev/null 2>&1")
191 end
192
193
194 process = {}
195 process.info = posix.getpid 
196
197 -- Sets the gid of a process
198 function process.setgroup(pid, gid)
199         return posix.setpid("g", pid, gid)
200 end
201
202 -- Sets the uid of a process
203 function process.setuser(pid, uid)
204         return posix.setpid("u", pid, uid)
205 end
206
207 user = {}
208 -- returns user information to a given uid
209 user.getuser = posix.getpasswd
210         
211 -- Changes the user password of given user
212 function user.setpasswd(user, pwd)
213         if pwd then
214                 pwd = pwd:gsub("'", "")
215         end
216         
217         if user then
218                 user = user:gsub("'", "")
219         end
220         
221         local cmd = "(echo '"..pwd.."';sleep 1;echo '"..pwd.."')|"
222         cmd = cmd .. "passwd '"..user.."' >/dev/null 2>&1"
223         return os.execute(cmd)
224 end
225
226
227 wifi = {}
228
229 function wifi.getiwconfig()
230         local cnt = exec("/usr/sbin/iwconfig 2>/dev/null")
231         local iwc = {}
232         
233         for i, l in pairs(ffluci.util.split(ffluci.util.trim(cnt), "\n\n")) do
234                 local k = l:match("^(.-) ")
235                 l = l:gsub("^(.-) +", "", 1)
236                 if k then
237                         iwc[k] = _parse_mixed_record(l)
238                 end
239         end
240         
241         return iwc      
242 end
243
244 function wifi.iwscan()
245         local cnt = exec("iwlist scan 2>/dev/null")
246         local iws = {}
247         
248         for i, l in pairs(ffluci.util.split(ffluci.util.trim(cnt), "\n\n")) do
249                 local k = l:match("^(.-) ")
250                 l = l:gsub("^[^\n]+", "", 1)
251                 l = ffluci.util.trim(l)
252                 if k then
253                         iws[k] = {}
254                         for j, c in pairs(ffluci.util.split(l, "\n          Cell")) do
255                                 c = c:gsub("^(.-)- ", "", 1)
256                                 c = ffluci.util.split(c, "\n", 7)
257                                 c = table.concat(c, "\n", 1)
258                                 table.insert(iws[k], _parse_mixed_record(c))
259                         end
260                 end
261         end
262         
263         return iws      
264 end
265
266
267 -- Internal functions
268
269 function _parse_delimited_table(iter, delimiter)
270         delimiter = delimiter or "\t+"
271         
272         local data  = {}
273         local trim  = ffluci.util.trim
274         local split = ffluci.util.split
275         
276         local keys = split(trim(iter()), delimiter, nil, true)
277         for i, j in pairs(keys) do
278                 keys[i] = trim(keys[i])
279         end
280         
281         for line in iter do
282                 local row = {}
283                 line = trim(line)
284                 if #line > 0 then
285                         for i, j in pairs(split(line, delimiter, nil, true)) do
286                                 if keys[i] then
287                                         row[keys[i]] = j
288                                 end
289                         end
290                 end
291                 table.insert(data, row)
292         end
293         
294         return data
295 end
296
297 function _parse_mixed_record(cnt)
298         local data = {}
299         
300         for i, l in pairs(ffluci.util.split(ffluci.util.trim(cnt), "\n")) do
301         for j, f in pairs(ffluci.util.split(ffluci.util.trim(l), "  ")) do
302                 local k, x, v = f:match('([^%s][^:=]+) *([:=]*) *"*([^\n"]*)"*')
303
304             if k then
305                                 if x == "" then
306                                         table.insert(data, k)                           
307                                 else
308                         data[k] = v
309                                 end
310             end
311         end
312         end
313                 
314     return data
315 end