fixup whitespace. Switch to useconds and sleep and sleep for less time when starting up and comment out the 5 second shutdown wait.

This commit is contained in:
Isaac Connor 2017-04-28 10:32:05 -04:00
parent fa0e1b728c
commit e9e913c043
1 changed files with 491 additions and 480 deletions

View File

@ -27,7 +27,7 @@ zmdc.pl - ZoneMinder Daemon Control script
=head1 SYNOPSIS =head1 SYNOPSIS
zmdc.pl {command} [daemon [options]] zmdc.pl {command} [daemon [options]]
=head1 DESCRIPTION =head1 DESCRIPTION
@ -39,12 +39,13 @@ connect to the server and pass instructions to it.
=head1 OPTIONS =head1 OPTIONS
{command} - One of 'startup|shutdown|status|check|logrot' or {command} - One of 'startup|shutdown|status|check|logrot' or
'start|stop|restart|reload|version'. 'start|stop|restart|reload|version'.
[daemon [options]] - Daemon name and options, required for second group of commands [daemon [options]] - Daemon name and options, required for second group of commands
=cut =cut
use strict; use strict;
use warnings;
use bytes; use bytes;
# ========================================================================== # ==========================================================================
@ -53,7 +54,9 @@ use bytes;
# #
# ========================================================================== # ==========================================================================
use constant MAX_CONNECT_DELAY => 10; # in useconds, not seconds.
use constant MAX_CONNECT_DELAY => 10*1000*1000;
use constant KILL_DELAY => 10*1000; # 1/10th of a second
# ========================================================================== # ==========================================================================
# #
@ -66,6 +69,7 @@ use ZoneMinder;
use POSIX; use POSIX;
use Socket; use Socket;
use IO::Handle; use IO::Handle;
use Time::HiRes qw(usleep);
use autouse 'Pod::Usage'=>qw(pod2usage); use autouse 'Pod::Usage'=>qw(pod2usage);
#use Data::Dumper; #use Data::Dumper;
@ -98,10 +102,10 @@ my @daemons = (
'zmupdate.pl', 'zmupdate.pl',
'zmtrack.pl', 'zmtrack.pl',
'zmtelemetry.pl' 'zmtelemetry.pl'
); );
my $command = shift @ARGV; my $command = shift @ARGV;
if( !$command ) { if( ! $command ) {
print( STDERR "No command given\n" ); print( STDERR "No command given\n" );
pod2usage(-exitstatus => -1); pod2usage(-exitstatus => -1);
} }
@ -111,7 +115,7 @@ if ( $command eq 'version' ) {
} }
my $needs_daemon = $command !~ /(?:startup|shutdown|status|check|logrot|version)/; my $needs_daemon = $command !~ /(?:startup|shutdown|status|check|logrot|version)/;
my $daemon = shift( @ARGV ); my $daemon = shift( @ARGV );
if( $needs_daemon && !$daemon ) { if ( $needs_daemon && ! $daemon ) {
print( STDERR "No daemon given\n" ); print( STDERR "No daemon given\n" );
pod2usage(-exitstatus => -1); pod2usage(-exitstatus => -1);
} }
@ -128,8 +132,8 @@ if ( $needs_daemon ) {
} }
foreach my $arg ( @ARGV ) { foreach my $arg ( @ARGV ) {
# Detaint arguments, if they look ok # Detaint arguments, if they look ok
#if ( $arg =~ /^(-{0,2}[\w]+)/ ) #if ( $arg =~ /^(-{0,2}[\w]+)/ )
if ( $arg =~ /^(-{0,2}[\w\/?&=.-]+)$/ ) { if ( $arg =~ /^(-{0,2}[\w\/?&=.-]+)$/ ) {
push( @args, $1 ); push( @args, $1 );
} else { } else {
@ -142,8 +146,10 @@ socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" );
my $saddr = sockaddr_un( SOCK_FILE ); my $saddr = sockaddr_un( SOCK_FILE );
my $server_up = connect( CLIENT, $saddr ); my $server_up = connect( CLIENT, $saddr );
if ( !$server_up ) { if ( ! $server_up ) {
# Server is not up. Some commands can still be handled
if ( $command eq 'logrot' ) { if ( $command eq 'logrot' ) {
# If server is not running, then logrotate doesn't need to do anything.
exit(); exit();
} }
if ( $command eq 'check' ) { if ( $command eq 'check' ) {
@ -153,43 +159,47 @@ if ( !$server_up ) {
print( "Unable to connect to server using socket at " . SOCK_FILE . "\n" ); print( "Unable to connect to server using socket at " . SOCK_FILE . "\n" );
exit( -1 ); exit( -1 );
} }
# The server isn't there # The server isn't there
print( "Starting server\n" ); print( "Starting server\n" );
close( CLIENT ); close( CLIENT );
if ( my $cpid = fork() ) { if ( my $cpid = fork() ) {
# Parent process just sleep and fall through
# I'm still not sure why we need to re-init the logs
logInit(); logInit();
# Parent process just sleep and fall through
socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" );
my $attempts = 0; my $attempts = 0;
while (!connect( CLIENT, $saddr )) { while( !connect( CLIENT, $saddr ) ) {
$attempts++; $attempts++;
Error("Waiting for zmdc.pl server process, attempt $attempts" );
Fatal( "Can't connect: $!" ) if ($attempts > MAX_CONNECT_DELAY); Fatal( "Can't connect: $!" ) if ($attempts > MAX_CONNECT_DELAY);
sleep(1); usleep(100);
} } # end while
} elsif ( defined($cpid) ) { } elsif ( defined($cpid) ) {
ZMServer::run(); ZMServer::run();
} else { } else {
Fatal( "Can't fork: $!" ); Fatal( "Can't fork: $!" );
} }
} } # end if ! server is up
if ( $command eq 'check' && !$daemon ) {
if ( $command eq 'check' && ! $daemon ) {
print( "running\n" ); print( "running\n" );
exit(); exit();
} elsif ( $command eq 'startup' ) { } elsif ( $command eq 'startup' ) {
# Our work here is done # Our work here is done
exit() if ( !$server_up ); exit() if ( !$server_up );
} }
# The server is there, connect to it # The server is there, connect to it
#print( "Writing commands\n" ); #print( "Writing commands\n" );
CLIENT->autoflush(); CLIENT->autoflush();
my $message = "$command"; my $message = join(';', $command, ( $daemon ? $daemon : () ), @args );
$message .= ";$daemon" if ( $daemon );
$message .= ";".join( ';', @args ) if ( @args );
print( CLIENT $message ); print( CLIENT $message );
shutdown( CLIENT, 1 ); shutdown( CLIENT, 1 );
while ( my $line = <CLIENT> ) { while( my $line = <CLIENT> ) {
chomp( $line ); chomp( $line );
print( "$line\n" ); print( "$line\n" );
} }
@ -202,6 +212,7 @@ exit;
package ZMServer; package ZMServer;
use strict; use strict;
use warnings;
use bytes; use bytes;
@EXTRA_PERL_LIB@ @EXTRA_PERL_LIB@
@ -275,7 +286,7 @@ sub run {
} elsif ( $command eq 'reload' ) { } elsif ( $command eq 'reload' ) {
reload( $daemon, @args ); reload( $daemon, @args );
} elsif ( $command eq 'startup' ) { } elsif ( $command eq 'startup' ) {
# Do nothing, this is all we're here for # Do nothing, this is all we're here for
dPrint( ZoneMinder::Logger::WARNING, "Already running, ignoring command '$command'\n" ); dPrint( ZoneMinder::Logger::WARNING, "Already running, ignoring command '$command'\n" );
} elsif ( $command eq 'shutdown' ) { } elsif ( $command eq 'shutdown' ) {
shutdownAll(); shutdownAll();
@ -298,9 +309,9 @@ sub run {
} }
} elsif ( $nfound < 0 ) { } elsif ( $nfound < 0 ) {
if ( $! == EINTR ) { if ( $! == EINTR ) {
# Dead child, will be reaped # Dead child, will be reaped
#print( "Probable dead child\n" ); #print( "Probable dead child\n" );
# See if it needs to start up again # See if it needs to start up again
restartPending(); restartPending();
} elsif ( $! == EPIPE ) { } elsif ( $! == EPIPE ) {
Error( "Can't select: $!" ); Error( "Can't select: $!" );
@ -308,7 +319,7 @@ sub run {
Fatal( "Can't select: $!" ); Fatal( "Can't select: $!" );
} }
} else { } else {
#print( "Select timed out\n" ); #print( "Select timed out\n" );
restartPending(); restartPending();
} }
} }
@ -353,7 +364,7 @@ sub start {
my $process = $cmd_hash{$command}; my $process = $cmd_hash{$command};
if ( !$process ) { if ( !$process ) {
# It's not running, or at least it's not been started by us # It's not running, or at least it's not been started by us
$process = { daemon=>$daemon, args=>\@args, command=>$command, keepalive=>!undef }; $process = { daemon=>$daemon, args=>\@args, command=>$command, keepalive=>!undef };
} elsif ( $process->{pid} && $pid_hash{$process->{pid}} ) { } elsif ( $process->{pid} && $pid_hash{$process->{pid}} ) {
dPrint( ZoneMinder::Logger::INFO, "'$process->{command}' already running at " dPrint( ZoneMinder::Logger::INFO, "'$process->{command}' already running at "
@ -381,7 +392,7 @@ sub start {
$cmd_hash{$process->{command}} = $pid_hash{$cpid} = $process; $cmd_hash{$process->{command}} = $pid_hash{$cpid} = $process;
sigprocmask( SIG_SETMASK, $sigset ) or Fatal( "Can't restore SIGCHLD: $!" ); sigprocmask( SIG_SETMASK, $sigset ) or Fatal( "Can't restore SIGCHLD: $!" );
} elsif ( defined($cpid ) ) { } elsif ( defined($cpid ) ) {
# Force reconnection to the db. # Force reconnection to the db.
zmDbConnect(1); zmDbConnect(1);
logReinit(); logReinit();
@ -399,7 +410,7 @@ sub start {
my @good_args; my @good_args;
foreach my $arg ( @args ) { foreach my $arg ( @args ) {
# Detaint arguments, if they look ok # Detaint arguments, if they look ok
if ( $arg =~ /^(-{0,2}[\w\/?&=.-]+)$/ ) { if ( $arg =~ /^(-{0,2}[\w\/?&=.-]+)$/ ) {
push( @good_args, $1 ); push( @good_args, $1 );
} else { } else {
@ -415,7 +426,7 @@ sub start {
POSIX::close( $fd++ ); POSIX::close( $fd++ );
} }
# Child process # Child process
$SIG{CHLD} = 'DEFAULT'; $SIG{CHLD} = 'DEFAULT';
$SIG{INT} = 'DEFAULT'; $SIG{INT} = 'DEFAULT';
$SIG{TERM} = 'DEFAULT'; $SIG{TERM} = 'DEFAULT';
@ -474,7 +485,7 @@ sub kill_until_dead {
} }
sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n"; sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n";
usleep( 100 ); usleep( KILL_DELAY );
sigprocmask(SIG_BLOCK, $blockset, $sigset ) or die "dying at block...\n"; sigprocmask(SIG_BLOCK, $blockset, $sigset ) or die "dying at block...\n";
} }
} }
@ -581,7 +592,7 @@ sub reaper {
$out_str .= 'normally'; $out_str .= 'normally';
} }
} }
#print( ", core dumped" ) if ( $core_dumped ); #print( ", core dumped" ) if ( $core_dumped );
$out_str .= "\n"; $out_str .= "\n";
if ( $exit_status == 0 ) { if ( $exit_status == 0 ) {
@ -591,16 +602,16 @@ sub reaper {
} }
if ( $process->{keepalive} ) { if ( $process->{keepalive} ) {
# Schedule for immediate restart # Schedule for immediate restart
$cmd_hash{$process->{command}} = $process; $cmd_hash{$process->{command}} = $process;
if ( !$process->{delay} || ($process->{runtime} > $Config{ZM_MAX_RESTART_DELAY} ) ) { if ( !$process->{delay} || ($process->{runtime} > $Config{ZM_MAX_RESTART_DELAY} ) ) {
#start( $process->{daemon}, @{$process->{args}} ); #start( $process->{daemon}, @{$process->{args}} );
$process->{pending} = $process->{stopped}; $process->{pending} = $process->{stopped};
$process->{delay} = 5; $process->{delay} = 5;
} else { } else {
$process->{pending} = $process->{stopped}+$process->{delay}; $process->{pending} = $process->{stopped}+$process->{delay};
$process->{delay} *= 2; $process->{delay} *= 2;
# Limit the start delay to 15 minutes max # Limit the start delay to 15 minutes max
if ( $process->{delay} > $Config{ZM_MAX_RESTART_DELAY} ) { if ( $process->{delay} > $Config{ZM_MAX_RESTART_DELAY} ) {
$process->{delay} = $Config{ZM_MAX_RESTART_DELAY}; $process->{delay} = $Config{ZM_MAX_RESTART_DELAY};
} }
@ -612,7 +623,7 @@ sub reaper {
} }
sub restartPending { sub restartPending {
# Restart any pending processes # Restart any pending processes
foreach my $process ( values( %cmd_hash ) ) { foreach my $process ( values( %cmd_hash ) ) {
if ( $process->{pending} && $process->{pending} <= time() ) { if ( $process->{pending} && $process->{pending} <= time() ) {
dPrint( ZoneMinder::Logger::INFO, "Starting pending process, $process->{command}\n" ); dPrint( ZoneMinder::Logger::INFO, "Starting pending process, $process->{command}\n" );
@ -623,12 +634,12 @@ sub restartPending {
sub shutdownAll { sub shutdownAll {
foreach my $pid ( keys %pid_hash ) { foreach my $pid ( keys %pid_hash ) {
# This is a quick fix because a SIGCHLD can happen and alter pid_hash while we are in here. # This is a quick fix because a SIGCHLD can happen and alter pid_hash while we are in here.
next if ! $pid_hash{$pid}; next if ! $pid_hash{$pid};
send_stop( 1, $pid_hash{$pid} ); send_stop( 1, $pid_hash{$pid} );
} }
foreach my $pid ( keys %pid_hash ) { foreach my $pid ( keys %pid_hash ) {
# This is a quick fix because a SIGCHLD can happen and alter pid_hash while we are in here. # This is a quick fix because a SIGCHLD can happen and alter pid_hash while we are in here.
next if ! $pid_hash{$pid}; next if ! $pid_hash{$pid};
my $process = $pid_hash{$pid}; my $process = $pid_hash{$pid};
@ -637,7 +648,9 @@ sub shutdownAll {
delete( $cmd_hash{$$process{command}} ); delete( $cmd_hash{$$process{command}} );
delete( $pid_hash{$pid} ); delete( $pid_hash{$pid} );
} }
if ( 0 ) {
killAll( 5 ); killAll( 5 );
}
dPrint( ZoneMinder::Logger::INFO, "Server shutdown at " dPrint( ZoneMinder::Logger::INFO, "Server shutdown at "
.strftime( '%y/%m/%d %H:%M:%S', localtime() ) .strftime( '%y/%m/%d %H:%M:%S', localtime() )
."\n" ."\n"
@ -653,8 +666,7 @@ sub check {
my $daemon = shift; my $daemon = shift;
my @args = @_; my @args = @_;
my $command = $daemon; my $command = join( ' ', $daemon, @args );
$command .= ' '.join( ' ', ( @args ) ) if ( @args );
my $process = $cmd_hash{$command}; my $process = $cmd_hash{$command};
if ( !$process ) { if ( !$process ) {
cPrint( "unknown\n" ); cPrint( "unknown\n" );
@ -662,7 +674,7 @@ sub check {
cPrint( "pending\n" ); cPrint( "pending\n" );
} else { } else {
my $cpid = $process->{pid}; my $cpid = $process->{pid};
if ( !$pid_hash{$cpid} ) { if ( ! $pid_hash{$cpid} ) {
cPrint( "stopped\n" ); cPrint( "stopped\n" );
} else { } else {
cPrint( "running\n" ); cPrint( "running\n" );
@ -675,28 +687,27 @@ sub status {
my @args = @_; my @args = @_;
if ( defined($daemon) ) { if ( defined($daemon) ) {
my $command = $daemon; my $command = join( ' ', $daemon, @args );
$command .= ' '.join( ' ', ( @args ) ) if ( @args );
my $process = $cmd_hash{$command}; my $process = $cmd_hash{$command};
if ( !$process ) { if ( ! $process ) {
dPrint( ZoneMinder::Logger::DEBUG, "'$command' not running\n" ); dPrint( ZoneMinder::Logger::DEBUG, "'$command' not running\n" );
return(); return();
} }
if ( $process->{pending} ) { if ( $process->{pending} ) {
dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at " dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at "
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending}) ) .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending} ) )
."\n" ."\n"
); );
} else { } else {
my $cpid = $process->{pid}; my $cpid = $process->{pid};
if ( !$pid_hash{$cpid} ) { if ( ! $pid_hash{$cpid} ) {
dPrint( ZoneMinder::Logger::DEBUG, "'$command' not running\n" ); dPrint( ZoneMinder::Logger::DEBUG, "'$command' not running\n" );
return(); return();
} }
} }
dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' running since " dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' running since "
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ) .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started} ) )
.", pid = $process->{pid}" .", pid = $process->{pid}"
); );
} else { } else {
@ -712,11 +723,11 @@ sub status {
foreach my $process ( values( %cmd_hash ) ) { foreach my $process ( values( %cmd_hash ) ) {
if ( $process->{pending} ) { if ( $process->{pending} ) {
dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at " dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at "
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending}) ) .strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending} ) )
."\n" ."\n"
); );
} }
} } # end foreach process
} }
} }