c97017d8d039f5b381702225f7cf4e0264e23f31
[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
147 function net.hexip4(hex)
148 if #hex ~= 8 then
149 return nil
150 end
151
152 local hexdec = ffluci.bits.Hex2Dec
153
154 local ip = ""
155 ip = ip .. tostring(hexdec(hex:sub(7,8))) .. "."
156 ip = ip .. tostring(hexdec(hex:sub(5,6))) .. "."
157 ip = ip .. tostring(hexdec(hex:sub(3,4))) .. "."
158 ip = ip .. tostring(hexdec(hex:sub(1,2)))
159
160 return ip
161 end
162
163 -- Returns the binary IP to a given IP
164 function net.ip4bin(ip)
165 local parts = ffluci.util.split(ip, '.')
166 if #parts ~= 4 then
167 return nil
168 end
169
170 local decbin = ffluci.bits.Dec2Bin
171
172 local bin = ""
173 bin = bin .. decbin(parts[1], 8)
174 bin = bin .. decbin(parts[2], 8)
175 bin = bin .. decbin(parts[3], 8)
176 bin = bin .. decbin(parts[4], 8)
177
178 return bin
179 end
180
181 -- Tests whether a host is pingable
182 function net.pingtest(host)
183 return os.execute("ping -c1 '"..host:gsub("'", '').."' >/dev/null 2>&1")
184 end
185
186
187 process = {}
188 process.info = posix.getpid
189
190 -- Sets the gid of a process
191 function process.setgroup(pid, gid)
192 return posix.setpid("g", pid, gid)
193 end
194
195 -- Sets the uid of a process
196 function process.setuser(pid, uid)
197 return posix.setpid("u", pid, uid)
198 end
199
200 user = {}
201 -- returns user information to a given uid
202 user.getuser = posix.getpasswd
203
204 -- Changes the user password of given user
205 function user.setpasswd(user, pwd)
206 if pwd then
207 pwd = pwd:gsub("'", "")
208 end
209
210 if user then
211 user = user:gsub("'", "")
212 end
213
214 local cmd = "(echo '"..pwd.."';sleep 1;echo '"..pwd.."')|"
215 cmd = cmd .. "passwd '"..user.."' >/dev/null 2>&1"
216 return os.execute(cmd)
217 end
218
219
220 wifi = {}
221
222 function wifi.getiwconfig()
223 local cnt = exec("/usr/sbin/iwconfig 2>/dev/null")
224 local iwc = {}
225
226 for i, l in pairs(ffluci.util.split(ffluci.util.trim(cnt), "\n\n")) do
227 local k = l:match("^(.-) ")
228 l = l:gsub("^(.-) +", "", 1)
229 if k then
230 iwc[k] = _parse_mixed_record(l)
231 end
232 end
233
234 return iwc
235 end
236
237 function wifi.iwscan()
238 local cnt = exec("iwlist scan 2>/dev/null")
239 local iws = {}
240
241 for i, l in pairs(ffluci.util.split(ffluci.util.trim(cnt), "\n\n")) do
242 local k = l:match("^(.-) ")
243 l = l:gsub("^[^\n]+", "", 1)
244 l = ffluci.util.trim(l)
245 if k then
246 iws[k] = {}
247 for j, c in pairs(ffluci.util.split(l, "\n Cell")) do
248 c = c:gsub("^(.-)- ", "", 1)
249 c = ffluci.util.split(c, "\n", 7)
250 c = table.concat(c, "\n", 1)
251 table.insert(iws[k], _parse_mixed_record(c))
252 end
253 end
254 end
255
256 return iws
257 end
258
259
260 -- Internal functions
261
262 function _parse_delimited_table(iter, delimiter)
263 delimiter = delimiter or "\t+"
264
265 local data = {}
266 local trim = ffluci.util.trim
267 local split = ffluci.util.split
268
269 local keys = split(trim(iter()), delimiter, nil, true)
270 for i, j in pairs(keys) do
271 keys[i] = trim(keys[i])
272 end
273
274 for line in iter do
275 local row = {}
276 line = trim(line)
277 if #line > 0 then
278 for i, j in pairs(split(line, delimiter, nil, true)) do
279 if keys[i] then
280 row[keys[i]] = j
281 end
282 end
283 end
284 table.insert(data, row)
285 end
286
287 return data
288 end
289
290 function _parse_mixed_record(cnt)
291 local data = {}
292
293 for i, l in pairs(ffluci.util.split(ffluci.util.trim(cnt), "\n")) do
294 for j, f in pairs(ffluci.util.split(ffluci.util.trim(l), " ")) do
295 local k, x, v = f:match('([^%s][^:=]+) *([:=]*) *"*([^\n"]*)"*')
296
297 if k then
298 if x == "" then
299 table.insert(data, k)
300 else
301 data[k] = v
302 end
303 end
304 end
305 end
306
307 return data
308 end