3 # List all active leases
5 require './dhcpd-lib.pl';
6 require 'timelocal.pl';
10 %access = &get_module_acl();
11 &error_setup($text{'eacl_aviol'});
12 &error("$text{'eacl_np'} $text{'eacl_psl'}") unless $access{'r_leases'};
15 $desc = &text('listl_network', "<tt>$in{'network'}</tt>",
16 "<tt>$in{'netmask'}</tt>");
18 print "Refresh: $config{'lease_refresh'}\r\n"
19 if ($config{'lease_refresh'});
20 &ui_print_header($desc, $text{'listl_header'}, "");
22 # Work out how many IPs we have in our subnet ranges
24 $conf = &get_config();
25 @subnets = &find("subnet", $conf);
26 foreach $shared (&find("shared-network", $conf)) {
27 push(@subnets, &find("subnet", $shared->{'members'}));
29 foreach $subnet (@subnets) {
31 # Only count ranges in specified subnet
32 if ($subnet->{'values'}->[0] ne $in{'network'}) {
37 @ranges = &find("range", $subnet->{'members'});
38 foreach $pool (&find("pool", $subnet->{'members'})) {
39 push(@ranges, &find("range", $pool->{'members'}));
41 foreach $range (@ranges) {
42 local @rv = @{$range->{'values'}};
43 shift(@rv) if ($rv[0] eq "dynamic-bootp");
44 foreach $ip (&expand_ip_range($rv[0], $rv[1])) {
45 if (&within_network($ip)) {
46 $ranges{$ip} = $subnet;
53 if (!-r $config{'lease_file'}) {
55 print "<b>".&text('listl_lfnotexist',$config{'lease_file'})."</b><p>\n";
57 elsif (!&tokenize_file($config{'lease_file'}, \@tok)) {
58 # Leases file is not valid or empty
59 print "<b>",&text('listl_lfnotcont',$config{'lease_file'}),"</b><p>\n";
64 local @nw = split(/\./, $in{'network'});
65 local @nm = split(/\./, $in{'netmask'});
66 LEASE: while($i < @tok) {
67 $lease = &parse_struct(\@tok, \$i, $j++, $config{'lease_file'});
68 next if (!$lease || $lease->{'name'} ne 'lease');
69 local $mems = $lease->{'members'};
70 local $starts = &find('starts', $mems);
71 local $ends = &find('ends', $mems);
72 $lease->{'stime'} = &lease_time($starts);
73 $lease->{'etime'} = &lease_time($ends);
74 if ($lease->{'etime'} < $timenow ||
75 $lease->{'stime'} > $timenow) {
76 if ($in{'all'}) { $lease->{'expired'}++; }
79 next if (!&within_network($lease->{'values'}->[0]));
80 push(@leases, $lease);
83 # Show links to select mode, if not showing a single subnet
84 if (!$in{'network'}) {
87 $msg = $text{'listl_mode_'.$m};
88 if ($m != $in{'bysubnet'}) {
89 $msg = "<a href='list_leases.cgi?bysubnet=$m'>".
94 print "<b>$text{'listl_mode'}</b> ",
95 &ui_links_row(\@links),"<br>\n";
98 if ($in{'bysubnet'}) {
99 # Show table of subnets, with lease usage
100 print &ui_columns_start([
101 $text{'index_net'}, $text{'index_desc'},
102 $text{'listl_size'}, $text{'listl_used'},
103 $text{'listl_pc'} ], 100);
104 foreach $subnet (@subnets) {
106 foreach $lease (@leases) {
107 $r = $ranges{$lease->{'values'}->[0]};
108 if ($r eq $subnet && !$lease->{'expired'}) {
109 $used{$lease->{'values'}->[0]}++;
112 $used = scalar(keys %used);
113 print &ui_columns_row([
114 $subnet->{'values'}->[0],
115 &html_escape($subnet->{'comment'}),
119 int(100*$used / $subnet->{'ips'})."%" :
123 print &ui_columns_end();
126 # Sort leases by selected type
127 if ($in{'sort'} eq 'ipaddr') {
128 @leases = sort { &ip_compare($a, $b) } @leases;
130 elsif ($in{'sort'} eq 'ether') {
131 @leases = sort { ðer_compare($a, $b) } @leases;
133 elsif ($in{'sort'} eq 'host') {
134 @leases = sort { &hostname_compare($a, $b) } @leases;
136 elsif ($in{'sort'} eq 'start') {
137 @leases = sort { $a->{'stime'} <=> $b->{'stime'} }
140 elsif ($in{'sort'} eq 'end') {
141 @leases = sort { $a->{'etime'} <=> $b->{'etime'} }
144 elsif ($config{'lease_sort'} == 1) {
145 @leases = sort { &ip_compare($a, $b) } @leases;
147 elsif ($config{'lease_sort'} == 2) {
148 @leases = sort { &hostname_compare($a, $b) } @leases;
151 # Show available and used
153 foreach $lease (@leases) {
154 $ip = $lease->{'values'}->[0];
155 if ($ranges{$ip} && !$donelease{$ip}++ &&
156 !$lease->{'expired'}) {
161 print &text('listl_allocs',
162 scalar(keys %ranges), $leased,
163 int($leased*100/scalar(keys %ranges))),"<p>\n";
166 # Table header, with sorting
167 @tds = ( "width=5" );
168 print &ui_form_start("delete_leases.cgi", "post");
169 print &ui_hidden("all", $in{'all'});
170 print &ui_hidden("network", $in{'network'});
171 print &ui_hidden("netmask", $in{'netmask'});
172 @links = ( &select_all_link("d"), &select_invert_link("d") );
173 $links = "<table width=100%><tr><td>".
174 &ui_links_row(\@links).
175 "</td><td align=right>".
176 &ui_links_row([ "<a href='list_leases.cgi?$in'>".
177 "$text{'listl_refresh'}</a>" ]).
178 "</td></tr></table>\n";
180 print &ui_columns_start([
182 &sort_link("ipaddr"),
189 foreach $lease (@leases) {
191 local $mems = $lease->{'members'};
192 local $starts = &find('starts', $mems);
193 local $ends = &find('ends', $mems);
194 local $ht = $lease->{'expired'} ? "i" : "tt";
195 push(@cols, "<$ht>$lease->{'values'}->[0]</$ht>");
196 local $hard = &find('hardware', $mems);
197 push(@cols,$hard->{'values'}->[1] ?
198 "<tt>$hard->{'values'}->[1]</tt>" :
199 "<i>$text{'listl_unknown'}</i>");
200 local $client = &find('client-hostname', $mems);
201 push(@cols, $client ? "<tt>".&html_escape(
202 $client->{'values'}->[0])."</tt>"
204 if ($config{'lease_tz'}) {
205 $s = &make_date($lease->{'stime'});
206 $e = &make_date($lease->{'etime'});
209 $s = $starts->{'values'}->[1]." ".
210 $starts->{'values'}->[2];
211 $e = $ends->{'values'}->[1]." ".
212 $ends->{'values'}->[2];
215 push(@cols, "<tt>$s</tt>");
216 push(@cols, "<tt>$e</tt>");
217 print &ui_checked_columns_row(\@cols, \@tds, "d",
220 print &ui_columns_end();
222 print &ui_form_end([ [ undef, $text{'listl_delete'} ] ]);
225 print "<b>",&text($in{'all'} ? 'listl_lfnotcont' :
226 'listl_lfnotcont2', $config{'lease_file'}),
229 if (!$in{'all'} && !$in{'bysubnet'}) {
230 print &ui_form_start("list_leases.cgi");
231 print &ui_hidden("all", 1);
232 print &ui_hidden("network", $in{'network'});
233 print &ui_hidden("netmask", $in{'netmask'});
234 print &ui_form_end([ [ undef, $text{'listl_all'} ] ]);
238 &ui_print_footer("", $text{'listl_return'});
242 local @d = split(/\//, $_[0]->{'values'}->[1]);
243 local @t = split(/:/, $_[0]->{'values'}->[2]);
245 eval { $t = timegm($t[2], $t[1], $t[0], $d[2], $d[1]-1, $d[0]-1900) };
246 return $@ ? undef : $t;
251 $a->{'values'}->[0] =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)/;
252 local ($a1, $a2, $a3, $a4) = ($1, $2, $3, $4);
253 $b->{'values'}->[0] =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)/;
254 return $a1 < $1 ? -1 :
266 local $client_a = &find_value('client-hostname', $a->{'members'});
267 local $client_b = &find_value('client-hostname', $b->{'members'});
268 return lc($client_a) cmp lc($client_b);
273 local $ether_a = &find('hardware', $a->{'members'});
274 local $ether_b = &find('hardware', $b->{'members'});
275 return lc($ether_a->{'values'}->[1]) cmp lc($ether_b->{'values'}->[1]);
281 if ($in{'sort'} eq $c) {
282 return $text{'listl_'.$c};
285 return "<a href='list_leases.cgi?all=$in{'all'}&network=$in{'network'}&netmask=$in{'netmask'}&sort=$c'>".$text{'listl_'.$c}."</a>";
292 if ($in{'network'}) {
293 # Is lease within network/netmask?
294 local @ad = split(/\./, $ip);
295 for($k=0; $k<4; $k++) {
296 if ((int($ad[$k]) & int($nm[$k])) != int($nw[$k])) {