From 667c672c3a2c2379e40e37dca9bb1ece2708af20 Mon Sep 17 00:00:00 2001 From: Bjoern Sikora Date: Mon, 10 Aug 2009 16:35:06 +0200 Subject: [PATCH] Added and improved some error handling. --- src/config.cpp | 68 ++++++++++++++++++++++++++++++-------------- src/logger.cpp | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/logger.h | 14 ++++++++- src/main.cpp | 55 +++++++++++++++++++++++++----------- src/updater.cpp | 18 +++++++---- src/updater.h | 2 +- 6 files changed, 189 insertions(+), 52 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index 392e5cf..b5f60a5 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -105,14 +105,11 @@ Config::~Config() /** * This function serializes all Service objects in Services and OldServices (where the update Timeout isn't expired) into a specified file. - * @return 0 if all is fine, -1 otherwise. + * @return 0 if all is fine, -1 if output file could not be opened for reading or error while serializing. */ int Config::serialize_services() { - //TODO: error handling - - // First of all we have to put all Service objects in a Serviceholder object. - + // Put Services and OldServices into Serviceholder. Serviceholder::Ptr service_holder(new Serviceholder()); BOOST_FOREACH(Service::Ptr service, Services) @@ -128,8 +125,7 @@ int Config::serialize_services() service_holder->add_service(service); } - // Then we can serialize this separate Object into one file. - + // Serialize Serviceholder into file. ofstream ofs(OBJECT_FILE); if ( ofs.is_open() ) { @@ -148,6 +144,11 @@ int Config::serialize_services() ofs.close(); } + else + { + Log->print_error_opening_rw(OBJECT_FILE); + return -1; + } Log->print_serialized_objects_success(); @@ -155,32 +156,51 @@ int Config::serialize_services() } +/** + * This function de-serializes the Serviceholder (containing Services) from the object file. + * @return 0 if all is fine, -1 if object file couldn't be opened for reading or error while de-serializing. + */ int Config::deserialize_services() { - // TODO: error handling - // TODO: redefine algorithm, to avoid tripple FOREACHes ;-) + // test if OBJECT_FILE exists + fs::path object_file = fs::system_complete(fs::path(OBJECT_FILE)); + if ( !fs::exists(object_file) ) + { + // There is no object file, possibly first program start, continue without recovering old Services' state. + Log->print_no_object_file(OBJECT_FILE); + return 0; + } ifstream ifs(OBJECT_FILE); if ( ifs.is_open() ) { + // deserialize Serviceholder Serviceholder* _service_holder; - boost::archive::text_iarchive ia(ifs); - ia >> _service_holder; // ends up in default constructor call for Serviceholder + try + { + boost::archive::text_iarchive ia(ifs); + ia >> _service_holder; // ends up in default constructor call for Serviceholder + } + catch( boost::archive::archive_exception e ) + { + Log->print_exception_deserialize(e.what()); + ifs.close(); + return -1; + } Serviceholder::Ptr service_holder(_service_holder); ifs.close(); + // Get the list of old Services from de-serialized Serviceholder object. list _old_services = service_holder->get_hold_services(); + // Put all de-serialized Services into OldServices member and + // compare new Services (generated from config file and cmd) with old Services (de-serialized from object file) + // if identical Service was found, adopt the value from old Service to recover Services' state. BOOST_FOREACH(Service::Ptr old_service, _old_services) { - // Put the deserialized service into the Old_service member list. OldServices.push_back(old_service); Log->print_service_object("Deserialized following Service object:", old_service->get_protocol(), old_service->get_hostname(), old_service->get_login() ,old_service->get_password() ,old_service->get_actual_ip(), old_service->get_lastupdated()); - } - - BOOST_FOREACH(Service::Ptr service, Services) - { - BOOST_FOREACH(Service::Ptr old_service, OldServices) + BOOST_FOREACH(Service::Ptr service, Services) { if ( *service == *old_service ) { @@ -193,12 +213,12 @@ int Config::deserialize_services() } } } - //TODO: debug output of OldServices (is element really removed from list if values were adopted???) Log->print_deserialized_objects_success(); } else { - Log->print_error_opening(OBJECT_FILE); + Log->print_error_opening_r(OBJECT_FILE); + return -1; } return 0; @@ -361,7 +381,7 @@ int Config::load_service_config_file(const string& full_filename) else { // error opening service config file for reading - Log->print_error_opening(full_filename); + Log->print_error_opening_r(full_filename); return 1; } return 0; @@ -405,7 +425,7 @@ int Config::load_main_config_file(const string& full_filename) else { // error opening main config file for reading - Log->print_error_opening(full_filename); + Log->print_error_opening_r(full_filename); return 1; } return 0; @@ -521,6 +541,12 @@ void Config::delete_services() service.reset(); } Services.clear(); + + BOOST_FOREACH( Service::Ptr service, OldServices ) + { + service.reset(); + } + OldServices.clear(); } diff --git a/src/logger.cpp b/src/logger.cpp index e3499b2..f8d936e 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -173,6 +173,17 @@ void Logger::print_cmd_parsed() } +void Logger::print_conf_files_parsed() +{ + if ( 1 <= Loglevel ) + { + ostringstream msg; + msg << "Config files successfully parsed." << endl; + log_notice(msg.str()); + } +} + + /** * Prints out the successful parsing of the config files. * @param config_path The specified config path. @@ -207,7 +218,7 @@ void Logger::print_conf_not_loaded(const string& config_path) * A file could not be opened for reading. * @param filename The filename. */ -void Logger::print_error_opening(const string& filename) +void Logger::print_error_opening_r(const string& filename) { if ( 0 <= Loglevel ) { @@ -219,6 +230,21 @@ void Logger::print_error_opening(const string& filename) /** + * A file could not be opened for writing. + * @param filename The filename. + */ +void Logger::print_error_opening_rw(const string& filename) +{ + if ( 0 <= Loglevel ) + { + ostringstream msg; + msg << "Error opening file for writing: " << filename << endl; + log_error(msg.str()); + } +} + + +/** * Desctructor of specified class was called. * @param _class Name of the class. */ @@ -504,12 +530,12 @@ void Logger::print_caught_sighup() /** * Error while setting signal handler. */ -void Logger::print_error_setting_signal() +void Logger::print_error_setting_signal(const string& signal) { if ( 0 <= Loglevel ) { ostringstream msg; - msg << "Error while setting signal handler." << endl; + msg << "Error while setting signal handler for: " << signal << endl; log_error(msg.str()); } } @@ -604,5 +630,55 @@ void Logger::print_service_object(const string& message, const string& protocol, */ void Logger::print_exception_serialize(const string& exception) { - cout << "Error while trying to serialize Serviceholder object: " << exception << endl; + if ( 0 <= Loglevel ) + { + ostringstream msg; + msg << "Error while trying to serialize Serviceholder object: " << exception << endl; + log_error(msg.str()); + } +} + + +/** + * Caught exception while de-serialize. + * @param exception Exception message. + */ +void Logger::print_exception_deserialize(const std::string& exception) +{ + if ( 0 <= Loglevel ) + { + ostringstream msg; + msg << "Error while trying to de-serialize Serviceholder object: " << exception << endl; + log_error(msg.str()); + } +} + + +/** + * Child couldn't be killed by parent. + * @param pid Pid of the child. + */ +void Logger::print_error_kill_child(const int pid) +{ + if ( 0 <= Loglevel ) + { + ostringstream msg; + msg << "Could not kill child process with PID: " << pid << endl; + log_error(msg.str()); + } +} + + +/** + * There is no object file. + * @param object_file The object file. + */ +void Logger::print_no_object_file(const std::string& object_file) +{ + if ( 1 <= Loglevel ) + { + ostringstream msg; + msg << "There is no object file: " << object_file << ". Continue without recovering state from old services!" << endl; + log_warning(msg.str()); + } } diff --git a/src/logger.h b/src/logger.h index caf7083..eb1fa29 100644 --- a/src/logger.h +++ b/src/logger.h @@ -55,6 +55,8 @@ public: void print_cmd_parsed(); + void print_conf_files_parsed(); + void print_destructor_call(const std::string&); void print_constructor_call(const std::string&); @@ -73,7 +75,9 @@ public: void print_unknown_main_conf_option(const std::string&); - void print_error_opening(const std::string&); + void print_error_opening_r(const std::string&); + + void print_error_opening_rw(const std::string&); void print_error_config_path(const std::string&); @@ -99,7 +103,7 @@ public: void print_caught_sighup(); - void print_error_setting_signal(); + void print_error_setting_signal(const std::string&); void print_init_log_facility(); @@ -112,6 +116,12 @@ public: void print_service_object(const std::string&, const std::string&, const std::string&, const std::string&, const std::string&, const std::string&, const int); void print_exception_serialize(const std::string&); + + void print_exception_deserialize(const std::string&); + + void print_error_kill_child(const int); + + void print_no_object_file(const std::string&); }; #endif diff --git a/src/main.cpp b/src/main.cpp index 2236b77..bd354b2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -76,14 +76,20 @@ int check_for_running_process() * Writes the pid into the pidfile. * @param pid The process's pid. */ -void write_pidfile(int pid) +int write_pidfile(int pid) { ofstream pidfile(PIDFILE); if ( pidfile.is_open() ) { pidfile << pid << endl; } + else + { + updater->get_logger()->print_error_opening_rw(PIDFILE); + return -1; + } pidfile.close(); + return 0; } @@ -97,7 +103,11 @@ void terminate(int param) // unfortunately we can't call serialize_services in any destructor // cause some singleton are already destroyed !?! - updater->get_config()->serialize_services(); + if ( updater->get_config()->serialize_services() != 0 ) + { + updater.reset(); + exit(-1); + } updater.reset(); exit(0); } @@ -122,7 +132,8 @@ void switch_to_offline(int param) void reload_config(int param) { updater->get_logger()->print_caught_sighup(); - updater->reload_config(); + if ( updater->reload_config() != 0 ) + exit(-1); is_online = true; } @@ -135,13 +146,22 @@ int init_signals() sighandler_t ret_val; ret_val = signal(SIGTERM,terminate); if ( ret_val == SIG_ERR ) + { + updater->get_logger()->print_error_setting_signal("SIGTERM"); return -1; + } ret_val = signal(SIGUSR1,switch_to_offline); if ( ret_val == SIG_ERR ) + { + updater->get_logger()->print_error_setting_signal("SIGUSR1"); return -1; + } ret_val = signal(SIGHUP,reload_config); if ( ret_val == SIG_ERR ) + { + updater->get_logger()->print_error_setting_signal("SIGHUP"); return -1; + } return 0; } @@ -160,28 +180,23 @@ int main(int argc, char *argv[]) updater = _updater; _updater.reset(); - // TODO: Why do errors return zero exit status? - // load the cmd options if ( updater->init_config_from_cmd(argc,argv) != 0 ) - return 0; + return -1; // load the config and service files if ( updater->init_config_from_files() != 0 ) - return 0; + return -1; // open pidfile and check for running process if ( check_for_running_process() != 0) - return 0; + return -1; // init signal handling if ( init_signals() != 0) - { - updater->get_logger()->print_error_setting_signal(); - return 0; - } + return -1; - // initialize daemon mode if configured + // initialize daemon mode if configured TODO: into separate function updater->get_logger()->print_daemon_mode(updater->get_config()->get_daemon_mode()); if ( updater->get_config()->get_daemon_mode() == 1 ) { @@ -190,12 +205,17 @@ int main(int argc, char *argv[]) { // error fork updater->get_logger()->print_error_fork(); - return 0; + return -1; } else if ( pid > 0 ) { // parent - write_pidfile(pid); + if ( write_pidfile(pid) != 0 ) + { + if ( kill(pid,SIGTERM) != 0 ) + updater->get_logger()->print_error_kill_child(pid); + return -1; + } updater->get_logger()->print_runnig_as_daemon(pid); return 0; } @@ -221,8 +241,9 @@ int main(int argc, char *argv[]) }while ( updater->get_config()->get_daemon_mode() == 1 ); - // serialize services - updater->get_config()->serialize_services(); + // serialize services to save their actual status + if ( updater->get_config()->serialize_services() != 0 ) + return -1; return 0; } diff --git a/src/updater.cpp b/src/updater.cpp index 94c6e00..83bf3ed 100644 --- a/src/updater.cpp +++ b/src/updater.cpp @@ -46,7 +46,7 @@ int Updater::init_config_from_cmd(int argc, char *argv[]) { // Load the command line parameters if( Conf->parse_cmd_line( argc, argv ) != 0) - return 1; + return -1; // If we have loaded the cmd options we need to init the log facility immediately in case debugging is enabled from cmd. init_log_facility(); @@ -65,7 +65,7 @@ int Updater::init_config_from_files() { // Load the main and service config files in config path if ( Conf->load_config_from_files() != 0 ) - return 1; + return -1; // Re-init log facility, perhaps new config file options for logger are set. // These config file options will only overwrite the cmd options if the SIGHUP (reload config) is caught. @@ -73,9 +73,10 @@ int Updater::init_config_from_files() // Here we are. All Service Objects should be initialized, so it is time to deserialize the old service objects and compare them. if ( Conf->deserialize_services() != 0 ) - return 1; + return -1; // successful loaded + Log->print_conf_files_parsed(); return 0; } @@ -103,10 +104,11 @@ Logger::Ptr Updater::get_logger() /** * Reloading the config. Delete all Service objects and then init new Service objects from config files. */ -void Updater::reload_config() +int Updater::reload_config() { // serialize all service objects - Conf->serialize_services(); + if ( Conf->serialize_services() != 0 ) + return -1; // delete all service objects Conf->delete_services(); @@ -115,8 +117,10 @@ void Updater::reload_config() Conf->delete_variables_map(); // load only config files - // TODO: Error handling? - init_config_from_files(); + if ( init_config_from_files() != 0 ) + return -1; + + return 0; } diff --git a/src/updater.h b/src/updater.h index cb5371d..13bec10 100644 --- a/src/updater.h +++ b/src/updater.h @@ -42,7 +42,7 @@ public: Logger::Ptr get_logger(); - void reload_config(); + int reload_config(); void init_log_facility(); }; -- 1.7.1