diff --git a/src/zm_config.cpp b/src/zm_config.cpp index 8ba0c8500..f6fd40679 100644 --- a/src/zm_config.cpp +++ b/src/zm_config.cpp @@ -241,6 +241,26 @@ void Config::Load() void Config::Assign() { ZM_CFG_ASSIGN_LIST + + if ( extra_debug ) + { + static char extra_level_env[PATH_MAX] = ""; + static char extra_log_env[PATH_MAX] = ""; + + snprintf( extra_level_env, sizeof(extra_level_env), "ZM_DBG_LEVEL%s=%d", extra_debug_target, extra_debug_level ); + if ( putenv( extra_level_env ) < 0 ) + { + Error(("Can't putenv %s: %s", extra_level_env, strerror(errno) )); + } + + snprintf( extra_log_env, sizeof(extra_log_env), "ZM_DBG_LOG%s=%s", extra_debug_target, extra_debug_log ); + if ( putenv( extra_log_env ) < 0 ) + { + Error(("Can't putenv %s: %s", extra_log_env, strerror(errno) )); + } + + zmDbgReinit( extra_debug_target ); + } } const ConfigItem &Config::Item( int id ) @@ -248,6 +268,7 @@ const ConfigItem &Config::Item( int id ) if ( !n_items ) { Load(); + Assign(); } if ( id < 0 || id > ZM_MAX_CFG_ID ) diff --git a/src/zm_debug.c b/src/zm_debug.c index 561203497..06bd6d0f8 100644 --- a/src/zm_debug.c +++ b/src/zm_debug.c @@ -108,15 +108,15 @@ int zmGetDebugEnv() } env_ptr = NULL; - sprintf(buffer,"ZM_DBG_LEVEL_%s_%s",zm_dbg_name,zm_dbg_id); + sprintf( buffer, "ZM_DBG_LEVEL_%s_%s", zm_dbg_name, zm_dbg_id ); env_ptr = getenv(buffer); if ( env_ptr == (char *)NULL ) { - sprintf(buffer,"ZM_DBG_LEVEL_%s",zm_dbg_name); + sprintf( buffer, "ZM_DBG_LEVEL_%s", zm_dbg_name ); env_ptr = getenv(buffer); if ( env_ptr == (char *)NULL ) { - sprintf(buffer,"ZM_DBG_LEVEL"); + sprintf( buffer, "ZM_DBG_LEVEL" ); env_ptr = getenv(buffer); } } @@ -162,41 +162,21 @@ int zmGetDebugEnv() return( 0 ); } -int zmDebugInitialise( const char *name, const char *id, int level ) +int zmDebugPrepareLog() { FILE *tmp_fp; - int status; - struct timezone tzp; - gettimeofday( &zm_dbg_start, &tzp ); - - Debug( 1,( "Initialising Debug" )); - - strncpy( zm_dbg_name, name, sizeof(zm_dbg_name) ); - strncpy( zm_dbg_id, id, sizeof(zm_dbg_id) ); - zm_dbg_level = level; - - /* Now set up the syslog stuff */ - if ( zm_dbg_id[0] ) - snprintf( zm_dbg_syslog, sizeof(zm_dbg_syslog), "%s_%s", zm_dbg_name, zm_dbg_id ); - else - strncpy( zm_dbg_syslog, zm_dbg_name, sizeof(zm_dbg_syslog) ); - - (void) openlog( zm_dbg_syslog, LOG_PID|LOG_NDELAY, LOG_LOCAL1 ); - - zm_temp_dbg_string[0] = '\0'; - zm_dbg_class[0] = '\0'; - - zm_dbg_pid = getpid(); - zm_dbg_log_fd = (FILE *)NULL; - if( (status = zmGetDebugEnv() ) < 0) + if ( zm_dbg_log_fd ) { - Error(( "Debug Environment Error, status = %d", status )); - return(ZM_DBG_ERROR); + fflush( zm_dbg_log_fd ); + if ( fclose(zm_dbg_log_fd) == -1 ) + { + Error(( "fclose(), error = %s",strerror(errno)) ); + return( ZM_DBG_ERROR ); + } + zm_dbg_log_fd = (FILE *)NULL; } - strncpy( zm_dbg_name, zm_dbg_syslog, sizeof(zm_dbg_name) ); - if ( ( zm_dbg_add_log_id == FALSE && zm_dbg_log[0] ) && ( zm_dbg_log[strlen(zm_dbg_log)-1] == '~' ) ) { zm_dbg_log[strlen(zm_dbg_log)-1] = '\0'; @@ -216,6 +196,45 @@ int zmDebugInitialise( const char *name, const char *id, int level ) Error(("fopen() for %s, error = %s",zm_dbg_log,strerror(errno))); return(ZM_DBG_ERROR); } +} + +int zmDebugInitialise( const char *name, const char *id, int level ) +{ + int status; + struct timezone tzp; + + gettimeofday( &zm_dbg_start, &tzp ); + + Debug( 1,( "Initialising Debug" )); + + strncpy( zm_dbg_name, name, sizeof(zm_dbg_name) ); + strncpy( zm_dbg_id, id, sizeof(zm_dbg_id) ); + zm_dbg_level = level; + + /* Now set up the syslog stuff */ + if ( zm_dbg_id[0] ) + snprintf( zm_dbg_syslog, sizeof(zm_dbg_syslog), "%s_%s", zm_dbg_name, zm_dbg_id ); + else + strncpy( zm_dbg_syslog, zm_dbg_name, sizeof(zm_dbg_syslog) ); + + (void) openlog( zm_dbg_syslog, LOG_PID|LOG_NDELAY, LOG_LOCAL1 ); + + strncpy( zm_dbg_name, zm_dbg_syslog, sizeof(zm_dbg_name) ); + + zm_temp_dbg_string[0] = '\0'; + zm_dbg_class[0] = '\0'; + + zm_dbg_pid = getpid(); + zm_dbg_log_fd = (FILE *)NULL; + + if( (status = zmGetDebugEnv() ) < 0) + { + Error(( "Debug Environment Error, status = %d", status )); + return(ZM_DBG_ERROR); + } + + zmDebugPrepareLog(); + Info(( "Debug Level = %d, Debug Log = %s", zm_dbg_level,zm_dbg_log[0]?zm_dbg_log:"" )); { @@ -243,20 +262,71 @@ int zmDbgInit( const char *name, const char *id, int level ) return((zmDebugInitialise( name, id, level ) == ZM_DBG_OK ? 0 : 1)); } +int zmDebugReinitialise( const char *target ) +{ + int status; + int reinit = FALSE; + char buffer[64]; + + if ( target ) + { + snprintf( buffer, sizeof(buffer), "_%s_%s", zm_dbg_name, zm_dbg_id ); + if ( strcmp( target, buffer ) == 0 ) + { + reinit = TRUE; + } + else + { + snprintf( buffer, sizeof(buffer), "_%s", zm_dbg_name ); + if ( strcmp( target, buffer ) == 0 ) + { + reinit = TRUE; + } + else + { + if ( strcmp( target, "" ) == 0 ) + { + reinit = TRUE; + } + } + } + } + + if ( reinit ) + { + if ( (status = zmGetDebugEnv() ) < 0 ) + { + Error(( "Debug Environment Error, status = %d", status )); + return(ZM_DBG_ERROR); + } + + zmDebugPrepareLog(); + + Info(( "New Debug Level = %d, New Debug Log = %s", zm_dbg_level, zm_dbg_log[0]?zm_dbg_log:"" )); + } + + return(ZM_DBG_OK); +} + +int zmDbgReinit( const char *target ) +{ + return( (zmDebugReinitialise( target )==ZM_DBG_OK?0:1) ); +} + int zmDebugTerminate() { - Debug(1,("Terminating Debug")); - fflush(zm_dbg_log_fd); - if((fclose(zm_dbg_log_fd)) == -1) + Debug( 1,( "Terminating Debug" )); + fflush( zm_dbg_log_fd ); + if ( fclose(zm_dbg_log_fd) == -1 ) { - Error(("fclose(), error = %s",strerror(errno))); - return(ZM_DBG_ERROR); + Error(( "fclose(), error = %s",strerror(errno)) ); + return( ZM_DBG_ERROR ); } zm_dbg_log_fd = (FILE *)NULL; (void) closelog(); zm_dbg_running = FALSE; - return(ZM_DBG_OK); + return( ZM_DBG_OK ); } int zmDbgTerm() @@ -382,8 +452,7 @@ int zmDbgOutput( const char *fstring, ... ) log_code = LOG_CRIT; break; default: - /* log_code = LOG_DEBUG; */ - log_code = LOG_INFO; + log_code = LOG_DEBUG; break; } log_code |= LOG_LOCAL1; diff --git a/src/zm_debug.h b/src/zm_debug.h index b303ca9e9..7c30e46c2 100644 --- a/src/zm_debug.h +++ b/src/zm_debug.h @@ -98,18 +98,21 @@ extern "C" { /* function declarations */ void zmUsrHandler( int sig ); int zmGetDebugEnv( void ); +int zmDebugPrepareLog( void ); int zmDebugInitialise( const char *name, const char *id, int level ); +int zmDebugReinitialise( const char *target ); int zmDebugTerminate( void ); void zmDbgSubtractTime( struct timeval * const tp1, struct timeval * const tp2 ); - #if defined(__STDC__) || defined(__cplusplus) int zmDbgInit( const char *name, const char *id, int level ); +int zmDbgReinit( const char *target ); int zmDbgTerm(void); -int zmDbgPrepare(const char * const file,const int line, const int code); -int zmDbgOutput(const char *fstring, ... ) __attribute__ ((format(printf, 1, 2))); +int zmDbgPrepare( const char * const file, const int line, const int code ); +int zmDbgOutput( const char *fstring, ... ) __attribute__ ((format(printf, 1, 2))); #else int zmDbgInit(); +int zmDbgReinit(); int zmDbgTerm(); int zmDbgPrepare(); int zmDbgOutput(); diff --git a/web/zm_actions.php b/web/zm_actions.php index 9893e4b58..21f173d10 100644 --- a/web/zm_actions.php +++ b/web/zm_actions.php @@ -1216,11 +1216,11 @@ if ( isset($action) ) case "x10" : case "mail" : case "ftp" : + case "tools" : $restart = true; break; case "web" : case "video" : - case "tools" : case "highband" : case "medband" : case "lowband" : diff --git a/zmconfig.pl.in b/zmconfig.pl.in index 85b393a49..ebca81f35 100755 --- a/zmconfig.pl.in +++ b/zmconfig.pl.in @@ -506,6 +506,41 @@ my @options = type => $types{boolean}, category => 'tools', }, + { + name => "ZM_EXTRA_DEBUG", + default => "no", + description => "Whether to switch additional debugging on", + help => "ZoneMinder binary components usually have several levels of debug information they can output. Normally this is set to a fairly low level to avoid filling logs too quickly. This options lets you switch on other options that allow you to configure additional debug information to be output. Components will pick up this instruction when they are restarted.", + type => $types{boolean}, + category => 'tools', + }, + { + name => "ZM_EXTRA_DEBUG_TARGET", + default => "", + description => "What components should have extra debug enabled", + help => "There are three scopes of debug available. Leaving this option blank means that all components will use extra debug (not recommended). Setting this option to '_', e.g. _zmc, will limit extra debug to that component only. Setting this option to '__', e.g. '_zmc_m1' will limit extra debug to that instance of the component only. This is ordinarily what you probably want to do.", + requires => [ { name => "ZM_EXTRA_DEBUG", value => "yes" } ], + type => $types{string}, + category => 'tools', + }, + { + name => "ZM_EXTRA_DEBUG_LEVEL", + default => 0, + description => "What level of extra debug should be enabled", + help => "There are 9 levels of debug available, with higher numbers being more debug and level 0 being no debug. However not all levels are used by all components. Also if there is debug at a high level it is usually likely to be output at such a volume that it may obstruct normal operation. For this reason you should set the level carefully and cautiously until the degree of debug you wish to see is present.", + requires => [ { name => "ZM_EXTRA_DEBUG", value => "yes" } ], + type => { db_type=>'integer', hint=>'0|1|2|3|4|5|6|7|8|9', pattern=>qr|^(\d+)$|, format=>q( $1 ) }, + category => 'tools', + }, + { + name => "ZM_EXTRA_DEBUG_LOG", + default => "/tmp/zm_debug.log+", + description => "Where extra debug is output to", + help => "Depending on your system configuration you may find that only errors, warning and informational messages are logged to your system log. This option allows you to specify an additional target for these messages and debug. This also has the advantage of partitioning debug for the component you are tracing, from messages from other components. Be warned however that if this is a simple filename and you are debugging several components then they will all try and write to the same file with undesirable consequences. Appending a '+' to the filename will cause the file to be created with a '.' suffic containing your process id. In this way debug from each run of a component is kept separate. This is the recommended setting as it will also prevent subsequent runs from overwriting the same log.", + requires => [ { name => "ZM_EXTRA_DEBUG", value => "yes" } ], + type => $types{string}, + category => 'tools', + }, { name => "ZM_PATH_SOCKS", default => "/tmp", @@ -1847,15 +1882,15 @@ if ( $reprocess ) $define_list .= sprintf( "#define $opt_name $opt_id\n" ); $declare_list .= sprintf( "\t" ); - if ( $opt_type == $types{boolean} ) + if ( $opt_type->{db_type} eq 'boolean' ) { $declare_list .= sprintf( "bool " ); } - elsif ( $opt_type == $types{integer} || $opt_type == $types{hexadecimal} ) + elsif ( $opt_type->{db_type} eq 'integer' || $opt_type->{db_type} eq 'hexadecimal' ) { $declare_list .= sprintf( "int " ); } - elsif ( $opt_type == $types{decimal} ) + elsif ( $opt_type->{db_type} eq 'decimal' ) { $declare_list .= sprintf( "double " ); } @@ -1867,15 +1902,15 @@ if ( $reprocess ) $assign_list .= sprintf( "\t" ); $assign_list .= sprintf( $var_name." = " ); - if ( $opt_type == $types{boolean} ) + if ( $opt_type->{db_type} eq 'boolean' ) { $assign_list .= sprintf( "(bool)" ); } - elsif ( $opt_type == $types{integer} || $opt_type == $types{hexadecimal} ) + elsif ( $opt_type->{db_type} eq 'integer' || $opt_type->{db_type} eq 'hexadecimal' ) { $assign_list .= sprintf( "(int)" ); } - elsif ( $opt_type == $types{decimal} ) + elsif ( $opt_type->{db_type} eq 'decimal' ) { $assign_list .= sprintf( "(double) " ); } @@ -1939,10 +1974,10 @@ if ( $reprocess ) $opt_value = "true" if ( $opt_value eq "yes" ); $opt_value = "false" if ( $opt_value eq "no" ); } - if ( $opt_type == $types{boolean} - || $opt_type == $types{integer} - || $opt_type == $types{decimal} - || $opt_type == $types{hexadecimal} ) + if ( $opt_type->{db_type} eq 'boolean' + || $opt_type->{db_type} eq 'integer' + || $opt_type->{db_type} eq 'decimal' + || $opt_type->{db_type} eq 'hexadecimal' ) { $data =~ s/^(#define\s+$opt_name\s+).*$/$1$opt_value\t\/\/ $opt_desc \(from zmconfig\)/mg; } @@ -1965,10 +2000,10 @@ if ( $reprocess ) $opt_value = 1 if ( $opt_value eq "yes" ); $opt_value = 0 if ( $opt_value eq "no" ); } - if ( $opt_type == $types{boolean} - || $opt_type == $types{integer} - || $opt_type == $types{decimal} - || $opt_type == $types{hexadecimal} ) + if ( $opt_type->{db_type} eq 'boolean' + || $opt_type->{db_type} eq 'integer' + || $opt_type->{db_type} eq 'decimal' + || $opt_type->{db_type} eq 'hexadecimal' ) { $data =~ s/^(\s*use\s+constant\s+$opt_name\s*=>\s*).*$/$1$opt_value;\t# $opt_desc \(from zmconfig\)/mg; } @@ -2004,10 +2039,10 @@ if ( $reprocess ) $opt_value = "true" if ( $opt_value eq "yes" ); $opt_value = "false" if ( $opt_value eq "no" ); } - if ( $opt_type == $types{boolean} - || $opt_type == $types{integer} - || $opt_type == $types{decimal} - || $opt_type == $types{hexadecimal} ) + if ( $opt_type->{db_type} eq 'boolean' + || $opt_type->{db_type} eq 'integer' + || $opt_type->{db_type} eq 'decimal' + || $opt_type->{db_type} eq 'hexadecimal' ) { $data =~ s/^(define\s*\(\s*"$opt_name"\s*,\s*).*$/$1$opt_value \);\t\/\/ $opt_desc \(from zmconfig\)/mg; }