Merge pull request #1735 from sumpfralle/olsr-jsoninfo-parser-handle-empty-result
[oweals/luci.git] / modules / luci-base / luasrc / tools / status.lua
1 -- Copyright 2011 Jo-Philipp Wich <jow@openwrt.org>
2 -- Licensed to the public under the Apache License 2.0.
3
4 module("luci.tools.status", package.seeall)
5
6 local uci = require "luci.model.uci".cursor()
7 local ipc = require "luci.ip"
8
9 local function dhcp_leases_common(family)
10         local rv = { }
11         local nfs = require "nixio.fs"
12         local sys = require "luci.sys"
13         local leasefile = "/tmp/dhcp.leases"
14
15         uci:foreach("dhcp", "dnsmasq",
16                 function(s)
17                         if s.leasefile and nfs.access(s.leasefile) then
18                                 leasefile = s.leasefile
19                                 return false
20                         end
21                 end)
22
23         local fd = io.open(leasefile, "r")
24         if fd then
25                 while true do
26                         local ln = fd:read("*l")
27                         if not ln then
28                                 break
29                         else
30                                 local ts, mac, ip, name, duid = ln:match("^(%d+) (%S+) (%S+) (%S+) (%S+)")
31                                 local expire = tonumber(ts) or 0
32                                 if ts and mac and ip and name and duid then
33                                         if family == 4 and not ip:match(":") then
34                                                 rv[#rv+1] = {
35                                                         expires  = (expire ~= 0) and os.difftime(expire, os.time()),
36                                                         macaddr  = ipc.checkmac(mac) or "00:00:00:00:00:00",
37                                                         ipaddr   = ip,
38                                                         hostname = (name ~= "*") and name
39                                                 }
40                                         elseif family == 6 and ip:match(":") then
41                                                 rv[#rv+1] = {
42                                                         expires  = (expire ~= 0) and os.difftime(expire, os.time()),
43                                                         ip6addr  = ip,
44                                                         duid     = (duid ~= "*") and duid,
45                                                         hostname = (name ~= "*") and name
46                                                 }
47                                         end
48                                 end
49                         end
50                 end
51                 fd:close()
52         end
53
54         local lease6file = "/tmp/hosts/odhcpd"
55         uci:foreach("dhcp", "odhcpd",
56                 function(t)
57                         if t.leasefile and nfs.access(t.leasefile) then
58                                 lease6file = t.leasefile
59                                 return false
60                         end
61                 end)
62         local fd = io.open(lease6file, "r")
63         if fd then
64                 while true do
65                         local ln = fd:read("*l")
66                         if not ln then
67                                 break
68                         else
69                                 local iface, duid, iaid, name, ts, id, length, ip = ln:match("^# (%S+) (%S+) (%S+) (%S+) (-?%d+) (%S+) (%S+) (.*)")
70                                 local expire = tonumber(ts) or 0
71                                 if ip and iaid ~= "ipv4" and family == 6 then
72                                         rv[#rv+1] = {
73                                                 expires  = (expire >= 0) and os.difftime(expire, os.time()),
74                                                 duid     = duid,
75                                                 ip6addr  = ip,
76                                                 hostname = (name ~= "-") and name
77                                         }
78                                 elseif ip and iaid == "ipv4" and family == 4 then
79                                         rv[#rv+1] = {
80                                                 expires  = (expire >= 0) and os.difftime(expire, os.time()),
81                                                 macaddr  = sys.net.duid_to_mac(duid) or "00:00:00:00:00:00",
82                                                 ipaddr   = ip,
83                                                 hostname = (name ~= "-") and name
84                                         }
85                                 end
86                         end
87                 end
88                 fd:close()
89         end
90
91         if family == 6 then
92                 local _, lease
93                 local hosts = sys.net.host_hints()
94                 for _, lease in ipairs(rv) do
95                         local mac = sys.net.duid_to_mac(lease.duid)
96                         local host = mac and hosts[mac]
97                         if host then
98                                 if not lease.name then
99                                         lease.host_hint = host.name or host.ipv4 or host.ipv6
100                                 elseif host.name and lease.hostname ~= host.name then
101                                         lease.host_hint = host.name
102                                 end
103                         end
104                 end
105         end
106
107         return rv
108 end
109
110 function dhcp_leases()
111         return dhcp_leases_common(4)
112 end
113
114 function dhcp6_leases()
115         return dhcp_leases_common(6)
116 end
117
118 function wifi_networks()
119         local rv = { }
120         local ntm = require "luci.model.network".init()
121
122         local dev
123         for _, dev in ipairs(ntm:get_wifidevs()) do
124                 local rd = {
125                         up       = dev:is_up(),
126                         device   = dev:name(),
127                         name     = dev:get_i18n(),
128                         networks = { }
129                 }
130
131                 local net
132                 for _, net in ipairs(dev:get_wifinets()) do
133                         local a, an = nil, 0
134                         for _, a in pairs(net:assoclist() or {}) do
135                                 an = an + 1
136                         end
137
138                         rd.networks[#rd.networks+1] = {
139                                 name       = net:shortname(),
140                                 link       = net:adminlink(),
141                                 up         = net:is_up(),
142                                 mode       = net:active_mode(),
143                                 ssid       = net:active_ssid(),
144                                 bssid      = net:active_bssid(),
145                                 encryption = net:active_encryption(),
146                                 frequency  = net:frequency(),
147                                 channel    = net:channel(),
148                                 signal     = net:signal(),
149                                 quality    = net:signal_percent(),
150                                 noise      = net:noise(),
151                                 bitrate    = net:bitrate(),
152                                 ifname     = net:ifname(),
153                                 country    = net:country(),
154                                 txpower    = net:txpower(),
155                                 txpoweroff = net:txpower_offset(),
156                                 num_assoc  = an,
157                                 disabled   = (dev:get("disabled") == "1" or
158                                              net:get("disabled") == "1")
159                         }
160                 end
161
162                 rv[#rv+1] = rd
163         end
164
165         return rv
166 end
167
168 function wifi_network(id)
169         local ntm = require "luci.model.network".init()
170         local net = ntm:get_wifinet(id)
171         if net then
172                 local dev = net:get_device()
173                 if dev then
174                         return {
175                                 id         = id,
176                                 name       = net:shortname(),
177                                 link       = net:adminlink(),
178                                 up         = net:is_up(),
179                                 mode       = net:active_mode(),
180                                 ssid       = net:active_ssid(),
181                                 bssid      = net:active_bssid(),
182                                 encryption = net:active_encryption(),
183                                 frequency  = net:frequency(),
184                                 channel    = net:channel(),
185                                 signal     = net:signal(),
186                                 quality    = net:signal_percent(),
187                                 noise      = net:noise(),
188                                 bitrate    = net:bitrate(),
189                                 ifname     = net:ifname(),
190                                 country    = net:country(),
191                                 txpower    = net:txpower(),
192                                 txpoweroff = net:txpower_offset(),
193                                 disabled   = (dev:get("disabled") == "1" or
194                                               net:get("disabled") == "1"),
195                                 device     = {
196                                         up     = dev:is_up(),
197                                         device = dev:name(),
198                                         name   = dev:get_i18n()
199                                 }
200                         }
201                 end
202         end
203         return { }
204 end
205
206 function wifi_assoclist()
207         local sys = require "luci.sys"
208         local ntm = require "luci.model.network".init()
209         local hosts = sys.net.host_hints()
210
211         local assoc = {}
212         local _, dev, net, bss
213
214         for _, dev in ipairs(ntm:get_wifidevs()) do
215                 local radioname = dev:get_i18n()
216
217                 for _, net in ipairs(dev:get_wifinets()) do
218                         local netname = net:shortname()
219                         local netlink = net:adminlink()
220                         local ifname  = net:ifname()
221
222                         for _, bss in pairs(net:assoclist() or {}) do
223                                 local host = hosts[_]
224
225                                 bss.bssid  = _
226                                 bss.ifname = ifname
227                                 bss.radio  = radioname
228                                 bss.name   = netname
229                                 bss.link   = netlink
230
231                                 bss.host_name = (host) and (host.name or host.ipv4 or host.ipv6)
232                                 bss.host_hint = (host and host.name and (host.ipv4 or host.ipv6)) and (host.ipv4 or host.ipv6)
233
234                                 assoc[#assoc+1] = bss
235                         end
236                 end
237         end
238
239         table.sort(assoc, function(a, b)
240                 if a.radio ~= b.radio then
241                         return a.radio < b.radio
242                 elseif a.ifname ~= b.ifname then
243                         return a.ifname < b.ifname
244                 else
245                         return a.bssid < b.bssid
246                 end
247         end)
248
249         return assoc
250 end