2003-11-05 21:50:08 +08:00
|
|
|
//
|
|
|
|
// ZoneMinder Configuration Implementation, $Date$, $Revision$
|
2008-07-25 17:33:23 +08:00
|
|
|
// Copyright (C) 2001-2008 Philip Coombes
|
2003-11-05 21:50:08 +08:00
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License
|
|
|
|
// as published by the Free Software Foundation; either version 2
|
|
|
|
// of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
2016-12-26 23:23:16 +08:00
|
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2003-11-05 21:50:08 +08:00
|
|
|
//
|
|
|
|
|
|
|
|
#include "zm.h"
|
|
|
|
#include "zm_db.h"
|
2004-12-29 00:46:48 +08:00
|
|
|
|
2011-06-21 17:19:10 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
2017-06-06 04:39:19 +08:00
|
|
|
#include <dirent.h>
|
|
|
|
#include <glob.h>
|
2011-06-21 17:19:10 +08:00
|
|
|
|
2015-07-16 22:04:56 +08:00
|
|
|
#include "zm_utils.h"
|
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
void zmLoadConfig() {
|
2017-06-06 04:39:19 +08:00
|
|
|
|
|
|
|
// Process name, value pairs from the main config file first
|
|
|
|
char configFile[PATH_MAX] = ZM_CONFIG;
|
|
|
|
process_configfile(configFile);
|
|
|
|
|
|
|
|
// Search for user created config files. If one or more are found then
|
|
|
|
// update the Config hash with those values
|
|
|
|
DIR* configSubFolder = opendir(ZM_CONFIG_SUBDIR);
|
|
|
|
if ( configSubFolder ) { // subfolder exists and is readable
|
|
|
|
char glob_pattern[PATH_MAX] = "";
|
|
|
|
snprintf( glob_pattern, sizeof(glob_pattern), "%s/*.conf", ZM_CONFIG_SUBDIR );
|
|
|
|
|
|
|
|
glob_t pglob;
|
|
|
|
int glob_status = glob( glob_pattern, 0, 0, &pglob );
|
|
|
|
if ( glob_status != 0 ) {
|
|
|
|
if ( glob_status < 0 ) {
|
|
|
|
Error( "Can't glob '%s': %s", glob_pattern, strerror(errno) );
|
|
|
|
} else {
|
|
|
|
Debug( 1, "Can't glob '%s': %d", glob_pattern, glob_status );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for ( unsigned int i = 0; i < pglob.gl_pathc; i++ ) {
|
|
|
|
process_configfile(pglob.gl_pathv[i]);
|
|
|
|
}
|
|
|
|
closedir(configSubFolder);
|
|
|
|
}
|
|
|
|
globfree( &pglob );
|
|
|
|
}
|
|
|
|
|
|
|
|
zmDbConnect();
|
|
|
|
config.Load();
|
|
|
|
config.Assign();
|
|
|
|
|
|
|
|
// Populate the server config entries
|
|
|
|
if ( ! staticConfig.SERVER_ID ) {
|
|
|
|
if ( ! staticConfig.SERVER_NAME.empty() ) {
|
|
|
|
|
|
|
|
Debug( 1, "Fetching ZM_SERVER_ID For Name = %s", staticConfig.SERVER_NAME.c_str() );
|
|
|
|
std::string sql = stringtf("SELECT Id FROM Servers WHERE Name='%s'", staticConfig.SERVER_NAME.c_str() );
|
2017-06-09 22:18:15 +08:00
|
|
|
zmDbRow dbrow;
|
|
|
|
if ( dbrow.fetch( sql.c_str() ) ) {
|
2017-06-06 04:39:19 +08:00
|
|
|
staticConfig.SERVER_ID = atoi(dbrow[0]);
|
|
|
|
} else {
|
|
|
|
Fatal("Can't get ServerId for Server %s", staticConfig.SERVER_NAME.c_str() );
|
|
|
|
}
|
|
|
|
|
|
|
|
} // end if has SERVER_NAME
|
|
|
|
} else if ( staticConfig.SERVER_NAME.empty() ) {
|
|
|
|
Debug( 1, "Fetching ZM_SERVER_NAME For Id = %d", staticConfig.SERVER_ID );
|
|
|
|
std::string sql = stringtf("SELECT Name FROM Servers WHERE Id='%d'", staticConfig.SERVER_ID );
|
|
|
|
|
2017-06-09 22:18:15 +08:00
|
|
|
zmDbRow dbrow;
|
|
|
|
if ( dbrow.fetch( sql.c_str() ) ) {
|
|
|
|
staticConfig.SERVER_NAME = std::string(dbrow[0]);
|
|
|
|
} else {
|
|
|
|
Fatal("Can't get ServerName for Server ID %d", staticConfig.SERVER_ID );
|
|
|
|
}
|
|
|
|
|
2017-06-06 04:39:19 +08:00
|
|
|
if ( staticConfig.SERVER_ID ) {
|
|
|
|
Debug( 3, "Multi-server configuration detected. Server is %d.", staticConfig.SERVER_ID );
|
|
|
|
} else {
|
|
|
|
Debug( 3, "Single server configuration assumed because no Server ID or Name was specified." );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void process_configfile( char* configFile) {
|
2016-04-04 22:11:48 +08:00
|
|
|
FILE *cfg;
|
|
|
|
char line[512];
|
2017-06-06 04:39:19 +08:00
|
|
|
if ( (cfg = fopen( configFile, "r")) == NULL ) {
|
|
|
|
Fatal( "Can't open %s: %s", configFile, strerror(errno) );
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
2017-05-20 00:24:19 +08:00
|
|
|
while ( fgets( line, sizeof(line), cfg ) != NULL ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
char *line_ptr = line;
|
|
|
|
|
|
|
|
// Trim off any cr/lf line endings
|
|
|
|
int chomp_len = strcspn( line_ptr, "\r\n" );
|
|
|
|
line_ptr[chomp_len] = '\0';
|
|
|
|
|
|
|
|
// Remove leading white space
|
|
|
|
int white_len = strspn( line_ptr, " \t" );
|
|
|
|
line_ptr += white_len;
|
|
|
|
|
|
|
|
// Check for comment or empty line
|
|
|
|
if ( *line_ptr == '\0' || *line_ptr == '#' )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Remove trailing white space
|
|
|
|
char *temp_ptr = line_ptr+strlen(line_ptr)-1;
|
2017-05-20 00:24:19 +08:00
|
|
|
while ( *temp_ptr == ' ' || *temp_ptr == '\t' ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
*temp_ptr-- = '\0';
|
|
|
|
temp_ptr--;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now look for the '=' in the middle of the line
|
|
|
|
temp_ptr = strchr( line_ptr, '=' );
|
2017-05-20 00:24:19 +08:00
|
|
|
if ( !temp_ptr ) {
|
2017-06-06 04:39:19 +08:00
|
|
|
Warning( "Invalid data in %s: '%s'", configFile, line );
|
2016-04-04 22:11:48 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Assign the name and value parts
|
|
|
|
char *name_ptr = line_ptr;
|
|
|
|
char *val_ptr = temp_ptr+1;
|
|
|
|
|
|
|
|
// Trim trailing space from the name part
|
2017-05-20 00:24:19 +08:00
|
|
|
do {
|
2016-04-04 22:11:48 +08:00
|
|
|
*temp_ptr = '\0';
|
|
|
|
temp_ptr--;
|
2017-05-20 00:24:19 +08:00
|
|
|
} while ( *temp_ptr == ' ' || *temp_ptr == '\t' );
|
2016-04-04 22:11:48 +08:00
|
|
|
|
|
|
|
// Remove leading white space from the value part
|
|
|
|
white_len = strspn( val_ptr, " \t" );
|
|
|
|
val_ptr += white_len;
|
|
|
|
|
|
|
|
if ( strcasecmp( name_ptr, "ZM_DB_HOST" ) == 0 )
|
|
|
|
staticConfig.DB_HOST = std::string(val_ptr);
|
|
|
|
else if ( strcasecmp( name_ptr, "ZM_DB_NAME" ) == 0 )
|
|
|
|
staticConfig.DB_NAME = std::string(val_ptr);
|
|
|
|
else if ( strcasecmp( name_ptr, "ZM_DB_USER" ) == 0 )
|
|
|
|
staticConfig.DB_USER = std::string(val_ptr);
|
|
|
|
else if ( strcasecmp( name_ptr, "ZM_DB_PASS" ) == 0 )
|
|
|
|
staticConfig.DB_PASS = std::string(val_ptr);
|
|
|
|
else if ( strcasecmp( name_ptr, "ZM_PATH_WEB" ) == 0 )
|
|
|
|
staticConfig.PATH_WEB = std::string(val_ptr);
|
|
|
|
else if ( strcasecmp( name_ptr, "ZM_SERVER_HOST" ) == 0 )
|
|
|
|
staticConfig.SERVER_NAME = std::string(val_ptr);
|
|
|
|
else if ( strcasecmp( name_ptr, "ZM_SERVER_NAME" ) == 0 )
|
|
|
|
staticConfig.SERVER_NAME = std::string(val_ptr);
|
|
|
|
else if ( strcasecmp( name_ptr, "ZM_SERVER_ID" ) == 0 )
|
|
|
|
staticConfig.SERVER_ID = atoi(val_ptr);
|
2017-06-13 09:39:37 +08:00
|
|
|
else if ( strcasecmp( name_ptr, "ZM_DIR_EVENTS" ) == 0 )
|
|
|
|
staticConfig.DIR_EVENTS = std::string(val_ptr);
|
|
|
|
else if ( strcasecmp( name_ptr, "ZM_DIR_IMAGES" ) == 0 )
|
|
|
|
staticConfig.DIR_IMAGES = std::string(val_ptr);
|
|
|
|
else if ( strcasecmp( name_ptr, "ZM_DIR_SOUNDS" ) == 0 )
|
|
|
|
staticConfig.DIR_SOUNDS = std::string(val_ptr);
|
|
|
|
else if ( strcasecmp( name_ptr, "ZM_DIR_EXPORTS" ) == 0 )
|
|
|
|
staticConfig.DIR_EXPORTS = std::string(val_ptr);
|
|
|
|
else if ( strcasecmp( name_ptr, "ZM_PATH_ZMS" ) == 0 )
|
|
|
|
staticConfig.PATH_ZMS = std::string(val_ptr);
|
|
|
|
else if ( strcasecmp( name_ptr, "ZM_PATH_MAP" ) == 0 )
|
|
|
|
staticConfig.PATH_MAP = std::string(val_ptr);
|
|
|
|
else if ( strcasecmp( name_ptr, "ZM_PATH_SOCKS" ) == 0 )
|
|
|
|
staticConfig.PATH_SOCKS = std::string(val_ptr);
|
|
|
|
else if ( strcasecmp( name_ptr, "ZM_PATH_LOGS" ) == 0 )
|
|
|
|
staticConfig.PATH_LOGS = std::string(val_ptr);
|
|
|
|
else if ( strcasecmp( name_ptr, "ZM_PATH_SWAP" ) == 0 )
|
|
|
|
staticConfig.PATH_SWAP = std::string(val_ptr);
|
|
|
|
else if ( strcasecmp( name_ptr, "ZM_PATH_ARP" ) == 0 )
|
|
|
|
staticConfig.PATH_ARP = std::string(val_ptr);
|
2017-05-20 00:24:19 +08:00
|
|
|
else {
|
2016-04-04 22:11:48 +08:00
|
|
|
// We ignore this now as there may be more parameters than the
|
|
|
|
// c/c++ binaries are bothered about
|
|
|
|
// Warning( "Invalid parameter '%s' in %s", name_ptr, ZM_CONFIG );
|
|
|
|
}
|
|
|
|
} // end foreach line of the config
|
|
|
|
fclose( cfg );
|
2004-12-29 00:46:48 +08:00
|
|
|
}
|
2003-11-05 21:50:08 +08:00
|
|
|
|
2008-07-25 01:12:53 +08:00
|
|
|
StaticConfig staticConfig;
|
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
ConfigItem::ConfigItem( const char *p_name, const char *p_value, const char *const p_type ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
name = new char[strlen(p_name)+1];
|
|
|
|
strcpy( name, p_name );
|
|
|
|
value = new char[strlen(p_value)+1];
|
|
|
|
strcpy( value, p_value );
|
|
|
|
type = new char[strlen(p_type)+1];
|
|
|
|
strcpy( type, p_type );
|
2003-11-05 21:50:08 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
//Info( "Created new config item %s = %s (%s)\n", name, value, type );
|
2003-11-05 21:50:08 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
accessed = false;
|
2003-11-05 21:50:08 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
ConfigItem::~ConfigItem() {
|
2016-04-04 22:11:48 +08:00
|
|
|
delete[] name;
|
|
|
|
delete[] value;
|
|
|
|
delete[] type;
|
2003-11-05 21:50:08 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
void ConfigItem::ConvertValue() const {
|
|
|
|
if ( !strcmp( type, "boolean" ) ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
cfg_type = CFG_BOOLEAN;
|
|
|
|
cfg_value.boolean_value = (bool)strtol( value, 0, 0 );
|
2017-05-20 00:24:19 +08:00
|
|
|
} else if ( !strcmp( type, "integer" ) ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
cfg_type = CFG_INTEGER;
|
|
|
|
cfg_value.integer_value = strtol( value, 0, 10 );
|
2017-05-20 00:24:19 +08:00
|
|
|
} else if ( !strcmp( type, "hexadecimal" ) ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
cfg_type = CFG_INTEGER;
|
|
|
|
cfg_value.integer_value = strtol( value, 0, 16 );
|
2017-05-20 00:24:19 +08:00
|
|
|
} else if ( !strcmp( type, "decimal" ) ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
cfg_type = CFG_DECIMAL;
|
|
|
|
cfg_value.decimal_value = strtod( value, 0 );
|
2017-05-20 00:24:19 +08:00
|
|
|
} else {
|
2016-04-04 22:11:48 +08:00
|
|
|
cfg_type = CFG_STRING;
|
|
|
|
cfg_value.string_value = value;
|
|
|
|
}
|
|
|
|
accessed = true;
|
2003-11-05 21:50:08 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
bool ConfigItem::BooleanValue() const {
|
2016-04-04 22:11:48 +08:00
|
|
|
if ( !accessed )
|
|
|
|
ConvertValue();
|
2003-11-05 21:50:08 +08:00
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
if ( cfg_type != CFG_BOOLEAN ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
Error( "Attempt to fetch boolean value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type );
|
|
|
|
exit( -1 );
|
|
|
|
}
|
2003-11-05 21:50:08 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
return( cfg_value.boolean_value );
|
2003-11-05 21:50:08 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
int ConfigItem::IntegerValue() const {
|
2016-04-04 22:11:48 +08:00
|
|
|
if ( !accessed )
|
|
|
|
ConvertValue();
|
2003-11-05 21:50:08 +08:00
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
if ( cfg_type != CFG_INTEGER ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
Error( "Attempt to fetch integer value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type );
|
|
|
|
exit( -1 );
|
|
|
|
}
|
2003-11-05 21:50:08 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
return( cfg_value.integer_value );
|
2003-11-05 21:50:08 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
double ConfigItem::DecimalValue() const {
|
2016-04-04 22:11:48 +08:00
|
|
|
if ( !accessed )
|
|
|
|
ConvertValue();
|
2003-11-05 21:50:08 +08:00
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
if ( cfg_type != CFG_DECIMAL ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
Error( "Attempt to fetch decimal value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type );
|
|
|
|
exit( -1 );
|
|
|
|
}
|
2003-11-05 21:50:08 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
return( cfg_value.decimal_value );
|
2003-11-05 21:50:08 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
const char *ConfigItem::StringValue() const {
|
2016-04-04 22:11:48 +08:00
|
|
|
if ( !accessed )
|
|
|
|
ConvertValue();
|
2003-11-05 21:50:08 +08:00
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
if ( cfg_type != CFG_STRING ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
Error( "Attempt to fetch string value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type );
|
|
|
|
exit( -1 );
|
|
|
|
}
|
2003-11-05 21:50:08 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
return( cfg_value.string_value );
|
2003-11-05 21:50:08 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
Config::Config() {
|
2016-04-04 22:11:48 +08:00
|
|
|
n_items = 0;
|
|
|
|
items = 0;
|
2003-11-05 21:50:08 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
Config::~Config() {
|
|
|
|
if ( items ) {
|
|
|
|
for ( int i = 0; i < n_items; i++ ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
delete items[i];
|
|
|
|
}
|
|
|
|
delete[] items;
|
|
|
|
}
|
2003-11-05 21:50:08 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
void Config::Load() {
|
2016-04-04 22:11:48 +08:00
|
|
|
static char sql[ZM_SQL_SML_BUFSIZ];
|
2010-11-11 20:22:35 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
strncpy( sql, "select Name, Value, Type from Config order by Id", sizeof(sql) );
|
2017-05-20 00:24:19 +08:00
|
|
|
if ( mysql_query( &dbconn, sql ) ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
Error( "Can't run query: %s", mysql_error( &dbconn ) );
|
|
|
|
exit( mysql_errno( &dbconn ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
MYSQL_RES *result = mysql_store_result( &dbconn );
|
2017-05-20 00:24:19 +08:00
|
|
|
if ( !result ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
Error( "Can't use query result: %s", mysql_error( &dbconn ) );
|
|
|
|
exit( mysql_errno( &dbconn ) );
|
|
|
|
}
|
|
|
|
n_items = mysql_num_rows( result );
|
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
if ( n_items <= ZM_MAX_CFG_ID ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
Error( "Config mismatch, expected %d items, read %d. Try running 'zmupdate.pl -f' to reload config.", ZM_MAX_CFG_ID+1, n_items );
|
|
|
|
exit( -1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
items = new ConfigItem *[n_items];
|
2017-05-20 00:24:19 +08:00
|
|
|
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
items[i] = new ConfigItem( dbrow[0], dbrow[1], dbrow[2] );
|
|
|
|
}
|
|
|
|
mysql_free_result( result );
|
2003-11-05 21:50:08 +08:00
|
|
|
}
|
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
void Config::Assign() {
|
2005-05-16 17:27:06 +08:00
|
|
|
ZM_CFG_ASSIGN_LIST
|
|
|
|
}
|
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
const ConfigItem &Config::Item( int id ) {
|
|
|
|
if ( !n_items ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
Load();
|
|
|
|
Assign();
|
|
|
|
}
|
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
if ( id < 0 || id > ZM_MAX_CFG_ID ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
Error( "Attempt to access invalid config, id = %d. Try running 'zmupdate.pl -f' to reload config.", id );
|
|
|
|
exit( -1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
ConfigItem *item = items[id];
|
|
|
|
|
2017-05-20 00:24:19 +08:00
|
|
|
if ( !item ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
Error( "Can't find config item %d", id );
|
|
|
|
exit( -1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
return( *item );
|
2003-11-05 21:50:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Config config;
|