Merge branch 'storageareas' of github.com:ConnorTechnology/ZoneMinder into storageareas

This commit is contained in:
Isaac Connor 2018-04-30 10:12:41 -04:00
commit 2845f891bc
11 changed files with 128 additions and 57 deletions

View File

@ -529,6 +529,8 @@ sub MoveTo {
my ( $NewPath ) = ( $NewStorage->Path() =~ /^(.*)$/ ); # De-taint
if ( ! $$NewStorage{Id} ) {
return "New storage does not have an id. Moving will not happen.";
} elsif ( $$NewStorage{Id} == $$self{StorageId} ) {
return "Event is already located at " . $NewPath;
} elsif ( !$NewPath ) {
return "New path ($NewPath) is empty.";
} elsif ( ! -e $NewPath ) {

View File

@ -161,9 +161,9 @@ sub Sql {
my ( $temp_attr_name ) = $term->{attr} =~ /^Monitor(.+)$/;
$self->{Sql} .= 'M.'.$temp_attr_name;
} elsif ( $term->{attr} eq 'ServerId' or $term->{attr} eq 'MonitorServerId' ) {
$self->{Sql} .= 'M.'.$term->{attr};
$self->{Sql} .= 'M.ServerId';
} elsif ( $term->{attr} eq 'StorageServerId' ) {
$self->{Sql} .= 'S.'.$term->{attr};
$self->{Sql} .= 'S.ServerId';
} elsif ( $term->{attr} eq 'FilterServerId' ) {
$self->{Sql} .= $Config{ZM_SERVER_ID};
# StartTime options

View File

@ -158,6 +158,7 @@ sub new {
( $this->{fileName} = $0 ) =~ s|^.*/||;
$this->{logPath} = $Config{ZM_PATH_LOGS};
$this->{logFile} = $this->{logPath}.'/'.$this->{id}.'.log';
($this->{logFile}) = $this->{logFile} =~ /^([\w\.\/]+)$/;
$this->{trace} = 0;
@ -207,6 +208,7 @@ sub initialise( @ ) {
if ( my $logFile = $this->getTargettedEnv('LOG_FILE') ) {
$tempLogFile = $logFile;
}
($tempLogFile) = $tempLogFile =~ /^([\w\.\/]+)$/;
my $tempLevel = INFO;
my $tempTermLevel = $this->{termLevel};
@ -582,24 +584,29 @@ sub logPrint {
}
print($LOGFILE $message) if $level <= $this->{fileLevel};
if ( $level <= $this->{databaseLevel} ) {
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} ) {
$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 ) {
if ( ( $this->{dbh} and $this->{dbh}->ping() ) or ( $this->{dbh} = 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} ) {
$this->{databaseLevel} = NOLOG;
Error("Can't execute log entry '$sql': ".$this->{sth}->errstr());
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());
}
}
} else {
print(STDERR "Can't log to database: ");
}
} # end if doing db logging
print(STDERR $message) if $level <= $this->{termLevel};

View File

@ -242,6 +242,7 @@ use constant KILL_DELAY => 60; # seconds to wait between sending TERM and sendin
our %cmd_hash;
our %pid_hash;
our %terminating_processes;
our $zm_terminate = 0;
sub run {
my $fd = 0;
@ -276,9 +277,9 @@ sub run {
listen(SERVER, SOMAXCONN) or Fatal("Can't listen: $!");
$SIG{CHLD} = \&reaper;
$SIG{INT} = \&shutdownAll;
$SIG{TERM} = \&shutdownAll;
$SIG{ABRT} = \&shutdownAll;
$SIG{INT} = \&shutdown_sig_handler;
$SIG{TERM} = \&shutdown_sig_handler;
$SIG{ABRT} = \&shutdown_sig_handler;
$SIG{HUP} = \&logrot;
my $rin = '';
@ -295,12 +296,18 @@ sub run {
dPrint(ZoneMinder::Logger::INFO, 'Loading Server record have ' . $$Server{Name});
}
while( 1 ) {
while( !$zm_terminate ) {
if ( $Config{ZM_SERVER_ID} ) {
if ( ! ( $secs_count % 60 ) ) {
$dbh = zmDbConnect() if ! $dbh->ping();
Debug("Connecting");
while ( !$zm_terminate and ! ($dbh and $dbh->ping()) ) {
Warning("Not connected to db. Reconnecting");
$dbh = zmDbConnect();
Debug("Conneted? : $dbh");
}
my @cpuload = 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());
@ -308,7 +315,9 @@ sub run {
}
$secs_count += 1;
}
Debug("Before select");
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);
@ -330,7 +339,8 @@ sub run {
# Do nothing, this is all we're here for
dPrint(ZoneMinder::Logger::WARNING, "Already running, ignoring command '$command'\n");
} elsif ( $command eq 'shutdown' ) {
shutdownAll();
# Breka out of while loop
last;
} elsif ( $command eq 'check' ) {
check($daemon, @args);
} elsif ( $command eq 'status' ) {
@ -362,7 +372,9 @@ sub run {
#print( "Select timed out\n" );
}
Debug("restartPending");
restartPending();
Debug("check_for_processes_to_kill");
check_for_processes_to_kill();
} # end while
@ -377,9 +389,7 @@ sub run {
Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr());
}
}
unlink(main::SOCK_FILE) or Error('Unable to unlink ' . main::SOCK_FILE .". Error message was: $!") if ( -e main::SOCK_FILE );
unlink(ZM_PID) or Error('Unable to unlink ' . ZM_PID .". Error message was: $!") if ( -e ZM_PID );
exit();
shutdownAll();
}
sub cPrint {
@ -426,10 +436,12 @@ sub start {
}
my $sigset = POSIX::SigSet->new;
my $blockset = POSIX::SigSet->new( SIGCHLD );
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() ) {
logReinit();
#logReinit();
$process->{pid} = $cpid;
$process->{started} = time();
@ -442,6 +454,7 @@ sub start {
$cmd_hash{$process->{command}} = $pid_hash{$cpid} = $process;
sigprocmask(SIG_SETMASK, $sigset) or Fatal("Can't restore SIGCHLD: $!");
Debug("unblocko child");
} elsif ( defined($cpid) ) {
# Force reconnection to the db.
$dbh = zmDbConnect(1);
@ -527,16 +540,18 @@ sub check_for_processes_to_kill {
my $sigset = POSIX::SigSet->new;
my $blockset = POSIX::SigSet->new(SIGCHLD);
sigprocmask(SIG_BLOCK, $blockset, $sigset) or die "dying at block...\n";
foreach my $command ( %terminating_processes ) {
foreach my $command ( keys %terminating_processes ) {
my $process = $cmd_hash{$command};
Debug("Have process $command at pid $$process{pid} $$process{term_sent_at}");
if ( $$process{term_sent_at} and ( $$process{term_sent_at} - time > KILL_DELAY ) ) {
my $now = time;
Debug("Have process $command at pid $$process{pid} $$process{term_sent_at} - $now = " . ( $$process{term_sent_at} - $now ) );
if ( $$process{term_sent_at} and ( $$process{term_sent_at} - $now > KILL_DELAY ) ) {
dPrint(ZoneMinder::Logger::WARNING, "'$$process{command}' has not stopped at "
.strftime('%y/%m/%d %H:%M:%S', localtime())
.' after ' . KILL_DELAY . ' seconds.'
." Sending KILL to pid $$process{pid}\n"
);
kill('KILL', $$process{pid});
delete $terminating_processes{$command};
}
}
sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n";
@ -595,8 +610,14 @@ sub logrot {
}
}
sub shutdown_sig_handler {
$zm_terminate = 1;
}
sub reaper {
my $saved_status = $!;
# Wait for a child to terminate
while ( (my $cpid = waitpid(-1, WNOHANG)) > 0 ) {
my $status = $?;
@ -620,8 +641,8 @@ sub reaper {
my $out_str = "'$process->{command}' ";
if ( $exit_signal ) {
# 15 == TERM, 14 == ALARM
if ( $exit_signal == 15 || $exit_signal == 14 ) {
# TERM or ALRM
$out_str .= 'exited';
} else {
$out_str .= 'crashed';
@ -659,22 +680,26 @@ sub reaper {
$process->{delay} = $Config{ZM_MAX_RESTART_DELAY};
}
}
Debug("Delay for $$process{command} is now $$process{delay}");
} else {
delete $cmd_hash{$$process{command}};
}
}
} # end while waitpid
$SIG{CHLD} = \&reaper;
$! = $saved_status;
Debug("Leaving reaper");
}
sub restartPending {
# Restart any pending processes
foreach my $process ( values( %cmd_hash ) ) {
# Restart any pending processes, we list them first because cmd_hash may change in foreach
my @processes = values %cmd_hash;
foreach my $process ( @processes ) {
if ( $process->{pending} && $process->{pending} <= time() ) {
dPrint(ZoneMinder::Logger::INFO, "Starting pending process, $process->{command}\n");
start($process->{daemon}, @{$process->{args}});
}
}
dPrint(ZoneMinder::Logger::INFO, "done restartPending");
}
sub shutdownAll {
@ -683,9 +708,14 @@ sub shutdownAll {
next if ! $pid_hash{$pid};
send_stop(1, $pid_hash{$pid});
}
while ( %terminating_processes ) {
my $count= KILL_DELAY;
while ( (keys %terminating_processes) and $count) {
check_for_processes_to_kill();
sleep(1) if %terminating_processes;
if ( %terminating_processes ) {
Debug("Still " . %terminating_processes . ' to die. count is: ' . $count . ' sleeping');
sleep(1);
$count --;
}
}
dPrint(ZoneMinder::Logger::INFO, "Server shutdown at "
.strftime('%y/%m/%d %H:%M:%S', localtime())

View File

@ -94,7 +94,7 @@ use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)
: ($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS})
;
logInit();
logInit($filter_id?(id=>'zmfilter_'.$filter_id.'.log'):());
sub HupHandler {
Info("Received HUP, reloading");
&ZoneMinder::Logger::logHupHandler();

View File

@ -259,7 +259,7 @@ Event::~Event() {
"UPDATE Events SET Name='%s %" PRIu64 "', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' WHERE Id = %" PRIu64,
monitor->EventPrefix(), id, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, video_name, id );
db_mutex.lock();
while ( mysql_query(&dbconn, sql) ) {
while ( mysql_query(&dbconn, sql) && !zm_terminate ) {
Error("Can't update event: %s reason: %s", sql, mysql_error(&dbconn));
db_mutex.unlock();
sleep(1);
@ -424,16 +424,16 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap ) {
#else
static char escapedNotes[ZM_SQL_MED_BUFSIZ];
mysql_real_escape_string( &dbconn, escapedNotes, notes.c_str(), notes.length() );
mysql_real_escape_string(&dbconn, escapedNotes, notes.c_str(), notes.length());
snprintf( sql, sizeof(sql), "UPDATE Events SET Notes = '%s' WHERE Id = %" PRIu64, escapedNotes, id );
snprintf(sql, sizeof(sql), "UPDATE Events SET Notes = '%s' WHERE Id = %" PRIu64, escapedNotes, id);
db_mutex.lock();
if ( mysql_query( &dbconn, sql ) ) {
Error( "Can't insert event: %s", mysql_error( &dbconn ) );
if ( mysql_query(&dbconn, sql) ) {
Error("Can't insert event: %s", mysql_error(&dbconn));
}
db_mutex.unlock();
#endif
}
} // end if update
}
void Event::AddFrames( int n_frames, Image **images, struct timeval **timestamps ) {
@ -487,7 +487,7 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st
snprintf( sql+sql_len, sizeof(sql)-sql_len, "( %" PRIu64 ", %d, from_unixtime(%ld), %s%ld.%02ld ), ", id, frames, timestamps[i]->tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec );
frameCount++;
}
} // end foreach frame
if ( frameCount ) {
Debug( 1, "Adding %d/%d frames to DB", frameCount, n_frames );
@ -545,7 +545,10 @@ Debug(3, "Writing video");
Debug( 1, "Adding frame %d of type \"%s\" to DB", frames, Event::frame_type_names[frame_type] );
static char sql[ZM_SQL_MED_BUFSIZ];
snprintf(sql, sizeof(sql), "INSERT INTO Frames ( EventId, FrameId, Type, TimeStamp, Delta, Score ) values ( %" PRIu64 ", %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d )", id, frames, frame_type_names[frame_type], timestamp.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, score);
snprintf(sql, sizeof(sql),
"INSERT INTO Frames ( EventId, FrameId, Type, TimeStamp, Delta, Score )"
" VALUES ( %" PRIu64 ", %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d )",
id, frames, frame_type_names[frame_type], timestamp.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, score);
db_mutex.lock();
if ( mysql_query(&dbconn, sql) ) {
Error("Can't insert frame: %s", mysql_error(&dbconn));
@ -558,7 +561,7 @@ Debug(3, "Writing video");
// We are writing a Bulk frame
if ( frame_type == BULK ) {
snprintf( sql, sizeof(sql),
snprintf(sql, sizeof(sql),
"UPDATE Events SET Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d where Id = %" PRIu64,
( delta_time.positive?"":"-" ),
delta_time.sec, delta_time.fsec,
@ -570,7 +573,7 @@ Debug(3, "Writing video");
id
);
db_mutex.lock();
while ( mysql_query(&dbconn, sql) ) {
while ( mysql_query(&dbconn, sql) && !zm_terminate ) {
Error("Can't update event: %s", mysql_error(&dbconn));
db_mutex.unlock();
sleep(1);

View File

@ -543,7 +543,7 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co
mysql_real_escape_string( &dbconn, escapedString, syslogStart, strlen(syslogStart) );
snprintf( sql, sizeof(sql), "insert into Logs ( TimeKey, Component, ServerId, Pid, Level, Code, Message, File, Line ) values ( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )", timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, escapedString, file, line );
if (mysql_query(&dbconn, sql)) {
if ( mysql_query(&dbconn, sql) ) {
Level tempDatabaseLevel = mDatabaseLevel;
databaseLevel(NOLOG);
Error("Can't insert log entry: sql(%s) error(%s)", sql, mysql_error(&dbconn));

View File

@ -1246,9 +1246,9 @@ bool Monitor::Analyse() {
Info("%s: %d - Analysing at %.2f fps", name, image_count, new_fps);
if ( fps != new_fps ) {
fps = new_fps;
db_mutex.lock();
static char sql[ZM_SQL_SML_BUFSIZ];
snprintf(sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,AnalysisFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE AnalysisFPS = %.2lf", id, fps, fps);
db_mutex.lock();
if ( mysql_query(&dbconn, sql) ) {
Error("Can't run query: %s", mysql_error(&dbconn));
}

@ -1 +1 @@
Subproject commit c3976f1478c681b0bbc132ec3a3e82c3984eeed5
Subproject commit 0bd63fb464957080ead342db58ca9e01532cf1ef

View File

@ -451,6 +451,11 @@ class Event {
$values[] = $this->{'Id'};
dbQuery( $sql, $values );
}
public function link_to($text=null) {
if ( !$text )
$text = $this->{'Id'};
return '<a href="?view=event&amp;eid='. $this->{'Id'}.'">'.$text.'</a>';
}
} # end class

View File

@ -102,6 +102,7 @@ while( $event = $result->fetch(PDO::FETCH_ASSOC) ) {
if ( count($EventsByMonitor[$event['MonitorId']]['Events']) ) {
$last_event = end($EventsByMonitor[$event['MonitorId']]['Events']);
#Logger::Debug(print_r($last_event,true));
$gap = $last_event->EndTimeSecs() - $event['StartTimeSecs'];
if ( $gap < $EventsByMonitor[$event['MonitorId']]['MinGap'] )
@ -140,7 +141,10 @@ while( $event = $result->fetch(PDO::FETCH_ASSOC) ) {
<tr>
<th class="colId"><?php echo translate('Id') ?></th>
<th class="colName"><i class="material-icons md-18">videocam</i>&nbsp;<?php echo translate('Name') ?></th>
<th class="colServer"><?php echo translate('Server') ?></th>
<th class="colEvents"><?php echo translate('Events') ?></th>
<th class="colFirstEvent"><?php echo translate('FirstEvent') ?></th>
<th class="colLastEvent"><?php echo translate('LastEvent') ?></th>
<th class="colMinGap"><?php echo translate('MinGap') ?></th>
<th class="colMaxGap"><?php echo translate('MaxGap') ?></th>
<th class="colMissingFiles"><?php echo translate('MissingFiles') ?></th>
@ -152,8 +156,25 @@ while( $event = $result->fetch(PDO::FETCH_ASSOC) ) {
for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
$monitor = $displayMonitors[$monitor_i];
$Monitor = new Monitor($monitor);
$montagereview_link = "?view=montagereview&live=0&MonitorId=". $monitor['Id'] . '&minTime='.$minTime.'&maxTime='.$maxTime;
if ( isset($EventsByMonitor[$Monitor->Id()]) ) {
$EventCounts = $EventsByMonitor[$Monitor->Id()];
$MinGap = $EventCounts['MinGap'];
$MaxGap = $EventCounts['MaxGap'];
$FileMissing = $EventCounts['FileMissing'];
$ZeroSize = $EventCounts['ZeroSize'];
$FirstEvent = $EventCounts['Events'][0];
$LastEvent = end($EventCounts['Events']);
} else {
$MinGap = 0;
$MaxGap = 0;
$FileMissing = 0;
$ZeroSize = 0;
$FirstEvent = 0;
$LastEvent = 0;
}
?>
<tr id="<?php echo 'monitor_id-'.$monitor['Id'] ?>" title="<?php echo $monitor['Id'] ?>">
<td class="colId"><a href="<?php echo $montagereview_link ?>"><?php echo $monitor['Id'] ?></a></td>
@ -168,11 +189,14 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
}, $Monitor->GroupIds() ) );
?>
</div></td>
<td class="colServer"><?php echo $Monitor->Server()->Name()?></td>
<td class="colEvents"><?php echo isset($EventsByMonitor[$Monitor->Id()])?count($EventsByMonitor[$Monitor->Id()]['Events']):0 ?></td>
<td class="colMinGap"><?php echo isset($EventsByMonitor[$Monitor->Id()])?$EventsByMonitor[$Monitor->Id()]['MinGap']:0 ?></td>
<td class="colMaxGap"><?php echo isset($EventsByMonitor[$Monitor->Id()])?$EventsByMonitor[$Monitor->Id()]['MaxGap']:0 ?></td>
<td class="colFileMissing"><?php echo isset($EventsByMonitor[$Monitor->Id()])?$EventsByMonitor[$Monitor->Id()]['FileMissing']:0 ?></td>
<td class="colZeroSize"><?php echo isset($EventsByMonitor[$Monitor->Id()])?$EventsByMonitor[$Monitor->Id()]['ZeroSize']:0 ?></td>
<td class="colFirstEvent"><?php echo $FirstEvent ? $FirstEvent->link_to($FirstEvent->Id().' at ' . $FirstEvent->StartTime()) : 'none'?></td>
<td class="colLastEvent"><?php echo $LastEvent ? $LastEvent->link_to($LastEvent->Id().' at ' . $LastEvent->StartTime()) : 'none'?></td>
<td class="colMinGap"><?php echo $MinGap ?></td>
<td class="colMaxGap"><?php echo $MaxGap ?></td>
<td class="colFileMissing<?php echo $FileMissing ? ' errorText' : ''?>"><?php echo $FileMissing ?></td>
<td class="colZeroSize<?php echo $ZeroSize ? ' errorText' : ''?>"><?php echo $ZeroSize ?></td>
</tr>
<?php
} # end for each monitor