diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index fe05585e4..a73bc524d 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -256,7 +256,7 @@ FOR EACH ROW END IF; END IF; END; - +// DELIMITER ; DROP TABLE IF EXISTS `Events_Day`; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index 0eb9e2763..56ecfa249 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -470,7 +470,7 @@ sub DiskSpace { $_[0]{DiskSpace} = $size; Debug("DiskSpace for event $_[0]{Id} at $_[0]{Path} Updated to $size bytes"); } else { - Warning("DiskSpace: Event does not exist at $_[0]{Path}:" . $Event->to_string() ); + Warning("DiskSpace: Event does not exist at $_[0]{Path}:" . $_[0]->to_string() ); } } # end if ! defined DiskSpace return $_[0]{DiskSpace}; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index 2d00a7781..38c56c40c 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -714,6 +714,9 @@ sub error { sub Fatal( @ ) { fetch()->logPrint( FATAL, @_ ); + if ( $SIG{TERM} ne 'DEFAULT' ) { + $SIG{TERM}(); + } exit( -1 ); } diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index b0fd7697b..761c07da2 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -159,14 +159,14 @@ MAIN: while( $loop ) { while ( ! ( $dbh and $dbh->ping() ) ) { $dbh = zmDbConnect(); if ( ! $dbh ) { + Error('Unable to connect to database'); if ( $continuous ) { - Error('Unable to connect to database'); # if we are running continuously, then just skip to the next # interval, otherwise we are a one off run, so wait a second and # retry until someone kills us. sleep( $Config{ZM_AUDIT_CHECK_INTERVAL} ); } else { - Fatal('Unable to connect to database'); + Term(); } # end if } # end if } # end while can't connect to the db @@ -175,13 +175,15 @@ MAIN: while( $loop ) { if ( defined $storage_id ) { @Storage_Areas = ZoneMinder::Storage->find( Id=>$storage_id ); if ( !@Storage_Areas ) { - Fatal("No Storage Area found with Id $storage_id"); + Error("No Storage Area found with Id $storage_id"); + Term(); } Info("Auditing Storage Area $Storage_Areas[0]{Id} $Storage_Areas[0]{Name} at $Storage_Areas[0]{Path}"); } elsif ( $Config{ZM_SERVER_ID} ) { @Storage_Areas = ZoneMinder::Storage->find( ServerId => $Config{ZM_SERVER_ID} ); if ( ! @Storage_Areas ) { - Fatal("No Storage Area found with ServerId =" . $Config{ZM_SERVER_ID}); + Error("No Storage Area found with ServerId =" . $Config{ZM_SERVER_ID}); + Term(); } Info("Auditing All Storage Areas on Server " . $Storage_Areas[0]->Server()->Name()); } else { @@ -465,10 +467,10 @@ MAIN: while( $loop ) { } # end if exists in filesystem } # end if ! in fs_events } # foreach db_event - } else { - my $Monitor = new ZoneMinder::Monitor( $db_monitor ); - my $Storage = $Monitor->Storage(); - aud_print( "Database monitor '$db_monitor' does not exist in filesystem, should have been at ".$Storage->Path().'/'.$Monitor->Id()."\n" ); + #} else { + #my $Monitor = new ZoneMinder::Monitor( $db_monitor ); + #my $Storage = $Monitor->Storage(); + #aud_print( "Database monitor '$db_monitor' does not exist in filesystem, should have been at ".$Storage->Path().'/'.$Monitor->Id()."\n" ); #if ( confirm() ) #{ # We don't actually do this in case it's new @@ -478,48 +480,62 @@ MAIN: while( $loop ) { #} } } # end foreach db_monitor - redo MAIN if ( $cleaned ); + if ( $cleaned ) { + Debug("Have done some cleaning, restarting."); + redo MAIN; + } # Remove orphaned events (with no monitor) $cleaned = 0; + Debug("Checking for Orphaned Events"); my $selectOrphanedEventsSql = 'SELECT Events.Id, Events.Name FROM Events LEFT JOIN Monitors ON (Events.MonitorId = Monitors.Id) WHERE isnull(Monitors.Id)'; my $selectOrphanedEventsSth = $dbh->prepare_cached( $selectOrphanedEventsSql ) - or Fatal( "Can't prepare '$selectOrphanedEventsSql': ".$dbh->errstr() ); + or Error( "Can't prepare '$selectOrphanedEventsSql': ".$dbh->errstr() ); $res = $selectOrphanedEventsSth->execute() - or Fatal( "Can't execute: ".$selectOrphanedEventsSth->errstr() ); + or Error( "Can't execute: ".$selectOrphanedEventsSth->errstr() ); while( my $event = $selectOrphanedEventsSth->fetchrow_hashref() ) { aud_print( "Found orphaned event with no monitor '$event->{Id}'" ); if ( confirm() ) { - $res = $deleteEventSth->execute( $event->{Id} ) - or Fatal( "Can't execute: ".$deleteEventSth->errstr() ); - $cleaned = 1; + if ( $res = $deleteEventSth->execute( $event->{Id} ) ) { + $cleaned = 1; + } else { + Error( "Can't execute: ".$deleteEventSth->errstr() ); + } } } - redo MAIN if ( $cleaned ); + redo MAIN if $cleaned; # Remove empty events (with no frames) $cleaned = 0; + Debug("Checking for Events with no Frames"); my $selectEmptyEventsSql = 'SELECT E.Id AS Id, E.StartTime, F.EventId FROM Events as E LEFT JOIN Frames as F ON (E.Id = F.EventId) WHERE isnull(F.EventId) AND now() - interval '.$Config{ZM_AUDIT_MIN_AGE}.' second > E.StartTime'; - my $selectEmptyEventsSth = $dbh->prepare_cached( $selectEmptyEventsSql ) - or Fatal( "Can't prepare '$selectEmptyEventsSql': ".$dbh->errstr() ); - $res = $selectEmptyEventsSth->execute() - or Fatal( "Can't execute: ".$selectEmptyEventsSth->errstr() ); - while( my $event = $selectEmptyEventsSth->fetchrow_hashref() ) { - aud_print( "Found empty event with no frame records '$event->{Id}' at $$event{StartTime}" ); - if ( confirm() ) { - $res = $deleteEventSth->execute( $event->{Id} ) - or Fatal( "Can't execute: ".$deleteEventSth->errstr() ); - $cleaned = 1; + if ( my $selectEmptyEventsSth = $dbh->prepare_cached( $selectEmptyEventsSql ) ) { + if ( $res = $selectEmptyEventsSth->execute() ) { + while( my $event = $selectEmptyEventsSth->fetchrow_hashref() ) { + aud_print( "Found empty event with no frame records '$event->{Id}' at $$event{StartTime}" ); + if ( confirm() ) { + if ( $res = $deleteEventSth->execute( $event->{Id} ) ) { + $cleaned = 1; + } else { + Error( "Can't execute: ".$deleteEventSth->errstr() ); + } + } + } # end foreach row + } else { + Error( "Can't execute: ".$selectEmptyEventsSth->errstr() ); } + } else { + Error( "Can't prepare '$selectEmptyEventsSql': ".$dbh->errstr() ); } - redo MAIN if ( $cleaned ); + redo MAIN if $cleaned; # Remove orphaned frame records $cleaned = 0; + Debug("Checking for Orphaned Frames"); my $selectOrphanedFramesSql = 'SELECT DISTINCT EventId FROM Frames WHERE EventId NOT IN (SELECT Id FROM Events)'; my $selectOrphanedFramesSth = $dbh->prepare_cached( $selectOrphanedFramesSql ) @@ -534,10 +550,11 @@ MAIN: while( $loop ) { $cleaned = 1; } } - redo MAIN if ( $cleaned ); + redo MAIN if $cleaned; # Remove orphaned stats records $cleaned = 0; + Debug("Checking for Orphaned Stats"); my $selectOrphanedStatsSql = 'SELECT DISTINCT EventId FROM Stats WHERE EventId NOT IN (SELECT Id FROM Events)'; my $selectOrphanedStatsSth = $dbh->prepare_cached( $selectOrphanedStatsSql ) @@ -571,11 +588,15 @@ MAIN: while( $loop ) { #; 'SELECT *, unix_timestamp(StartTime) AS TimeStamp FROM Events WHERE EndTime IS NULL AND StartTime < (now() - interval '.$Config{ZM_AUDIT_MIN_AGE}.' second)'; - my $selectFrameDataSql = 'SELECT max(TimeStamp) as EndTime, unix_timestamp(max(TimeStamp)) AS EndTimeStamp, max(FrameId) as Frames, - count(if(Score>0,1,NULL)) as AlarmFrames, - sum(Score) as TotScore, - max(Score) as MaxScore - FROM Frames WHERE EventId=?'; + my $selectFrameDataSql = ' +SELECT + max(TimeStamp) as EndTime, + unix_timestamp(max(TimeStamp)) AS EndTimeStamp, + max(FrameId) as Frames, + count(if(Score>0,1,NULL)) as AlarmFrames, + sum(Score) as TotScore, + max(Score) as MaxScore +FROM Frames WHERE EventId=?'; my $selectFrameDataSth = $dbh->prepare_cached($selectFrameDataSql) or Fatal( "Can't prepare '$selectFrameDataSql': ".$dbh->errstr() ); @@ -664,6 +685,11 @@ MAIN: while( $loop ) { } } else { # Time of record + + # 7 days is invalid. We need to remove the s + if ( $Config{ZM_LOG_DATABASE_LIMIT} =~ /^(.*)s$/ ) { + $Config{ZM_LOG_DATABASE_LIMIT} = $1; + } my $deleteLogByTimeSql = 'DELETE low_priority FROM Logs WHERE TimeKey < unix_timestamp(now() - interval '.$Config{ZM_LOG_DATABASE_LIMIT}.')'; diff --git a/src/zmc.cpp b/src/zmc.cpp index 4caebb7c0..c278a002c 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -222,14 +222,6 @@ int main(int argc, char *argv[]) { } Info("Starting Capture version %s", ZM_VERSION); - static char sql[ZM_SQL_SML_BUFSIZ]; - for ( int i = 0; i < n_monitors; i ++ ) { - snprintf( sql, sizeof(sql), "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Running')", monitors[i]->Id() ); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - } - } - zmSetDefaultTermHandler(); zmSetDefaultDieHandler(); @@ -242,9 +234,15 @@ int main(int argc, char *argv[]) { int result = 0; while( ! zm_terminate ) { result = 0; + static char sql[ZM_SQL_SML_BUFSIZ]; for ( int i = 0; i < n_monitors; i ++ ) { time_t now = (time_t)time(NULL); monitors[i]->setStartupTime(now); + + snprintf( sql, sizeof(sql), "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Running')", monitors[i]->Id() ); + if ( mysql_query( &dbconn, sql ) ) { + Error( "Can't run query: %s", mysql_error( &dbconn ) ); + } } // Outer primary loop, handles connection to camera if ( monitors[0]->PrimeCapture() < 0 ) { @@ -252,7 +250,6 @@ int main(int argc, char *argv[]) { sleep(10); continue; } - static char sql[ZM_SQL_SML_BUFSIZ]; for ( int i = 0; i < n_monitors; i ++ ) { snprintf( sql, sizeof(sql), "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Connected')", monitors[i]->Id() ); if ( mysql_query( &dbconn, sql ) ) { @@ -374,6 +371,15 @@ int main(int argc, char *argv[]) { delete [] analysis_threads; sleep(10); } // end while ! zm_terminate outer connection loop + + for ( int i = 0; i < n_monitors; i++ ) { + static char sql[ZM_SQL_SML_BUFSIZ]; + snprintf( sql, sizeof(sql), "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','NotRunning')", monitors[i]->Id() ); + if ( mysql_query( &dbconn, sql ) ) { + Error( "Can't run query: %s", mysql_error( &dbconn ) ); + } + delete monitors[i]; + } delete [] monitors; Image::Deinitialise(); diff --git a/web/includes/Server.php b/web/includes/Server.php index aa93f309c..d76984598 100644 --- a/web/includes/Server.php +++ b/web/includes/Server.php @@ -69,6 +69,7 @@ class Server { if ( $this->Id() ) { return ZM_BASE_PROTOCOL . '://'. $this->Hostname(); } else { + return ZM_BASE_PROTOCOL . '://'. $_SERVER['SERVER_NAME']; return ''; } } diff --git a/web/includes/database.php b/web/includes/database.php index 250e5fce8..f11f50d04 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -132,7 +132,13 @@ function dbQuery( $sql, $params=NULL ) { return NULL; } } else { - $result = $dbConn->query( $sql ); + if ( defined('ZM_DB_DEBUG') ) { + if ( $params ) + Warning("SQL: $sql" . implode(',',$params) ); + else + Warning("SQL: $sql:" ); + } + $result = $dbConn->query($sql); } if ( defined('ZM_DB_DEBUG') ) { if ( $params ) diff --git a/web/skins/classic/css/base/skin.css b/web/skins/classic/css/base/skin.css index e86264989..6983d3715 100644 --- a/web/skins/classic/css/base/skin.css +++ b/web/skins/classic/css/base/skin.css @@ -84,7 +84,7 @@ a:hover { } label { - margin-right: 4px; + margin: 0 4px; } input,textarea,select,button,.btn-primary { @@ -474,6 +474,7 @@ input[type=submit], cursor: pointer; text-decoration: none; display: inline-block; + text-align: center; } button:hover, diff --git a/web/skins/classic/css/base/views/console.css b/web/skins/classic/css/base/views/console.css index db84313d0..88d022683 100644 --- a/web/skins/classic/css/base/views/console.css +++ b/web/skins/classic/css/base/views/console.css @@ -70,12 +70,11 @@ } #consoleTable th,td { - height: 16px; text-align: left; } #consoleTable .colMark { - width: 62px; + width: 52px; text-align: center; } @@ -86,6 +85,10 @@ #consoleTable .colZones { text-align: right; } +#consoleTable .colFunction { + width: 120px; + text-align: center; +} #consoleTable .colLeftButtons { text-align: left; diff --git a/web/skins/classic/css/base/views/montagereview.css b/web/skins/classic/css/base/views/montagereview.css index 4fb55a337..63ce22bd7 100644 --- a/web/skins/classic/css/base/views/montagereview.css +++ b/web/skins/classic/css/base/views/montagereview.css @@ -53,3 +53,6 @@ input[type=range]::-ms-tooltip { #downloadVideo { margin-left: 5px; } +#minTime, #maxTime { +margin: 0 4px; +} diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index 66db14579..e2bf1f549 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -147,7 +147,6 @@ echo output_link_if_exists( array( - Logger::NOLOG ) { if ( ! ZM_RUN_AUDIT ) { # zmaudit can clean the logs, but if we aren't running it, then we should clecan them regularly - dbQuery("DELETE FROM Logs WHERE TimeKey < NOW()-to_days('".ZM_LOG_DATABASE_LIMIT."')"); + dbQuery('DELETE FROM Logs WHERE TimeKey < unix_timestamp( NOW() - interval '.ZM_LOG_DATABASE_LIMIT.')'); } echo makePopupLink( '?view=log', 'zmLog', 'log', ''.translate('Log').'' ); } diff --git a/web/skins/classic/views/_monitor_filters.php b/web/skins/classic/views/_monitor_filters.php index 6c9e3f799..72c31f410 100644 --- a/web/skins/classic/views/_monitor_filters.php +++ b/web/skins/classic/views/_monitor_filters.php @@ -43,54 +43,97 @@ foreach ( $storage_areas as $S ) { $StorageById[$S->Id()] = $S; } -?> +$html = +'