+ my @rows;
+
+ my $debug_proc = '';
+
+warn "XXX pids = ", dump( $daemons::pids );
+
+ foreach my $name ( sort keys %$daemons::pids ) {
+ my $pid = $daemons::pids->{$name}; # || next;
+
+ my $html;
+
+ my $proc = "/proc/$pid/status";
+
+ if ( -e $proc ) {
+ $html .= qq|<a href=/start_stop/$name>$pid</a>|;
+ if ( $debug ) {
+ $html .= qq| <a name=$pid href=#proc-$pid>?</a>| if $name->can('start');
+
+ $debug_proc
+ .= qq|<a name=proc-$pid href=#$pid>$proc</a><pre style="font-size: 10%">|
+ . read_file($proc)
+ . qq|</pre>|
+ ;
+ }
+
+ if ( $name->can('fork_if_active') ) {
+ $html .= qq| <a href=/start_stop/$name/$_>$_</a>| foreach $name->fork_if_active;
+ }
+
+ if ( $name->can('actions') ) {
+ $html .= qq| <a href=/action/$name/$_>$_</a>| foreach $name->actions;
+ }
+ } else {
+ if ( $pid =~ m{^\d+$} ) {
+ $html .= qq|$pid exited |
+ } else {
+ $html .= qq|$pid |;
+ }
+ $html .= qq|<a href=/start_stop/$name>restart</a>| if $pid || $name->can('start');
+ if ( $name->can('fork_actions') ) {
+ $html .= qq| <a href=/start_stop/$name/$_>$_</a>| foreach $name->fork_actions;
+ }
+ }
+
+ die "no html generated" unless $html;
+
+ push @rows, ( $name => $html );
+ }
+
+ my $below_table = '';
+
+ warn 'static_pids: ', dump( $static_pids ) if $debug;
+ foreach my $pid ( keys %$static_pids ) {
+ my $path = $static_pids->{$pid};
+ if ( -d "/proc/$pid" ) {
+ push @rows, ( $path => qq|<a href=/kill/static/$pid>$pid</a>| );
+ } elsif ( $param->{clean_completed_downloads} ) {
+ delete $static_pids->{$pid}
+ } else {
+ push @rows, ( $path => "$pid competed" );
+ $below_table = qq|<a href="/?clean_completed_downloads=1">clean completed downloads</a>|;
+ }
+ }
+
+ print $client ok
+ , html::table( 2, @rows )
+ , $below_table
+ , html::tabs( log::mac_changes )
+ , $debug_proc
+ ;
+
+ } elsif ( $path =~ m{^/server} ) {
+ print $client ok
+ , html::table( 2,
+ 'debug' => qq|<a href=/our/debug/| . boolean::toggle($debug) . qq|>$debug</a>|,
+ map {
+ ( $_, html::tt eval '$server::'.$_ )
+ } ( 'ip', 'netmask', 'ip_from', 'ip_to', 'domain_name', 'base_dir', 'conf' )
+ )
+ ;
+ } elsif ( $path =~ m!^/client(?:/$RE{net}{IPv4}{-keep})?! ) {
+ my $ip = $1;
+
+ if ( $param->{action} eq 'remove' ) {
+ client::remove( $param->{change_ip} );
+ print $client redirect("$url/client");
+ return;
+ } elsif ( $param->{action} eq 'change' ) {
+ if ( my $new_ip = client::change_ip( $ip, $param->{change_ip} ) ) {
+ print $client redirect("$url/client#$new_ip");
+ return;
+ }
+ }
+
+ if ( ! $ip ) {
+ my $peer_ip = $client->peerhost;
+
+ my $netmask = ip::to_int $server::netmask;
+ my $network = ip::to_int $server::ip & $netmask;
+ my ( $from, $to ) = ( $network | $server::ip_from, $network | $server::ip_to );
+ my $ip_int = ip::to_int $peer_ip;
+
+ # show edit for clients in our dhcp range
+ if ( $ip_int >= ( $network | $server::ip_from ) && $ip_int <= ( $network | $server::ip_to ) ) {
+ $ip = $peer_ip;
+ }
+ }
+
+ if ( $ip && $ip ne $server::ip ) {
+ my $hostname = client::conf( $ip, 'hostname' => $param->{hostname} );
+
+ my @table = (
+ 'ip' => qq|<input type=text name=change_ip value="$ip" onChange="document.getElementById('old_ip').style.display = '';"><span id=old_ip style="display: none; color: #888;">old: $ip<span>|,
+ 'hostname' => qq|<input type=text name=hostname value="$hostname">|,
+ );