b9d529a8c8a89b895b379f6ec5d827acde7e9441
[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 if k then
245 iws[k] = {}
246 for j, c in pairs(ffluci.util.split(l, "\n Cell")) do
247 c = c:gsub("^(.-)- ", "", 1)
248 c = ffluci.util.split(c, "\n", 7)
249 c = table.concat(c, "\n", 1, 7)
250 table.insert(iws[k], _parse_mixed_record(c))
251 end
252 end
253 end
254
255 return iws
256 end
257
258
259 -- Internal functions
260
261 function _parse_delimited_table(iter, delimiter)
262 delimiter = delimiter or "\t+"
263
264 local data = {}
265 local trim = ffluci.util.trim
266 local split = ffluci.util.split
267
268 local keys = split(trim(iter()), delimiter, nil, true)
269 for i, j in pairs(keys) do
270 keys[i] = trim(keys[i])
271 end
272
273 for line in iter do
274 local row = {}
275 line = trim(line)
276 if #line > 0 then
277 for i, j in pairs(split(line, delimiter, nil, true)) do
278 if keys[i] then
279 row[keys[i]] = j
280 end
281 end
282 end
283 table.insert(data, row)
284 end
285
286 return data
287 end
288
289 function _parse_mixed_record(cnt)
290 local data = {}
291
292 for i, l in pairs(ffluci.util.split(ffluci.util.trim(cnt), "\n")) do
293 for j, f in pairs(ffluci.util.split(ffluci.util.trim(l), " ")) do
294 local k, x, v = f:match('([^%s][^:=]+) *([:=]*) *"*([^\n"]*)"*')
295
296 if k then
297 if x == "" then
298 table.insert(data, k)
299 else
300 data[k] = v
301 end
302 end
303 end
304 end
305
306 return data
307 end