/** @file * @brief The main function. * * * * @copyright Intra2net AG * @license GPLv2 */ #ifdef HAVE_CONFIG_H #include #endif #define PIDFILE "/var/run/bpdyndnsd/bpdyndnsd.pid" #include #include #include #include #include #include #include #include "updater.hpp" using namespace std; Updater::Ptr updater; volatile bool is_online = false; volatile bool webcheck_enabled = false; /** * Checks if a bpdyndnsd process is already running. * @param updater Shared Pointer to updater, needed for logging. * @return 0 if process not running already or pid of already running process. */ int check_for_running_process() { ifstream pidfile(PIDFILE); if ( pidfile.is_open() ) { int pid; pidfile >> pid; if ( pid > 0 ) updater->get_logger()->print_pid_found(pid); else return 0; // check if process still running ret_val==-1 -> not runnig, ret_val==0 -> running if ( kill(pid,0) == 0) { updater->get_logger()->print_process_already_running(pid); pidfile.close(); return pid; } } pidfile.close(); return 0; } /** * Writes the pid into the pidfile. * @param pid The process's 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; } /** * Parent shutdown function * @return 0 if all is fine, -1 otherwise */ int shutdown_parent(bool remove_pid, int ret_val) { // starting shutdown_parent updater->get_logger()->print_starting_shutdown_parent(); // remove pidfile if requested if(remove_pid) unlink(PIDFILE); // shutdown parent complete updater->get_logger()->print_shutdown_parent_succeeded(); // release shared pointer updater.reset(); exit(ret_val); } /** * Shutdown function * @return 0 if all is fine, -1 otherwise */ int shutdown() { int ret_val = 0; // starting shutdown updater->get_logger()->print_starting_shutdown(); // serialize actual service objects if ( updater->get_service_holder()->serialize_services() != 0 ) ret_val = -1; // unlink pidfile unlink(PIDFILE); // shutdown complete updater->get_logger()->print_shutdown_succeeded(); // release shared pointer updater.reset(); return ret_val; } /** * Signal SIGTERM caught, releasing resources and exit. * @param param Parameter from the signal interface. */ void terminate(int param) { updater->get_logger()->print_caught_sigterm(); exit(shutdown()); } /*lint !e715 */ /** * Signal SIGUSR1 caught, switching to offline mode. * @param param Parameter from the signal interface. */ void switch_to_offline(int param) { updater->get_logger()->print_caught_siguser1(); is_online = false; } /*lint !e715 */ /** * Signal SIGHUP caught, reloading config. * @param param Parameter from the signal interface. */ void reload_config(int param) { updater->get_logger()->print_caught_sighup(); if ( updater->reload_config() != 0 ) exit(-1); } /*lint !e715 */ /** * Signal SIGUSR2 caught, switching to online mode. * @param param Parameter from the signal interface. */ void switch_to_online(int param) { updater->get_logger()->print_caught_siguser2(); is_online = true; webcheck_enabled = false; } /*lint !e715 */ /** * Signal SIGRTMIN caught, switching to online mode with webcheck enabled. * @param param Parameter from the signal interface. */ void switch_to_online_webcheck(int param) { updater->get_logger()->print_caught_sigrtmin(); is_online = true; webcheck_enabled = true; } /*lint !e715 */ /** * Initialize the signals we handle. * @return 0 if all is fine, -1 on error. */ 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; } ret_val = signal(SIGUSR2,switch_to_online); if ( ret_val == SIG_ERR ) { updater->get_logger()->print_error_setting_signal("SIGUSR2"); return -1; } ret_val = signal(SIGRTMIN,switch_to_online_webcheck); if ( ret_val == SIG_ERR ) { updater->get_logger()->print_error_setting_signal("SIGRTMIN"); return -1; } return 0; } /** * Try to run in daemon mode if enabled in config. * @param daemon_mode True if process should detach to init (run as daemon), false if not detach to init. * @return 0 if all is fine, -1 on error. */ int init_daemon_mode(bool daemon_mode) { updater->get_logger()->print_daemon_mode(daemon_mode); if ( daemon_mode == true ) { int pid = fork(); if ( pid < 0 ) { // error fork updater->get_logger()->print_error_fork(); return -1; } else if ( pid > 0 ) { // parent continues here if ( write_pidfile(pid) != 0 ) { if ( kill(pid,SIGTERM) != 0 ) { updater->get_logger()->print_error_kill_child(pid); shutdown_parent(false,-1); /*lint !e534 */ } else { updater->get_logger()->print_child_killed(pid); shutdown_parent(true,-1); /*lint !e534 */ } } updater->get_logger()->print_runnig_as_daemon(pid); shutdown_parent(false,0); /*lint !e534 */ } // child starts here } else { if ( write_pidfile(getpid()) != 0 ) { shutdown(); /*lint !e534 */ exit(-1); } } return 0; } /** * @brief The main part. * @param argc Number of arguments * @param argv Command line arguments * @return 0 if all is fine. */ int main(int argc, char *argv[]) { // initialize Updater updater = Updater::Ptr(new Updater); // load config and initialize helper classes if ( updater->load_config(argc,argv) != 0 ) return -1; // open pidfile and check for running process if ( check_for_running_process() != 0) return -1; // init signal handling if ( init_signals() != 0) return -1; // init daemon_mode if enabled if ( init_daemon_mode(updater->get_config()->get_daemon_mode()) != 0 ) return -1; // Should we start in offline mode? is_online = !updater->get_config()->get_start_offline(); webcheck_enabled = updater->get_config()->get_webcheck_enabled(); // service processing starts here do { if ( is_online == true ) { // Check if webcheck_enabled differs due to caught singnal then set it in config correspondingly if ( updater->get_config()->get_webcheck_enabled() != webcheck_enabled ) /*lint !e731 */ updater->get_config()->set_webcheck_enabled(webcheck_enabled); // update all configured services updater->update_services(); } else { // We are in offline mode, do nothing, expect printing "offline mode". updater->get_logger()->print_offline_mode(); } // Snore, snore... don't hog the cpu if we are in daemon_mode. if ( updater->get_config()->get_daemon_mode() == 1 ) sleep(10); /*lint !e534 */ }while ( updater->get_config()->get_daemon_mode() == 1 ); // Serialize services to save their actual state. if ( shutdown() != 0 ) return -1; return 0; }