From 7c1f2a2791ff62851d425e34d830882fe20a8b70 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 23 Jun 2017 10:13:08 -0400 Subject: [PATCH 01/32] fix level=>effectiveLevel --- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index ee1022263..44c7f7e8e 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -375,8 +375,8 @@ sub level { $this->{effectiveLevel} = $this->{termLevel} if ( $this->{termLevel} > $this->{effectiveLevel} ); $this->{effectiveLevel} = $this->{databaseLevel} if ( $this->{databaseLevel} > $this->{effectiveLevel} ); $this->{effectiveLevel} = $this->{fileLevel} if ( $this->{fileLevel} > $this->{effectiveLevel} ); - $this->{effectiveLevel} = $this->{syslogLevel} if ( $this->{syslogLevel} > $this->{level} ); - $this->{effectiveLevel} = $this->{level} if ( $this->{effectiveLevel} > $this->{level} ); + $this->{effectiveLevel} = $this->{syslogLevel} if ( $this->{syslogLevel} > $this->{effectiveLevel} ); + $this->{effectiveLevel} = $this->{level} if ( $this->{effectiveLevel} > $this->{effectiveLevel} ); } return( $this->{level} ); } From 2eb3c8ef6d2ffaa08575976cd4daedad0333209a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 31 May 2018 10:24:54 -0400 Subject: [PATCH 02/32] use a stored prepared sth instead of re-preparing it --- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index a455bf71c..aec308b65 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -544,8 +544,9 @@ sub logPrint { if ( $level <= $this->{databaseLevel} ) { if ( ( $this->{dbh} and $this->{dbh}->ping() ) or ( $this->{dbh} = ZoneMinder::Database::zmDbConnect() ) ) { + my $sql = 'INSERT INTO Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) VALUES ( ?, ?, ?, ?, ?, ?, ?, NULL )'; - $this->{sth} = $this->{dbh}->prepare_cached($sql); + $this->{sth} = $this->{dbh}->prepare_cached($sql) if ! $this->{sth}; if ( !$this->{sth} ) { $this->{databaseLevel} = NOLOG; Error("Can't prepare log entry '$sql': ".$this->{dbh}->errstr()); From 21e26c8c14fd72c855cfb164981621086be8aaa8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 31 May 2018 10:25:16 -0400 Subject: [PATCH 03/32] Spacing and parenthesis and some debug lines --- scripts/zmdc.pl.in | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index 3ddf07e15..fee01658f 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -119,13 +119,13 @@ if ( $command eq 'version' ) { } my $needs_daemon = $command !~ /(?:startup|shutdown|status|check|logrot|version)/; my $daemon = shift @ARGV; -if ( $needs_daemon && ! $daemon ) { +if ( $needs_daemon && !$daemon ) { print(STDERR "No daemon given\n"); pod2usage(-exitstatus => -1); } my @args; -my $daemon_patt = '('.join( '|', @daemons ).')'; +my $daemon_patt = '('.join('|', @daemons).')'; if ( $needs_daemon ) { if ( $daemon =~ /^${daemon_patt}$/ ) { $daemon = $1; @@ -139,7 +139,7 @@ foreach my $arg ( @ARGV ) { # Detaint arguments, if they look ok #if ( $arg =~ /^(-{0,2}[\w]+)/ ) if ( $arg =~ /^(-{0,2}[\w\/?&=.-]+)$/ ) { - push( @args, $1 ); + push @args, $1; } else { print(STDERR "Bogus argument '$arg' found"); exit(-1); @@ -306,7 +306,7 @@ sub run { $dbh = zmDbConnect(); } my @cpuload = CpuLoad(); - Debug("UPdating Server record @cpuload"); + Debug("Updating Server record @cpuload"); if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,CpuLoad=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef, 'Running', $cpuload[0], &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) { Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr()); @@ -382,7 +382,7 @@ Debug("check_for_processes_to_kill"); ."\n" ); if ( $Config{ZM_SERVER_ID} ) { - $dbh = zmDbConnect() if ! $dbh->ping(); + $dbh = zmDbConnect() if ! ($dbh and $dbh->ping()); if ( ! defined $dbh->do(q{UPDATE Servers SET Status='NotRunning' WHERE Id=?}, undef, $Config{ZM_SERVER_ID}) ) { Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr()); } @@ -399,7 +399,9 @@ sub cPrint { # I think the purpose of this is to echo the logs to the client process so it can then display them. sub dPrint { my $logLevel = shift; + # One thought here, if no client exists to read these... does it block? if ( fileno(CLIENT) ) { + Debug("Have fileno for CLIENT, printing "); print CLIENT @_ } if ( $logLevel == ZoneMinder::Logger::DEBUG ) { @@ -439,8 +441,10 @@ sub start { sigprocmask(SIG_BLOCK, $blockset, $sigset) or Fatal("Can't block SIGCHLD: $!"); Debug("forking"); if ( my $cpid = fork() ) { + Debug("before logReinit"); # This logReinit is required. Not sure why. logReinit(); + Debug("aftere logReinit"); $process->{pid} = $cpid; $process->{started} = time(); @@ -808,7 +812,7 @@ sub status { foreach my $process ( values %cmd_hash ) { if ( $process->{pending} ) { 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" ); } From 405b1f92edb2479266b690b38758160dbcc01fab Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 31 May 2018 10:25:53 -0400 Subject: [PATCH 04/32] add a .fail to log the errors given when a navbar ajax call fails --- web/skins/classic/js/skin.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index 7f960cc90..5da53d0d2 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -192,7 +192,13 @@ if ( currentView != 'none' ) { }); function getNavBar() { - $j.getJSON(thisUrl + '?view=request&request=status&entity=navBar', setNavBar); + $j.getJSON(thisUrl + '?view=request&request=status&entity=navBar') + .done(setNavBar) + .fail(function( jqxhr, textStatus, error ) { + var err = textStatus + ", " + error; + console.log( "Request Failed: " + err ); + window.location.href = thisUrl; + }); } function setNavBar(data) { From 00ace16b618582cee85176b8febd1f1fe4d76e83 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 31 May 2018 13:54:33 -0500 Subject: [PATCH 05/32] bump zoneminder rpm specfile --- distros/redhat/zoneminder.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index c52ccbad9..efe4a88e2 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -26,7 +26,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.31.43 +Version: 1.31.44 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons From 8559dce350480e59dad6979181d4ab2f8ec67e06 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 1 Jun 2018 08:51:53 -0500 Subject: [PATCH 06/32] rpm readme - mention changes to apache config file --- distros/redhat/readme/README.Fedora | 5 +++++ distros/redhat/readme/README.Redhat7 | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/distros/redhat/readme/README.Fedora b/distros/redhat/readme/README.Fedora index d0ccf8c4e..3366c31a6 100644 --- a/distros/redhat/readme/README.Fedora +++ b/distros/redhat/readme/README.Fedora @@ -3,6 +3,11 @@ What's New 1. See the ZoneMinder release notes for a list of new features: https://github.com/ZoneMinder/zoneminder/releases + +2. The contents of the ZoneMinder Apache config file have changed. In + addition, this ZoneMinder package now requires you to manually symlink the + ZoneMinder Apache config file. See new install step 6 and upgrade step 3 + below for details. New installs ============ diff --git a/distros/redhat/readme/README.Redhat7 b/distros/redhat/readme/README.Redhat7 index b70e7768d..d8d1b4bde 100644 --- a/distros/redhat/readme/README.Redhat7 +++ b/distros/redhat/readme/README.Redhat7 @@ -4,6 +4,11 @@ What's New 1. See the ZoneMinder release notes for a list of new features: https://github.com/ZoneMinder/zoneminder/releases +2. The contents of the ZoneMinder Apache config file have changed. In + addition, this ZoneMinder package now requires you to manually symlink the + ZoneMinder Apache config file. See new install step 6 and upgrade step 3 + below for details. + New installs ============ From 316dbb5eb8ee600f1941026ca2966b8902cdc443 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 1 Jun 2018 11:27:35 -0400 Subject: [PATCH 07/32] Implement a RecursiveMutex class which is an explicit Recursive Mutex. Change the db mutex to a recursive Mutex --- src/zm_db.cpp | 6 +++--- src/zm_db.h | 2 +- src/zm_thread.cpp | 9 +++++++++ src/zm_thread.h | 41 ++++++++++++++++++++++++----------------- 4 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/zm_db.cpp b/src/zm_db.cpp index d4a927f3b..806ef8e5c 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -24,7 +24,7 @@ #include "zm_db.h" MYSQL dbconn; -Mutex db_mutex; +RecursiveMutex db_mutex; bool zmDbConnected = false; @@ -91,15 +91,15 @@ void zmDbClose() { } MYSQL_RES * zmDbFetch(const char * query) { - if ( ! zmDbConnected ) { + if ( !zmDbConnected ) { Error("Not connected."); return NULL; } db_mutex.lock(); if ( mysql_query(&dbconn, query) ) { - Error("Can't run query: %s", mysql_error(&dbconn)); db_mutex.unlock(); + Error("Can't run query: %s", mysql_error(&dbconn)); return NULL; } Debug(4, "Success running query: %s", query); diff --git a/src/zm_db.h b/src/zm_db.h index de47a6108..c707ad2b7 100644 --- a/src/zm_db.h +++ b/src/zm_db.h @@ -41,7 +41,7 @@ class zmDbRow { }; extern MYSQL dbconn; -extern Mutex db_mutex; +extern RecursiveMutex db_mutex; bool zmDbConnect(); void zmDbClose(); diff --git a/src/zm_thread.cpp b/src/zm_thread.cpp index 8bb854e26..03d048bea 100644 --- a/src/zm_thread.cpp +++ b/src/zm_thread.cpp @@ -95,6 +95,15 @@ bool Mutex::locked() { return( state == EBUSY ); } +RecursiveMutex::RecursiveMutex() { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + + if ( pthread_mutex_init(&mMutex, &attr) < 0 ) + Error("Unable to create pthread mutex: %s", strerror(errno)); +} + Condition::Condition( Mutex &mutex ) : mMutex( mutex ) { if ( pthread_cond_init( &mCondition, NULL ) < 0 ) throw ThreadException( stringtf( "Unable to create pthread condition: %s", strerror(errno) ) ); diff --git a/src/zm_thread.h b/src/zm_thread.h index e1facc6a5..0c41a93a5 100644 --- a/src/zm_thread.h +++ b/src/zm_thread.h @@ -59,27 +59,34 @@ public: }; class Mutex { -friend class Condition; + friend class Condition; -private: - pthread_mutex_t mMutex; + private: + pthread_mutex_t mMutex; -public: - Mutex(); - ~Mutex(); + public: + Mutex(); + ~Mutex(); -private: - pthread_mutex_t *getMutex() { - return( &mMutex ); - } + private: + pthread_mutex_t *getMutex() { + return &mMutex; + } -public: - int trylock(); - void lock(); - void lock( int secs ); - void lock( double secs ); - void unlock(); - bool locked(); + public: + int trylock(); + void lock(); + void lock( int secs ); + void lock( double secs ); + void unlock(); + bool locked(); +}; + +class RecursiveMutex : public Mutex { + private: + pthread_mutex_t mMutex; + public: + RecursiveMutex(); }; class ScopedMutex { From 87d9fc447ec0dffb5265aa222c194d27c70c4880 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 1 Jun 2018 11:27:53 -0400 Subject: [PATCH 08/32] google code style --- src/zms.cpp | 49 ++++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/src/zms.cpp b/src/zms.cpp index e8d20f72f..c785485da 100644 --- a/src/zms.cpp +++ b/src/zms.cpp @@ -74,45 +74,44 @@ int main( int argc, const char *argv[] ) { unsigned int playback_buffer = 0; bool nph = false; - const char *basename = strrchr( argv[0], '/' ); - if (basename) //if we found a / lets skip past it + const char *basename = strrchr(argv[0], '/'); + if ( basename ) //if we found a / lets skip past it basename++; else //argv[0] will not always contain the full path, but rather just the script name basename = argv[0]; const char *nph_prefix = "nph-"; - if ( basename && !strncmp( basename, nph_prefix, strlen(nph_prefix) ) ) { + if ( basename && !strncmp(basename, nph_prefix, strlen(nph_prefix)) ) { nph = true; } zmLoadConfig(); - - const char *query = getenv( "QUERY_STRING" ); + const char *query = getenv("QUERY_STRING"); if ( query ) { - Debug( 1, "Query: %s", query ); + Debug(1, "Query: %s", query); char temp_query[1024]; - strncpy( temp_query, query, sizeof(temp_query) ); + strncpy(temp_query, query, sizeof(temp_query)); char *q_ptr = temp_query; char *parms[16]; // Shouldn't be more than this int parm_no = 0; - while( (parm_no < 16) && (parms[parm_no] = strtok( q_ptr, "&" )) ) { + while( (parm_no < 16) && (parms[parm_no] = strtok(q_ptr, "&")) ) { parm_no++; q_ptr = NULL; } for ( int p = 0; p < parm_no; p++ ) { - char *name = strtok( parms[p], "=" ); - char *value = strtok( NULL, "=" ); + char *name = strtok(parms[p], "="); + char *value = strtok(NULL, "="); if ( !value ) value = (char *)""; - if ( !strcmp( name, "source" ) ) { - source = !strcmp( value, "event" )?ZMS_EVENT:ZMS_MONITOR; - } else if ( !strcmp( name, "mode" ) ) { - mode = !strcmp( value, "jpeg" )?ZMS_JPEG:ZMS_MPEG; - mode = !strcmp( value, "raw" )?ZMS_RAW:mode; - mode = !strcmp( value, "zip" )?ZMS_ZIP:mode; - mode = !strcmp( value, "single" )?ZMS_SINGLE:mode; + if ( !strcmp(name, "source") ) { + source = !strcmp(value, "event")?ZMS_EVENT:ZMS_MONITOR; + } else if ( !strcmp(name, "mode") ) { + mode = !strcmp(value, "jpeg")?ZMS_JPEG:ZMS_MPEG; + mode = !strcmp(value, "raw")?ZMS_RAW:mode; + mode = !strcmp(value, "zip")?ZMS_ZIP:mode; + mode = !strcmp(value, "single")?ZMS_SINGLE:mode; } else if ( !strcmp( name, "format" ) ) { strncpy( format, value, sizeof(format) ); } else if ( !strcmp( name, "monitor" ) ) { @@ -182,32 +181,32 @@ int main( int argc, const char *argv[] ) { if ( config.opt_use_auth ) { User *user = 0; - if ( strcmp( config.auth_relay, "none" ) == 0 ) { + if ( strcmp(config.auth_relay, "none") == 0 ) { if ( username.length() ) { - user = zmLoadUser( username.c_str() ); + user = zmLoadUser(username.c_str()); } } else { //if ( strcmp( config.auth_relay, "hashed" ) == 0 ) { if ( *auth ) { - user = zmLoadAuthUser( auth, config.auth_hash_ips ); + user = zmLoadAuthUser(auth, config.auth_hash_ips); } } //else if ( strcmp( config.auth_relay, "plain" ) == 0 ) { if ( username.length() && password.length() ) { - user = zmLoadUser( username.c_str(), password.c_str() ); + user = zmLoadUser(username.c_str(), password.c_str()); } } } if ( !user ) { - Error( "Unable to authenticate user" ); + Error("Unable to authenticate user"); logTerm(); zmDbClose(); - return( -1 ); + return -1; } - ValidateAccess( user, monitor_id ); - } + ValidateAccess(user, monitor_id); + } // end if config.opt_use_auth hwcaps_detect(); zmSetDefaultTermHandler(); From 5d772f16f67656228df6c937236ff43128db4cd7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 1 Jun 2018 16:18:07 -0400 Subject: [PATCH 09/32] fix closing td --- web/skins/classic/views/options.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/options.php b/web/skins/classic/views/options.php index 0a70ed96a..31c1f57cb 100644 --- a/web/skins/classic/views/options.php +++ b/web/skins/classic/views/options.php @@ -279,7 +279,7 @@ foreach( array_map( 'basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Scheme()), $canEdit ) ?> Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Name()), $canEdit ) ?> - disk_used_space()) . ' of ' . human_filesize($Storage->disk_total_space()) ?> + disk_used_space()) . ' of ' . human_filesize($Storage->disk_total_space()) ?> disabled="disabled"/> From 627ee8aeb3fca36e7191bf59db55a4cb1148c659 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 4 Jun 2018 14:59:42 -0400 Subject: [PATCH 10/32] close syslog in order to not leak ram --- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index aec308b65..1f56c0a11 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -474,7 +474,7 @@ sub openSyslog { sub closeSyslog { my $this = shift; -#closelog(); + closelog(); } sub logFile { From a25f5f1b123c561acdf6880fc760902ed9a7bf31 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Tue, 5 Jun 2018 09:43:40 -0500 Subject: [PATCH 11/32] don't call Debug after select This line was causing havoc when starting up zoneminder. --- scripts/zmdc.pl.in | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index fee01658f..b65388892 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -315,7 +315,6 @@ sub run { $secs_count += 1; } my $nfound = select(my $rout = $rin, undef, undef, $timeout); -Debug("Aftere select $nfound"); if ( $nfound > 0 ) { if ( vec($rout, fileno(SERVER), 1) ) { my $paddr = accept(CLIENT, SERVER); From c30992be3f90acbb919d389b7618e6b1e3fcedf9 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Wed, 6 Jun 2018 08:15:01 -0500 Subject: [PATCH 12/32] fixes #2105 A more simplified approach to fixing #2105, compared to previous attempts. --- web/includes/Filter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/Filter.php b/web/includes/Filter.php index de51b9876..721302edb 100644 --- a/web/includes/Filter.php +++ b/web/includes/Filter.php @@ -20,7 +20,7 @@ public $defaults = array( 'limit' => 100, 'Query' => array(), 'sort_field' => ZM_WEB_EVENT_SORT_FIELD, - 'sort_asc' => ZM_WEB_EVENT_SORT_ORDER == 'asc' ? 'asc' : 'desc', + 'sort_asc' => ZM_WEB_EVENT_SORT_ORDER, ); public function __construct( $IdOrRow=NULL ) { From 798d046d815405c80134c654c84c2ea50bc54426 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 6 Jun 2018 11:39:41 -0400 Subject: [PATCH 13/32] Remove some debugging lines --- web/ajax/stream.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/web/ajax/stream.php b/web/ajax/stream.php index 1c2fb3d62..44aaec8e6 100644 --- a/web/ajax/stream.php +++ b/web/ajax/stream.php @@ -22,13 +22,9 @@ if ( sem_acquire($semaphore,1) !== false ) { if ( file_exists( $localSocketFile ) ) { Warning("sock file $localSocketFile already exists?! Is someone else talking to zms?"); // They could be. We can maybe have concurrent requests from a browser. - } else { - Logger::Debug("socket file does not exist, we should be good to connect."); } if ( ! socket_bind( $socket, $localSocketFile ) ) { - ajaxError( "socket_bind( $localSocketFile ) failed: ".socket_strerror(socket_last_error()) ); - } else { - Logger::Debug("Bound to $localSocketFile"); + ajaxError("socket_bind( $localSocketFile ) failed: ".socket_strerror(socket_last_error()) ); } switch ( $_REQUEST['command'] ) { @@ -81,7 +77,6 @@ if ( sem_acquire($semaphore,1) !== false ) { $eSockets = NULL; $timeout = MSG_TIMEOUT - ( time() - $start_time ); - Logger::Debug("TImeout is: $timeout/1000 seconds. " ); $numSockets = socket_select( $rSockets, $wSockets, $eSockets, intval($timeout/1000), ($timeout%1000)*1000 ); From b3c9f508f45c80c9b06f6b2f26824cf90c83c9ce Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 6 Jun 2018 11:40:12 -0400 Subject: [PATCH 14/32] Remove debugging line that is causing systemd to fail --- scripts/zmdc.pl.in | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index fee01658f..b65388892 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -315,7 +315,6 @@ sub run { $secs_count += 1; } my $nfound = select(my $rout = $rin, undef, undef, $timeout); -Debug("Aftere select $nfound"); if ( $nfound > 0 ) { if ( vec($rout, fileno(SERVER), 1) ) { my $paddr = accept(CLIENT, SERVER); From db6bd67f595edb6fe195ae7fc175ae2d726cfa59 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 6 Jun 2018 11:40:38 -0400 Subject: [PATCH 15/32] just fix structure/spacing --- web/skins/classic/includes/functions.php | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index e1808410a..3d7777ef1 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -373,18 +373,13 @@ function xhtmlFooter() { global $view; global $skin; global $running; -if ( canEdit('System') ) { - include("skins/$skin/views/state.php"); + if ( canEdit('System') ) { + include("skins/$skin/views/state.php"); + } ?> - - - + + From d961b7408406202d52f712f64434eadae427c3b1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 6 Jun 2018 11:41:00 -0400 Subject: [PATCH 16/32] spacing and double to single quotes --- web/skins/classic/views/video.php | 118 ++++++++++++++++-------------- 1 file changed, 62 insertions(+), 56 deletions(-) diff --git a/web/skins/classic/views/video.php b/web/skins/classic/views/video.php index 0c7c4e153..6a111fed3 100644 --- a/web/skins/classic/views/video.php +++ b/web/skins/classic/views/video.php @@ -18,8 +18,8 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // -if ( !canView( 'Events' ) ) { - $view = "error"; +if ( !canView('Events') ) { + $view = 'error'; return; } @@ -28,31 +28,31 @@ require_once('includes/Event.php'); $eid = validInt($_REQUEST['eid']); $sql = 'SELECT E.*,M.Name AS MonitorName,M.DefaultRate,M.DefaultScale FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE E.Id = ?'; -$sql_values = array( $eid ); +$sql_values = array($eid); if ( $user['MonitorIds'] ) { - $monitor_ids = explode( ',', $user['MonitorIds'] ); - $sql .= ' AND MonitorId IN (' .implode( ',', array_fill(0,count($monitor_ids),'?') ) . ')'; - $sql_values = array_merge( $sql_values, $monitor_ids ); + $monitor_ids = explode(',', $user['MonitorIds']); + $sql .= ' AND MonitorId IN ('.implode(',', array_fill(0,count($monitor_ids),'?')).')'; + $sql_values = array_merge($sql_values, $monitor_ids); } -$event = dbFetchOne( $sql, NULL, $sql_values ); +$event = dbFetchOne($sql, NULL, $sql_values); -if ( isset( $_REQUEST['rate'] ) ) +if ( isset($_REQUEST['rate']) ) $rate = validInt($_REQUEST['rate']); else - $rate = reScale( RATE_BASE, $event['DefaultRate'], ZM_WEB_DEFAULT_RATE ); -if ( isset( $_REQUEST['scale'] ) ) + $rate = reScale(RATE_BASE, $event['DefaultRate'], ZM_WEB_DEFAULT_RATE); +if ( isset($_REQUEST['scale']) ) $scale = validInt($_REQUEST['scale']); else - $scale = reScale( SCALE_BASE, $event['DefaultScale'], ZM_WEB_DEFAULT_SCALE ); + $scale = reScale(SCALE_BASE, $event['DefaultScale'], ZM_WEB_DEFAULT_SCALE); -$Event = new Event( $event['Id'] ); +$Event = new Event($event['Id']); $eventPath = $Event->Path(); $videoFormats = array(); -$ffmpegFormats = preg_split( '/\s+/', ZM_FFMPEG_FORMATS ); +$ffmpegFormats = preg_split('/\s+/', ZM_FFMPEG_FORMATS); foreach ( $ffmpegFormats as $ffmpegFormat ) { - if ( preg_match( '/^([^*]+)(\*\*?)$/', $ffmpegFormat, $matches ) ) { + if ( preg_match('/^([^*]+)(\*\*?)$/', $ffmpegFormat, $matches) ) { $videoFormats[$matches[1]] = $matches[1]; if ( !isset($videoFormat) && $matches[2] == '*' ) { $videoFormat = $matches[1]; @@ -63,42 +63,42 @@ foreach ( $ffmpegFormats as $ffmpegFormat ) { } $videoFiles = array(); -if ( $dir = opendir( $eventPath ) ) { - while ( ($file = readdir( $dir )) !== false ) { +if ( $dir = opendir($eventPath) ) { + while ( ($file = readdir($dir)) !== false ) { $file = $eventPath.'/'.$file; - if ( is_file( $file ) ) { - if ( preg_match( '/\.(?:'.join( '|', $videoFormats ).')$/', $file ) ) { + if ( is_file($file) ) { + if ( preg_match('/\.(?:'.join('|', $videoFormats).')$/', $file) ) { $videoFiles[] = $file; } } } - closedir( $dir ); + closedir($dir); } if ( isset($_REQUEST['deleteIndex']) ) { $deleteIndex = validInt($_REQUEST['deleteIndex']); - unlink( $videoFiles[$deleteIndex] ); - unset( $videoFiles[$deleteIndex] ); + unlink($videoFiles[$deleteIndex]); + unset($videoFiles[$deleteIndex]); } if ( isset($_REQUEST['downloadIndex']) ) { $downloadIndex = validInt($_REQUEST['downloadIndex']); - header( 'Pragma: public' ); - header( 'Expires: 0' ); - header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' ); - header( 'Cache-Control: private', false ); // required by certain browsers - header( 'Content-Description: File Transfer' ); - header( 'Content-disposition: attachment; filename="'.basename($videoFiles[$downloadIndex]).'"' ); // basename is required because the video index contains the path and firefox doesn't strip the path but simply replaces the slashes with an underscore. - header( 'Content-Transfer-Encoding: binary' ); - header( 'Content-Type: application/force-download' ); - header( 'Content-Length: '.filesize($videoFiles[$downloadIndex]) ); - readfile( $videoFiles[$downloadIndex] ); + header('Pragma: public'); + header('Expires: 0'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Cache-Control: private', false); // required by certain browsers + header('Content-Description: File Transfer'); + header('Content-disposition: attachment; filename="'.basename($videoFiles[$downloadIndex]).'"'); // basename is required because the video index contains the path and firefox doesn't strip the path but simply replaces the slashes with an underscore. + header('Content-Transfer-Encoding: binary'); + header('Content-Type: application/force-download'); + header('Content-Length: '.filesize($videoFiles[$downloadIndex])); + readfile($videoFiles[$downloadIndex]); exit; } $focusWindow = true; -xhtmlHeaders(__FILE__, translate('Video') ); +xhtmlHeaders(__FILE__, translate('Video')); ?>
@@ -112,30 +112,30 @@ xhtmlHeaders(__FILE__, translate('Video') ); -

-
+

+
- +
- + - + - + @@ -143,16 +143,22 @@ if ( isset($_REQUEST['showIndex']) ) {
- disabled="disabled"/> + disabled="disabled"/>
-

+

+ + +

- + @@ -164,7 +170,7 @@ if ( isset($_REQUEST['showIndex']) ) { - +
@@ -178,29 +184,29 @@ if ( isset($_REQUEST['showIndex']) ) { 0 ) { - preg_match( '/^(.+)-((?:r[_\d]+)|(?:F[_\d]+))-((?:s[_\d]+)|(?:S[0-9a-z]+))\.([^.]+)$/', $file, $matches ); - if ( preg_match( '/^r(.+)$/', $matches[2], $temp_matches ) ) { + if ( filesize($file) > 0 ) { + preg_match('/^(.+)-((?:r[_\d]+)|(?:F[_\d]+))-((?:s[_\d]+)|(?:S[0-9a-z]+))\.([^.]+)$/', $file, $matches); + if ( preg_match('/^r(.+)$/', $matches[2], $temp_matches) ) { $rate = (int)(100 * preg_replace( '/_/', '.', $temp_matches[1] ) ); $rateText = isset($rates[$rate])?$rates[$rate]:($rate."x"); - } elseif ( preg_match( '/^F(.+)$/', $matches[2], $temp_matches ) ) { - $rateText = $temp_matches[1]."fps"; + } elseif ( preg_match('/^F(.+)$/', $matches[2], $temp_matches) ) { + $rateText = $temp_matches[1].'fps'; } - if ( preg_match( '/^s(.+)$/', $matches[3], $temp_matches ) ) { - $scale = (int)(100 * preg_replace( '/_/', '.', $temp_matches[1] ) ); - $scaleText = isset($scales[$scale])?$scales[$scale]:($scale."x"); - } elseif ( preg_match( '/^S(.+)$/', $matches[3], $temp_matches ) ) { + if ( preg_match('/^s(.+)$/', $matches[3], $temp_matches) ) { + $scale = (int)(100 * preg_replace('/_/', '.', $temp_matches[1]) ); + $scaleText = isset($scales[$scale])?$scales[$scale]:($scale.'x'); + } elseif ( preg_match('/^S(.+)$/', $matches[3], $temp_matches) ) { $scaleText = $temp_matches[1]; } - $width = $scale?reScale( $event['Width'], $scale ):$event['Width']; - $height = $scale?reScale( $event['Height'], $scale ):$event['Height']; + $width = $scale?reScale($event['Width'], $scale):$event['Width']; + $height = $scale?reScale($event['Height'], $scale):$event['Height']; ?> - + - + Date: Wed, 6 Jun 2018 11:41:28 -0400 Subject: [PATCH 17/32] WHen we are storing jpgs we don't generate a snapshot, so handle that --- web/views/image.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/web/views/image.php b/web/views/image.php index 2da92899b..26c58f4f7 100644 --- a/web/views/image.php +++ b/web/views/image.php @@ -32,7 +32,7 @@ // If both scale and either width or height are specified, scale is ignored // -if ( !canView( 'Events' ) ) { +if ( !canView('Events') ) { $view = 'error'; return; } @@ -85,7 +85,13 @@ if ( empty($_REQUEST['path']) ) { $Frame->Delta(1); $Frame->FrameId('snapshot'); } - $path = $Event->Path().'/snapshot.jpg'; + $Monitor = $Event->Monitor(); + if ( $Monitor->SaveJPEGs() & 1 ) { + # If we store Frames as jpgs, then we don't store a snapshot + $path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d',$Frame->FrameId()).'-'.$show.'.jpg'; + } else { + $path = $Event->Path().'/snapshot.jpg'; + } } else { $Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'FrameId'=>$_REQUEST['fid'])); From 3109536dda9e753fab781dff62b44b82b1c5e7b6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 6 Jun 2018 11:55:51 -0400 Subject: [PATCH 18/32] Alternate fix for video generation under csrf. Now we just turn off output buffering (discarding contents before sending the avi --- web/index.php | 2 +- web/skins/classic/views/video.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/web/index.php b/web/index.php index d93b46e23..4cc7cf75c 100644 --- a/web/index.php +++ b/web/index.php @@ -200,7 +200,7 @@ isset($view) || $view = NULL; isset($request) || $request = NULL; isset($action) || $action = NULL; -if ( ZM_ENABLE_CSRF_MAGIC && $action != 'login' && $view != 'view_video' && $view != 'video' && $request != 'control' && $view != 'frames' && $view != 'archive' ) { +if ( ZM_ENABLE_CSRF_MAGIC && $action != 'login' && $view != 'view_video' && $request != 'control' && $view != 'frames' && $view != 'archive' ) { require_once( 'includes/csrf/csrf-magic.php' ); #Logger::Debug("Calling csrf_check with the following values: \$request = \"$request\", \$view = \"$view\", \$action = \"$action\""); csrf_check(); diff --git a/web/skins/classic/views/video.php b/web/skins/classic/views/video.php index 6a111fed3..2a6a41424 100644 --- a/web/skins/classic/views/video.php +++ b/web/skins/classic/views/video.php @@ -82,6 +82,8 @@ if ( isset($_REQUEST['deleteIndex']) ) { } if ( isset($_REQUEST['downloadIndex']) ) { + // can't be output buffering, as this file might be large + ob_end_clean(); $downloadIndex = validInt($_REQUEST['downloadIndex']); header('Pragma: public'); header('Expires: 0'); From cd646197437de2bb85476f81a3c64282734b9012 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 6 Jun 2018 12:56:33 -0400 Subject: [PATCH 19/32] Fix controlling daemon when the monitor is Local --- web/api/app/Controller/MonitorsController.php | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/web/api/app/Controller/MonitorsController.php b/web/api/app/Controller/MonitorsController.php index 660bee5ce..5801c1e9e 100644 --- a/web/api/app/Controller/MonitorsController.php +++ b/web/api/app/Controller/MonitorsController.php @@ -332,25 +332,18 @@ class MonitorsController extends AppController { } public function daemonControl($id, $command, $monitor=null, $daemon=null) { - $args = ''; $daemons = array(); - if (!$monitor) { + if ( !$monitor ) { // Need to see if it is local or remote $monitor = $this->Monitor->find('first', array( - 'fields' => array('Type', 'Function'), + 'fields' => array('Type', 'Function', 'Device'), 'conditions' => array('Id' => $id) )); $monitor = $monitor['Monitor']; } - if ($monitor['Type'] == 'Local') { - $args = '-d ' . $monitor['Device']; - } else { - $args = '-m ' . $id; - } - - if ($monitor['Function'] == 'Monitor') { + if ( $monitor['Function'] == 'Monitor' ) { array_push($daemons, 'zmc'); } else { array_push($daemons, 'zmc', 'zma'); @@ -359,6 +352,13 @@ class MonitorsController extends AppController { $zm_path_bin = Configure::read('ZM_PATH_BIN'); foreach ($daemons as $daemon) { + $args = ''; + if ( $daemon == 'zmc' and $monitor['Type'] == 'Local') { + $args = '-d ' . $monitor['Device']; + } else { + $args = '-m ' . $id; + } + $shellcmd = escapeshellcmd("$zm_path_bin/zmdc.pl $command $daemon $args"); $status = exec( $shellcmd ); } From 9050ffaf92b89ed98dda5ddd5c8cf052213e545d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 6 Jun 2018 12:57:35 -0400 Subject: [PATCH 20/32] spacing, remove some debug lines --- web/includes/actions.php | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/web/includes/actions.php b/web/includes/actions.php index 8549d3978..54402da7c 100644 --- a/web/includes/actions.php +++ b/web/includes/actions.php @@ -476,15 +476,12 @@ if ( canEdit( 'Monitors' ) ) { ); if ( $_REQUEST['newMonitor']['ServerId'] == 'auto' ) { - Logger::Debug("Auto selecting server"); $_REQUEST['newMonitor']['ServerId'] = dbFetchOne('SELECT Id FROM Servers WHERE Status=\'Running\' ORDER BY FreeMem DESC, CpuLoad ASC LIMIT 1', 'Id'); Logger::Debug("Auto selecting server: Got " . $_REQUEST['newMonitor']['ServerId'] ); if ( ( ! $_REQUEST['newMonitor'] ) and defined('ZM_SERVER_ID') ) { $_REQUEST['newMonitor']['ServerId'] = ZM_SERVER_ID; Logger::Debug("Auto selecting server to " . ZM_SERVER_ID); } - } else { - Logger::Debug("NOT Auto selecting server" . $_REQUEST['newMonitor']['ServerId']); } $columns = getTableColumns('Monitors'); @@ -571,22 +568,23 @@ if ( canEdit( 'Monitors' ) ) { $restart = true; } # end if count(changes) - if ( - ( !isset($_POST['newMonitor']['GroupIds']) ) - or - ( count($_POST['newMonitor']['GroupIds']) != count($Monitor->GroupIds()) ) - or - array_diff($_POST['newMonitor']['GroupIds'], $Monitor->GroupIds()) - ) { - if ( $Monitor->Id() ) - dbQuery('DELETE FROM Groups_Monitors WHERE MonitorId=?', array($mid)); - if ( isset($_POST['newMonitor']['GroupIds']) ) { - foreach ( $_POST['newMonitor']['GroupIds'] as $group_id ) { - dbQuery('INSERT INTO Groups_Monitors (GroupId,MonitorId) VALUES (?,?)', array($group_id, $mid)); - } + if ( + ( !isset($_POST['newMonitor']['GroupIds']) ) + or + ( count($_POST['newMonitor']['GroupIds']) != count($Monitor->GroupIds()) ) + or + array_diff($_POST['newMonitor']['GroupIds'], $Monitor->GroupIds()) + ) { + if ( $Monitor->Id() ) + dbQuery('DELETE FROM Groups_Monitors WHERE MonitorId=?', array($mid)); + + if ( isset($_POST['newMonitor']['GroupIds']) ) { + foreach ( $_POST['newMonitor']['GroupIds'] as $group_id ) { + dbQuery('INSERT INTO Groups_Monitors (GroupId,MonitorId) VALUES (?,?)', array($group_id, $mid)); } - } // end if there has been a change of groups + } + } // end if there has been a change of groups if ( ZM_OPT_X10 ) { $x10Changes = getFormChanges( $x10Monitor, $_REQUEST['newX10Monitor'] ); From 0937bfdf846ac67b4007a625710116a5e27b8461 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 6 Jun 2018 13:37:12 -0400 Subject: [PATCH 21/32] consoleTableBody needs to be an id in order for dragndrop sorting to work --- web/skins/classic/views/console.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 119a223eb..c5a9f54f1 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -223,7 +223,7 @@ ob_start(); - + Date: Wed, 6 Jun 2018 14:05:58 -0400 Subject: [PATCH 22/32] add a --daemon command line option to zmfilter.pl to tell it to run as a daemon even when --filter_id is specified. Use this command line option in zmpkg.pl to make zmfilter.pl's stick around. This reduces the impact of the memork leak in zmdc.pl --- scripts/zmfilter.pl.in | 4 +- scripts/zmpkg.pl.in | 324 ++++++++++++++++++++--------------------- 2 files changed, 165 insertions(+), 163 deletions(-) diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index fa59d91e0..095d2764e 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -70,12 +70,14 @@ use Getopt::Long; use autouse 'Pod::Usage'=>qw(pod2usage); use autouse 'Data::Dumper'=>qw(Dumper); +my $daemon = 0; my $filter_name = ''; my $filter_id; my $version = 0; my $zm_terminate = 0; GetOptions( + 'daemon' =>\$daemon, 'filter=s' =>\$filter_name, 'filter_id=s' =>\$filter_id, 'version' =>\$version @@ -201,7 +203,7 @@ while( !$zm_terminate ) { } } - last if $filter_name or $filter_id or $zm_terminate; + last if (!$daemon and ($filter_name or $filter_id)) or $zm_terminate; Debug("Sleeping for $delay seconds\n"); sleep($delay); diff --git a/scripts/zmpkg.pl.in b/scripts/zmpkg.pl.in index 62771c7aa..e146f76c8 100644 --- a/scripts/zmpkg.pl.in +++ b/scripts/zmpkg.pl.in @@ -41,9 +41,10 @@ use autouse 'Pod::Usage'=>qw(pod2usage); $ENV{PATH} = '/bin:/usr/bin:/usr/local/bin'; $ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL}; delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; -my $store_state=""; # PP - will remember state name passed +my $store_state=''; # PP - will remember state name passed logInit(); +Info("Aftere LogInit"); my $command = $ARGV[0]||''; if ( $command eq 'version' ) { @@ -53,28 +54,27 @@ if ( $command eq 'version' ) { my $state; -my $dbh; - +my $dbh = zmDbConnect(); +Info("Command: $command"); if ( !$command || $command !~ /^(?:start|stop|restart|status|logrot|version)$/ ) { if ( $command ) { - $dbh = zmDbConnect(); # Check to see if it's a valid run state my $sql = 'SELECT * FROM States WHERE Name=?'; - my $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $command ) - or Fatal( "Can't execute: ".$sth->errstr() ); + my $sth = $dbh->prepare_cached($sql) + or Fatal("Can't prepare '$sql': ".$dbh->errstr()); + my $res = $sth->execute($command) + or Fatal("Can't execute: ".$sth->errstr()); if ( $state = $sth->fetchrow_hashref() ) { - $state->{Name} = $command; + #$state->{Name} = $command; $state->{Definitions} = []; - foreach( split( /,/, $state->{Definition} ) ) { - my ( $id, $function, $enabled ) = split( /:/, $_ ); + foreach( split(',', $state->{Definition}) ) { + my ( $id, $function, $enabled ) = split(':', $_); push( @{$state->{Definitions}}, { Id=>$id, Function=>$function, Enabled=>$enabled } ); } - $store_state=$command; # PP - Remember the name that was passed to search in DB - $command = 'state'; + $store_state = $command; # PP - Remember the name that was passed to search in DB + $command = 'state'; } else { $command = undef; } @@ -82,64 +82,66 @@ if ( !$command || $command !~ /^(?:start|stop|restart|status|logrot|version)$/ ) if ( !$command ) { pod2usage(-exitstatus => -1); } -} -$dbh = zmDbConnect() if ! $dbh; +} # end if not one of the usual commands + # PP - Sane state check +Debug("StartisActiveSSantiyCheck"); isActiveSanityCheck(); +Debug("Done isActiveSSantiyCheck"); # Move to the right place -chdir( $Config{ZM_PATH_WEB} ) - or Fatal( "Can't chdir to '".$Config{ZM_PATH_WEB}."': $!" ); +chdir($Config{ZM_PATH_WEB}) + or Fatal("Can't chdir to '$Config{ZM_PATH_WEB}': $!"); - my $dbg_id = ''; +my $dbg_id = ''; - Info( "Command: $command\n" ); +Info("Command: $command"); - my $retval = 0; +my $retval = 0; - if ( $command eq 'state' ) { - Info( "Updating DB: $state->{Name}\n" ); - my $sql = $Config{ZM_SERVER_ID} ? 'SELECT * FROM Monitors WHERE ServerId=? ORDER BY Id ASC' : 'SELECT * FROM Monitors ORDER BY Id ASC'; - my $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID}: () ) - or Fatal( "Can't execute: ".$sth->errstr() ); - while( my $monitor = $sth->fetchrow_hashref() ) { - foreach my $definition ( @{$state->{Definitions}} ) { - if ( $monitor->{Id} =~ /^$definition->{Id}$/ ) { - $monitor->{NewFunction} = $definition->{Function}; - $monitor->{NewEnabled} = $definition->{Enabled}; - } - } -#next if ( !$monitor->{NewFunction} ); - $monitor->{NewFunction} = 'None' - if ( !$monitor->{NewFunction} ); - $monitor->{NewEnabled} = 0 - if ( !$monitor->{NewEnabled} ); - if ( $monitor->{Function} ne $monitor->{NewFunction} - || $monitor->{Enabled} ne $monitor->{NewEnabled} - ) { - my $sql = 'UPDATE Monitors SET Function=?, Enabled=? WHERE Id=?'; - my $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $monitor->{NewFunction}, $monitor->{NewEnabled}, $monitor->{Id} ) - or Fatal( "Can't execute: ".$sth->errstr() ); +if ( $command eq 'state' ) { + Info("Updating DB: $state->{Name}"); + my $sql = 'SELECT * FROM Monitors' . ($Config{ZM_SERVER_ID} ? ' WHERE ServerId=?' : '' ) .' ORDER BY Id ASC'; + my $sth = $dbh->prepare_cached($sql) + or Fatal("Can't prepare '$sql': ".$dbh->errstr()); + my $res = $sth->execute($Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID}: ()) + or Fatal("Can't execute: ".$sth->errstr()); + while( my $monitor = $sth->fetchrow_hashref() ) { + foreach my $definition ( @{$state->{Definitions}} ) { + if ( $monitor->{Id} =~ /^$definition->{Id}$/ ) { + $monitor->{NewFunction} = $definition->{Function}; + $monitor->{NewEnabled} = $definition->{Enabled}; } } - $sth->finish(); + #next if ( !$monitor->{NewFunction} ); + $monitor->{NewFunction} = 'None' + if ( !$monitor->{NewFunction} ); + $monitor->{NewEnabled} = 0 + if ( !$monitor->{NewEnabled} ); + if ( $monitor->{Function} ne $monitor->{NewFunction} + || $monitor->{Enabled} ne $monitor->{NewEnabled} + ) { + my $sql = 'UPDATE Monitors SET Function=?, Enabled=? WHERE Id=?'; + my $sth = $dbh->prepare_cached($sql) + or Fatal("Can't prepare '$sql': ".$dbh->errstr()); + my $res = $sth->execute($monitor->{NewFunction}, $monitor->{NewEnabled}, $monitor->{Id}) + or Fatal("Can't execute: ".$sth->errstr()); + } # end if change of function or enablement + } # end foreach monitor + $sth->finish(); -# PP - Now mark a specific state as active - resetStates(); - Info ("Marking $store_state as Enabled"); - $sql = "UPDATE States SET IsActive = '1' WHERE Name = ?"; - $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - $res = $sth->execute( $store_state ) - or Fatal( "Can't execute: ".$sth->errstr() ); + # PP - Now mark a specific state as active + resetStates(); + Info("Marking $store_state as Enabled"); + $sql = 'UPDATE States SET IsActive = 1 WHERE Name = ?'; + $sth = $dbh->prepare_cached($sql) + or Fatal("Can't prepare '$sql': ".$dbh->errstr()); + $res = $sth->execute($store_state) + or Fatal("Can't execute: ".$sth->errstr()); -# PP - zero out other states isActive - $command = 'restart'; - } + # PP - zero out other states isActive + $command = 'restart'; +} # end if command = state # Check if we are running systemd and if we have been called by the system if ( $command =~ /^(start|stop|restart)$/ ) { @@ -147,13 +149,27 @@ if ( $command =~ /^(start|stop|restart)$/ ) { $command = $1; if ( systemdRunning() && !calledBysystem() ) { - qx(@BINDIR@/zmsystemctl.pl $command); - $command = ''; + Info("Redirecting command through systemctl"); + my $path = qx(which systemctl); + Info("Path is $path"); + Info("Status is $?"); + my $status = $? >> 8; + Info("Status is $status"); + ( $path ) = $path =~ /^(.*)$/; + + if ( !$path || $status ) { + Fatal('Unable to determine systemctl executable. Is systemd in use?'); + } + Info("exec $path $command zoneminder"); + exec("$path $command zoneminder"); + } else { + Debug("called by SystemD"); } } if ( $command =~ /^(?:stop|restart)$/ ) { my $status = runCommand('zmdc.pl check'); + Debug("zmdc.pl check = $status"); if ( $status eq 'running' ) { runCommand('zmdc.pl shutdown'); @@ -163,20 +179,19 @@ if ( $command =~ /^(?:stop|restart)$/ ) { } } -#runCommand( "zmupdate.pl -f" ); - if ( $command =~ /^(?:start|restart)$/ ) { my $status = runCommand('zmdc.pl check'); + Debug("zmdc.pl check = $status"); if ( $status eq 'stopped' ) { if ( $Config{ZM_DYN_DB_VERSION} and ( $Config{ZM_DYN_DB_VERSION} ne ZM_VERSION ) ) { - Fatal( 'Version mismatch, system is version '.ZM_VERSION + Fatal('Version mismatch, system is version '.ZM_VERSION .', database is '.$Config{ZM_DYN_DB_VERSION} .', please run zmupdate.pl to update.' ); - exit( -1 ); + exit(-1); } # Recreate the temporary directory if it's been wiped @@ -196,8 +211,8 @@ if ( $command =~ /^(?:start|restart)$/ ) { my @values; if ( $Config{ZM_SERVER_ID} ) { require ZoneMinder::Server; - Info("Multi-server configuration detected. Starting up services for server $Config{ZM_SERVER_ID}\n"); - $Server = new ZoneMinder::Server( $Config{ZM_SERVER_ID} ); + Info("Multi-server configuration detected. Starting up services for server $Config{ZM_SERVER_ID}"); + $Server = new ZoneMinder::Server($Config{ZM_SERVER_ID}); $sql = 'SELECT * FROM Monitors WHERE ServerId=?'; @values = ( $Config{ZM_SERVER_ID} ); } else { @@ -206,46 +221,49 @@ if ( $command =~ /^(?:start|restart)$/ ) { } { - my $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( @values ) - or Fatal( "Can't execute: ".$sth->errstr() ); - while( my $monitor = $sth->fetchrow_hashref() ) { - if ( $monitor->{Function} ne 'None' && $monitor->{Type} ne 'WebSite' ) { - if ( $monitor->{Type} eq 'Local' ) { - runCommand( "zmdc.pl start zmc -d $monitor->{Device}" ); - } else { - runCommand( "zmdc.pl start zmc -m $monitor->{Id}" ); - } - if ( $monitor->{Function} ne 'Monitor' ) { - runCommand( "zmdc.pl start zma -m $monitor->{Id}" ); - } - if ( $Config{ZM_OPT_CONTROL} ) { - if ( $monitor->{Function} eq 'Modect' || $monitor->{Function} eq 'Mocord' ) { - if ( $monitor->{Controllable} && $monitor->{TrackMotion} ) { - runCommand( "zmdc.pl start zmtrack.pl -m $monitor->{Id}" ); - } + my $sth = $dbh->prepare_cached($sql) + or Fatal("Can't prepare '$sql': ".$dbh->errstr()); + my $res = $sth->execute(@values) + or Fatal("Can't execute: ".$sth->errstr()); + while( my $monitor = $sth->fetchrow_hashref() ) { + if ( $monitor->{Function} ne 'None' && $monitor->{Type} ne 'WebSite' ) { + if ( $monitor->{Type} eq 'Local' ) { + runCommand("zmdc.pl start zmc -d $monitor->{Device}"); + } else { + runCommand("zmdc.pl start zmc -m $monitor->{Id}"); } - } - } - } - $sth->finish(); + if ( $monitor->{Function} ne 'Monitor' ) { + runCommand("zmdc.pl start zma -m $monitor->{Id}"); + } + if ( $Config{ZM_OPT_CONTROL} ) { + if ( $monitor->{Controllable} && $monitor->{TrackMotion} ) { + if ( $monitor->{Function} eq 'Modect' || $monitor->{Function} eq 'Mocord' ) { + runCommand( "zmdc.pl start zmtrack.pl -m $monitor->{Id}" ); + } else { + Warning(' Monitor is set to track motion, but does not have motion detection enabled.'); + } # end if Has motion enabled + } # end if track motion + } # end if ZM_OPT_CONTROL + } # end if function is not none or Website + } # end foreach monitor + $sth->finish(); } + { - my $sql = 'SELECT Id FROM Filters WHERE Background=1'; - my $sth = $dbh->prepare_cached($sql) - or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute() - or Fatal( "Can't execute: ".$sth->errstr() ); - if ( $sth->rows ) { - while( my $filter = $sth->fetchrow_hashref() ) { -# This is now started unconditionally - runCommand("zmdc.pl start zmfilter.pl --filter_id=$$filter{Id}"); + my $sql = 'SELECT Id FROM Filters WHERE Background=1'; + my $sth = $dbh->prepare_cached($sql) + or Fatal("Can't prepare '$sql': ".$dbh->errstr()); + my $res = $sth->execute() + or Fatal("Can't execute: ".$sth->errstr()); + if ( $sth->rows ) { + while( my $filter = $sth->fetchrow_hashref() ) { + # This is now started unconditionally + runCommand("zmdc.pl start zmfilter.pl --filter_id=$$filter{Id} --daemon"); + } + } else { + runCommand('zmdc.pl start zmfilter.pl'); } - } else { - runCommand('zmdc.pl start zmfilter.pl'); - } - $sth->finish(); + $sth->finish(); } if ( $Config{ZM_RUN_AUDIT} ) { @@ -283,32 +301,32 @@ if ( $command =~ /^(?:start|restart)$/ ) { } else { $retval = 1; } -} +} # end if command is start or restart if ( $command eq 'status' ) { my $status = runCommand('zmdc.pl check'); - print( STDOUT $status."\n" ); + print(STDOUT $status."\n"); } elsif ( $command eq 'logrot' ) { runCommand('zmdc.pl logrot'); } -exit( $retval ); +exit($retval); # PP - Make sure isActive is on and only one sub isActiveSanityCheck { - Info ('Sanity checking States table...'); + Info('Sanity checking States table...'); $dbh = zmDbConnect() if ! $dbh; # PP - First, make sure default exists and there is only one - my $sql = "SELECT Name FROM States WHERE Name='default'"; - my $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $sql = q`SELECT Name FROM States WHERE Name='default'`; + my $sth = $dbh->prepare_cached($sql) + or Fatal("Can't prepare '$sql': ".$dbh->errstr()); my $res = $sth->execute() - or Fatal( "Can't execute: ".$sth->errstr() ); + or Fatal("Can't execute: ".$sth->errstr()); - if ($sth->rows != 1) { + if ( $sth->rows != 1 ) { # PP - no row, or too many rows. Either case is an error Info( 'Fixing States table - either no default state or duplicate default states' ); $sql = "DELETE FROM States WHERE Name='default'"; @@ -316,69 +334,53 @@ sub isActiveSanityCheck { or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() ); - $sql = "INSERT INTO States (Name,Definition,IsActive) VALUES ('default','','1');"; - $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + $sql = q`"INSERT INTO States (Name,Definition,IsActive) VALUES ('default','','1');`; + $sth = $dbh->prepare_cached($sql) + or Fatal("Can't prepare '$sql': ".$dbh->errstr()); $res = $sth->execute() - or Fatal( "Can't execute: ".$sth->errstr() ); + or Fatal("Can't execute: ".$sth->errstr()); } - # PP - Now make sure no two states have IsActive=1 - $sql = "SELECT Name FROM States WHERE IsActive = '1'"; - $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + $sql = 'SELECT Name FROM States WHERE IsActive = 1'; + $sth = $dbh->prepare_cached($sql) + or Fatal("Can't prepare '$sql': ".$dbh->errstr()); $res = $sth->execute() - or Fatal( "Can't execute: ".$sth->errstr() ); + or Fatal("Can't execute: ".$sth->errstr()); if ( $sth->rows != 1 ) { - Info( 'Fixing States table so only one run state is active' ); + Info('Fixing States table so only one run state is active'); resetStates(); - $sql = "UPDATE States SET IsActive='1' WHERE Name='default'"; - $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + $sql = q`UPDATE States SET IsActive=1 WHERE Name='default'`; + $sth = $dbh->prepare_cached($sql) + or Fatal("Can't prepare '$sql': ".$dbh->errstr()); $res = $sth->execute() - or Fatal( "Can't execute: ".$sth->errstr() ); + or Fatal("Can't execute: ".$sth->errstr()); } -} - +} # end sub isActiveSanityCheck # PP - zeroes out isActive for all states sub resetStates { $dbh = zmDbConnect() if ! $dbh; - my $sql = "UPDATE States SET IsActive='0'"; - my $sth = $dbh->prepare_cached( $sql ) - or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + my $sql = 'UPDATE States SET IsActive=0'; + my $sth = $dbh->prepare_cached($sql) + or Fatal("Can't prepare '$sql': ".$dbh->errstr()); my $res = $sth->execute() - or Fatal( "Can't execute: ".$sth->errstr() ); - + or Fatal("Can't execute: ".$sth->errstr()); } sub systemdRunning { - my $result = 0; - my $output = qx(ps -o comm="" -p 1); - chomp( $output ); - - if ( $output =~ /systemd/ ) { - $result = 1; - } - - return $result; + return scalar ( $output =~ /systemd/ ); } sub calledBysystem { - my $result = 0; my $ppid = getppid(); my $output = qx(ps -o comm="" -p $ppid); - chomp( $output ); + #chomp( $output ); - if ($output =~ /^(?:systemd|init)$/) { - $result = 1; - } - - return $result; + return ($output =~ /^(?:systemd|init)$/); } sub verifyFolder { @@ -386,24 +388,22 @@ sub verifyFolder { # Recreate the temporary directory if it's been wiped if ( !-e $folder ) { - Debug( "Recreating directory '$folder'" ); - mkdir( $folder, 0774 ) + Debug("Recreating directory '$folder'"); + mkdir($folder, 0774) or Fatal( "Can't create missing temporary directory '$folder': $!" ); - my ( $runName ) = getpwuid( $> ); + my ( $runName ) = getpwuid($>); if ( $runName ne $Config{ZM_WEB_USER} ) { # Not running as web user, so should be root in which case # chown the directory - my ( $webName, $webPass, $webUid, $webGid ) = getpwnam( $Config{ZM_WEB_USER} ) - or Fatal( "Can't get user details for web user '" - .$Config{ZM_WEB_USER}."': $!" + my ( $webName, $webPass, $webUid, $webGid ) = getpwnam($Config{ZM_WEB_USER}) + or Fatal("Can't get details for web user '$Config{ZM_WEB_USER}': $!"); + chown($webUid, $webGid, $folder) + or Fatal("Can't change ownership of '$folder' to '" + .$Config{ZM_WEB_USER}.':'.$Config{ZM_WEB_GROUP}."': $!" ); - chown( $webUid, $webGid, "$folder" ) - or Fatal( "Can't change ownership of directory '$folder' to '" - .$Config{ZM_WEB_USER}.":".$Config{ZM_WEB_GROUP}."': $!" - ); - } - } -} + } # end if runName ne ZM_WEB_USER + } # end if folder doesn't exist +} # end sub verifyFolder 1; __END__ From 05a434893e2bcff6eb8196bddfb4759334054acc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 6 Jun 2018 16:59:07 -0400 Subject: [PATCH 23/32] We should be able to edit zones even if zm isn't running --- web/skins/classic/views/console.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 119a223eb..8777c04fd 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -318,7 +318,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { - + From aa055c147b7f27d942867d54aac70045d27adf01 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 7 Jun 2018 14:32:36 -0500 Subject: [PATCH 24/32] classic skin - fix dvr control buttons The buttons were being drawn too small which cropped the symbols inside the buttons. Deleting the classic-skin-specific override of the css file allows the default css to apply which looks good to me. --- web/skins/classic/css/classic/views/watch.css | 7 ------- 1 file changed, 7 deletions(-) diff --git a/web/skins/classic/css/classic/views/watch.css b/web/skins/classic/css/classic/views/watch.css index 4ebb30dda..247be4f05 100644 --- a/web/skins/classic/css/classic/views/watch.css +++ b/web/skins/classic/css/classic/views/watch.css @@ -38,13 +38,6 @@ text-align: center; } -#dvrControls input { - height: 20px; - width: 28px; - padding-bottom: 3px; - margin: 0 3px; -} - #dvrControls input[disabled] { color: #aaaaaa; } From be61c50efa1cc70eaca384ab0e4f94c9b92c7517 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 7 Jun 2018 17:25:02 -0400 Subject: [PATCH 25/32] Fix setting Debug option when ZM_LOG_DEBUG_TARGET is empty and fix setting effectiveLevel --- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index aec308b65..0624e3e26 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -245,7 +245,8 @@ sub initialise( @ ) { $tempSyslogLevel = $level if defined($level = $this->getTargettedEnv('LOG_LEVEL_SYSLOG')); if ( $Config{ZM_LOG_DEBUG} ) { - foreach my $target ( split( /\|/, $Config{ZM_LOG_DEBUG_TARGET} ) ) { + # Splitting on an empty string doesn't return an empty string, it returns an empty array + foreach my $target ( $Config{ZM_LOG_DEBUG_TARGET} ? split(/\|/, $Config{ZM_LOG_DEBUG_TARGET}) : '' ) { if ( $target eq $this->{id} || $target eq '_'.$this->{id} || $target eq $this->{idRoot} @@ -392,6 +393,12 @@ sub level { # ICON: I am remarking this out because I don't see the point of having an effective level, if we are just going to set it to level. #$this->{effectiveLevel} = $this->{level} if ( $this->{level} > $this->{effectiveLevel} ); + # ICON: The point is that LOG_DEBUG can be set either in db or in env var and will get passed in here. + # So this will turn on debug, even if not output has Debug level turned on. I think it should be the other way around + + # ICON: Let's try this line instead. effectiveLevel is 1 DEBUG from above, but LOG_DEBUG is off, then $this->level will be 0, and + # so effectiveLevel will become 0 + $this->{effectiveLevel} = $this->{level} if ( $this->{level} < $this->{effectiveLevel} ); } return $this->{level}; } From 61445620aaf319db7d2697cd93050d5bf91af048 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 8 Jun 2018 07:53:23 -0500 Subject: [PATCH 26/32] create the pid file before doing anything else (#2114) * create the pid file before doing anything else * update comment --- scripts/zmdc.pl.in | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index b65388892..d8565cfe9 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -245,6 +245,16 @@ our %terminating_processes; our $zm_terminate = 0; sub run { + + # Call this first otherwise stdout/stderror redirects to the pidfile = bad + if ( open(my $PID, '>', ZM_PID) ) { + print($PID $$); + close($PID); + } else { + # Log not initialized at this point so use die instead + die "Can't open pid file at ".ZM_PID."\n"; + } + my $fd = 0; while( $fd < POSIX::sysconf(&POSIX::_SC_OPEN_MAX) ) { POSIX::close($fd++); @@ -259,13 +269,6 @@ sub run { ."\n" ); - if ( open(my $PID, '>', ZM_PID) ) { - print($PID $$); - close($PID); - } else { - Error("Can't open pid file at " . ZM_PID); - } - # Tell any existing processes to die, wait 1 second between TERM and KILL killAll(1); From fc0369b9a4e7562868fed109ff45ee68e3672ae2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Jun 2018 09:04:31 -0400 Subject: [PATCH 27/32] when detecting a down db connection, need to clear the stored sth as it is no longer valid. --- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 48 +++++++++++---------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index 0624e3e26..ac7b772e9 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -549,30 +549,34 @@ sub logPrint { print(STDERR $message) if $level <= $this->{termLevel}; if ( $level <= $this->{databaseLevel} ) { - if ( ( $this->{dbh} and $this->{dbh}->ping() ) or ( $this->{dbh} = ZoneMinder::Database::zmDbConnect() ) ) { - - - my $sql = 'INSERT INTO Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) VALUES ( ?, ?, ?, ?, ?, ?, ?, NULL )'; - $this->{sth} = $this->{dbh}->prepare_cached($sql) if ! $this->{sth}; - if ( !$this->{sth} ) { + if ( ! ( $this->{dbh} and $this->{dbh}->ping() ) ) { + $this->{sth} = undef; + if ( ! ( $this->{dbh} = ZoneMinder::Database::zmDbConnect() ) ) { + print(STDERR "Can't log to database: "); $this->{databaseLevel} = NOLOG; - Error("Can't prepare log entry '$sql': ".$this->{dbh}->errstr()); - } else { - my $res = $this->{sth}->execute($seconds+($microseconds/1000000.0) - , $this->{id} - , $$ - , $level - , $code - , $string - , $this->{fileName} - ); - if ( !$res ) { - $this->{databaseLevel} = NOLOG; - Error("Can't execute log entry '$sql': ".$this->{dbh}->errstr()); - } + return; } - } else { - print(STDERR "Can't log to database: "); + } + + my $sql = 'INSERT INTO Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) VALUES ( ?, ?, ?, ?, ?, ?, ?, NULL )'; + $this->{sth} = $this->{dbh}->prepare_cached($sql) if ! $this->{sth}; + if ( !$this->{sth} ) { + $this->{databaseLevel} = NOLOG; + Error("Can't prepare log entry '$sql': ".$this->{dbh}->errstr()); + return; + } + + my $res = $this->{sth}->execute($seconds+($microseconds/1000000.0) + , $this->{id} + , $$ + , $level + , $code + , $string + , $this->{fileName} + ); + if ( !$res ) { + $this->{databaseLevel} = NOLOG; + Error("Can't execute log entry '$sql': ".$this->{dbh}->errstr()); } } # end if doing db logging } # end if level < effectivelevel From 7c32e4d86ccb417d93493ad89032aa342d399a2b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Jun 2018 09:15:19 -0400 Subject: [PATCH 28/32] Move zmDbConnect up before logInit because the db handle got closed --- scripts/zmdc.pl.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index d8565cfe9..aa4cbc488 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -262,6 +262,8 @@ sub run { setpgrp(); + # dbh got closed with the rest of the fd's above, so need to reconnect. + my $dbh = zmDbConnect(1); logInit(); dPrint(ZoneMinder::Logger::INFO, 'Server starting at ' @@ -273,7 +275,6 @@ sub run { killAll(1); dPrint(ZoneMinder::Logger::INFO, 'Socket should be open at ' .main::SOCK_FILE); - my $dbh = zmDbConnect(1); socket(SERVER, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!"); unlink(main::SOCK_FILE) or Error('Unable to unlink ' . main::SOCK_FILE .". Error message was: $!") if -e main::SOCK_FILE; bind(SERVER, $saddr) or Fatal("Can't bind to " . main::SOCK_FILE . ": $!"); From d30d8efaf0ae23dc72839cca09ef7a3627f88b51 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Jun 2018 09:17:25 -0400 Subject: [PATCH 29/32] clear stored sth on initialize and re-initialize --- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index ac7b772e9..1714da201 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -279,6 +279,9 @@ sub initialise( @ ) { $this->{initialised} = !undef; + # this function can get called on a previously initialized log Object, so clean any sth's + $this->{sth} = undef; + Debug( 'LogOpts: level='.$codes{$this->{level}} .'/'.$codes{$this->{effectiveLevel}} .', screen='.$codes{$this->{termLevel}} @@ -320,6 +323,8 @@ sub reinitialise { my $screenLevel = $this->termLevel(); $this->termLevel(NOLOG); $this->termLevel($screenLevel) if $screenLevel > NOLOG; + + $this->{sth} = undef; } # Prevents undefined logging levels From 5cdbc85dcc502b2a7d7e3c4074e30ef80e81408b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Jun 2018 14:18:38 -0400 Subject: [PATCH 30/32] Slightly more efficient logPrint. Don't create the message string unless it is going to be used --- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 42 ++++++++++----------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index dc7e361f6..213b83dac 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -529,29 +529,29 @@ sub logPrint { if ( $level <= $this->{effectiveLevel} ) { $string =~ s/[\r\n]+$//g; - - my $code = $codes{$level}; + if ( $level <= $this->{syslogLevel} ) { + syslog($priorities{$level}, $codes{$level}.' [%s]', $string); + } my ($seconds, $microseconds) = gettimeofday(); - my $message = sprintf( - '%s.%06d %s[%d].%s [%s]' - , strftime('%x %H:%M:%S', localtime($seconds)) - , $microseconds - , $this->{id} - , $$ - , $code - , $string - ); - if ( $this->{trace} ) { - $message = Carp::shortmess($message); - } else { - $message = $message."\n"; + if ( $level <= $this->{fileLevel} or $level <= $this->{termLevel} ) { + my $message = sprintf( + '%s.%06d %s[%d].%s [%s]' + , strftime('%x %H:%M:%S', localtime($seconds)) + , $microseconds + , $this->{id} + , $$ + , $codes{$level} + , $string + ); + if ( $this->{trace} ) { + $message = Carp::shortmess($message); + } else { + $message = $message."\n"; + } + print($LOGFILE $message) if $level <= $this->{fileLevel}; + print(STDERR $message) if $level <= $this->{termLevel}; } - if ( $level <= $this->{syslogLevel} ) { - syslog($priorities{$level}, $code.' [%s]', $string); - } - print($LOGFILE $message) if $level <= $this->{fileLevel}; - print(STDERR $message) if $level <= $this->{termLevel}; if ( $level <= $this->{databaseLevel} ) { if ( ! ( $this->{dbh} and $this->{dbh}->ping() ) ) { @@ -575,7 +575,7 @@ sub logPrint { , $this->{id} , $$ , $level - , $code + , $codes{$level} , $string , $this->{fileName} ); From 374123f9c298a4897cbdf819cbdb9fa3714ad034 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Jun 2018 14:21:27 -0400 Subject: [PATCH 31/32] get rid of debugging and turn of extra logReInit --- scripts/zmdc.pl.in | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index aa4cbc488..e2a69aa57 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -373,9 +373,7 @@ sub run { #print( "Select timed out\n" ); } -Debug("restartPending"); restartPending(); -Debug("check_for_processes_to_kill"); check_for_processes_to_kill(); } # end while @@ -404,7 +402,6 @@ sub dPrint { my $logLevel = shift; # One thought here, if no client exists to read these... does it block? if ( fileno(CLIENT) ) { - Debug("Have fileno for CLIENT, printing "); print CLIENT @_ } if ( $logLevel == ZoneMinder::Logger::DEBUG ) { @@ -440,14 +437,10 @@ sub start { my $sigset = POSIX::SigSet->new; my $blockset = POSIX::SigSet->new(SIGCHLD); - Debug("Blocking SIGCHLD"); sigprocmask(SIG_BLOCK, $blockset, $sigset) or Fatal("Can't block SIGCHLD: $!"); - Debug("forking"); if ( my $cpid = fork() ) { - Debug("before logReinit"); # This logReinit is required. Not sure why. - logReinit(); - Debug("aftere logReinit"); + #logReinit(); $process->{pid} = $cpid; $process->{started} = time(); @@ -460,7 +453,6 @@ sub start { $cmd_hash{$process->{command}} = $pid_hash{$cpid} = $process; sigprocmask(SIG_SETMASK, $sigset) or Fatal("Can't restore SIGCHLD: $!"); - Debug("unblocking child"); } elsif ( defined($cpid) ) { # Force reconnection to the db. $dbh = zmDbConnect(1); @@ -523,7 +515,7 @@ sub send_stop { .strftime('%y/%m/%d %H:%M:%S', localtime()) ."\n" ); - sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n"; + sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n"; return(); } @@ -715,7 +707,6 @@ sub reaper { } # end while waitpid $SIG{CHLD} = \&reaper; $! = $saved_status; - Debug("Leaving reaper"); } sub restartPending { @@ -727,7 +718,6 @@ sub restartPending { start($process->{daemon}, @{$process->{args}}); } } - Debug("done restartPending"); } sub shutdownAll { From be26f14566e05edc2bcd0107ab53190e81ec60dd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Jun 2018 14:59:14 -0400 Subject: [PATCH 32/32] put back zmsystemctl.pl --- scripts/zmpkg.pl.in | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/scripts/zmpkg.pl.in b/scripts/zmpkg.pl.in index e146f76c8..d11e04d5a 100644 --- a/scripts/zmpkg.pl.in +++ b/scripts/zmpkg.pl.in @@ -149,21 +149,8 @@ if ( $command =~ /^(start|stop|restart)$/ ) { $command = $1; if ( systemdRunning() && !calledBysystem() ) { - Info("Redirecting command through systemctl"); - my $path = qx(which systemctl); - Info("Path is $path"); - Info("Status is $?"); - my $status = $? >> 8; - Info("Status is $status"); - ( $path ) = $path =~ /^(.*)$/; - - if ( !$path || $status ) { - Fatal('Unable to determine systemctl executable. Is systemd in use?'); - } - Info("exec $path $command zoneminder"); - exec("$path $command zoneminder"); - } else { - Debug("called by SystemD"); + qx(@BINDIR@/zmsystemctl.pl $command); + $command = ''; } }
 /  /  /  /