/*****************************************************************************
 *
 * ICINGA.C - Core Program Code For Icinga
 *
 * Copyright (c) 1999-2009 Ethan Galstad (http://www.nagios.org)
 * Copyright (c) 2009-2013 Nagios Core Development Team and Community Contributors
 * Copyright (c) 2009-2015 Icinga Development Team (http://www.icinga.org)
 *
 * Description:
 *
 * Icinga (Nagios) is a network monitoring tool that will check hosts and services
 * that you specify.  It has the ability to notify contacts via email, pager,
 * or other user-defined methods when a service or host goes down and
 * recovers.  Service and host monitoring is done through the use of external
 * plugins which can be developed independently of Icinga.
 *
 * License:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * 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
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *****************************************************************************/

#include "../include/config.h"
#include "../include/common.h"
#include "../include/objects.h"
#include "../include/comments.h"
#include "../include/downtime.h"
#include "../include/statusdata.h"
#include "../include/macros.h"
#include "../include/icinga.h"
#include "../include/sretention.h"
#include "../include/perfdata.h"
#include "../include/broker.h"
#include "../include/nebmods.h"
#include "../include/nebmodules.h"

/*#define DEBUG_MEMORY 1*/
#ifdef DEBUG_MEMORY
#include <mcheck.h>
#endif


char		*config_file = NULL;
char		*log_file = NULL;
char            *command_file = NULL;
char            *temp_file = NULL;
char            *temp_path = NULL;
char            *check_result_path = NULL;
char            *lock_file = NULL;
char            *log_archive_path = NULL;
char            *p1_file = NULL;  /**** EMBEDDED PERL ****/
char            *auth_file = NULL; /**** EMBEDDED PERL INTERPRETER AUTH FILE ****/
char            *nagios_user = NULL;
char            *nagios_group = NULL;

char            *global_host_event_handler = NULL;
char            *global_service_event_handler = NULL;
command         *global_host_event_handler_ptr = NULL;
command         *global_service_event_handler_ptr = NULL;

char            *ocsp_command = NULL;
char            *ochp_command = NULL;
command         *ocsp_command_ptr = NULL;
command         *ochp_command_ptr = NULL;

char            *illegal_object_chars = NULL;
char            *illegal_output_chars = NULL;
char		illegal_output_char_map[] = CHAR_MAP_INIT(0);

int             use_regexp_matches = FALSE;
int             use_true_regexp_matching = FALSE;

int             use_daemon_log = DEFAULT_USE_DAEMON_LOG;
int		use_syslog = DEFAULT_USE_SYSLOG;
int		use_syslog_local_facility = DEFAULT_USE_SYSLOG_LOCAL_FACILITY;
int		syslog_local_facility = DEFAULT_SYSLOG_LOCAL_FACILITY;
int             log_notifications = DEFAULT_NOTIFICATION_LOGGING;
int             log_service_retries = DEFAULT_LOG_SERVICE_RETRIES;
int             log_host_retries = DEFAULT_LOG_HOST_RETRIES;
int             log_event_handlers = DEFAULT_LOG_EVENT_HANDLERS;
int             log_initial_states = DEFAULT_LOG_INITIAL_STATES;
int             log_current_states = DEFAULT_LOG_CURRENT_STATES;
int             log_external_commands = DEFAULT_LOG_EXTERNAL_COMMANDS;
int             log_passive_checks = DEFAULT_LOG_PASSIVE_CHECKS;
int             log_long_plugin_output = DEFAULT_LOG_LONG_PLUGIN_OUTPUT;
int             log_anonymized_external_command_author = DEFAULT_LOG_ANONYMIZED_EXTERNAL_COMMAND_AUTHOR;

unsigned long   logging_options = 0;
unsigned long   syslog_options = 0;

int             service_check_timeout = DEFAULT_SERVICE_CHECK_TIMEOUT;
int             service_check_timeout_state = STATE_CRITICAL;
int             host_check_timeout = DEFAULT_HOST_CHECK_TIMEOUT;
int             event_handler_timeout = DEFAULT_EVENT_HANDLER_TIMEOUT;
int             notification_timeout = DEFAULT_NOTIFICATION_TIMEOUT;
int             ocsp_timeout = DEFAULT_OCSP_TIMEOUT;
int             ochp_timeout = DEFAULT_OCHP_TIMEOUT;

double          sleep_time = DEFAULT_SLEEP_TIME;
int             interval_length = DEFAULT_INTERVAL_LENGTH;
int             service_inter_check_delay_method = ICD_SMART;
int             host_inter_check_delay_method = ICD_SMART;
int             service_interleave_factor_method = ILF_SMART;
int             max_host_check_spread = DEFAULT_HOST_CHECK_SPREAD;
int             max_service_check_spread = DEFAULT_SERVICE_CHECK_SPREAD;

int             command_check_interval = DEFAULT_COMMAND_CHECK_INTERVAL;
int             check_reaper_interval = DEFAULT_CHECK_REAPER_INTERVAL;
int             max_check_reaper_time = DEFAULT_MAX_REAPER_TIME;
int             service_freshness_check_interval = DEFAULT_FRESHNESS_CHECK_INTERVAL;
int             host_freshness_check_interval = DEFAULT_FRESHNESS_CHECK_INTERVAL;
int             auto_rescheduling_interval = DEFAULT_AUTO_RESCHEDULING_INTERVAL;

int             check_external_commands = DEFAULT_CHECK_EXTERNAL_COMMANDS;
int             check_orphaned_services = DEFAULT_CHECK_ORPHANED_SERVICES;
int             check_orphaned_hosts = DEFAULT_CHECK_ORPHANED_HOSTS;
int             check_service_freshness = DEFAULT_CHECK_SERVICE_FRESHNESS;
int             check_host_freshness = DEFAULT_CHECK_HOST_FRESHNESS;
int             auto_reschedule_checks = DEFAULT_AUTO_RESCHEDULE_CHECKS;
int             auto_rescheduling_window = DEFAULT_AUTO_RESCHEDULING_WINDOW;

int             additional_freshness_latency = DEFAULT_ADDITIONAL_FRESHNESS_LATENCY;

time_t          last_command_check = 0L;
time_t          last_command_status_update = 0L;
time_t          last_log_rotation = 0L;
time_t          last_program_stop = 0L;

int             use_aggressive_host_checking = DEFAULT_AGGRESSIVE_HOST_CHECKING;
unsigned long   cached_host_check_horizon = DEFAULT_CACHED_HOST_CHECK_HORIZON;
unsigned long   cached_service_check_horizon = DEFAULT_CACHED_SERVICE_CHECK_HORIZON;
int             enable_predictive_host_dependency_checks = DEFAULT_ENABLE_PREDICTIVE_HOST_DEPENDENCY_CHECKS;
int             enable_predictive_service_dependency_checks = DEFAULT_ENABLE_PREDICTIVE_SERVICE_DEPENDENCY_CHECKS;

int             soft_state_dependencies = FALSE;

int             retain_state_information = FALSE;
int             retention_update_interval = DEFAULT_RETENTION_UPDATE_INTERVAL;
int             use_retained_program_state = TRUE;
int		dump_retained_host_service_states_to_neb = FALSE;
int             use_retained_scheduling_info = FALSE;
int             retention_scheduling_horizon = DEFAULT_RETENTION_SCHEDULING_HORIZON;
unsigned long   modified_host_process_attributes = MODATTR_NONE;
unsigned long   modified_service_process_attributes = MODATTR_NONE;
unsigned long   retained_host_attribute_mask = 0L;
unsigned long   retained_service_attribute_mask = 0L;
unsigned long   retained_contact_host_attribute_mask = 0L;
unsigned long   retained_contact_service_attribute_mask = 0L;
unsigned long   retained_process_host_attribute_mask = 0L;
unsigned long   retained_process_service_attribute_mask = 0L;

unsigned long   next_comment_id = 0L;
unsigned long   next_downtime_id = 0L;
unsigned long   next_event_id = 0L;
unsigned long   next_problem_id = 0L;
unsigned long   next_notification_id = 0L;

int             log_rotation_method = LOG_ROTATION_NONE;

int             sigshutdown = FALSE;
int             sigrestart = FALSE;
char            *sigs[35] = {"EXIT", "HUP", "INT", "QUIT", "ILL", "TRAP", "ABRT", "BUS", "FPE", "KILL", "USR1", "SEGV", "USR2", "PIPE", "ALRM", "TERM", "STKFLT", "CHLD", "CONT", "STOP", "TSTP", "TTIN", "TTOU", "URG", "XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "IO", "PWR", "UNUSED", "ZERR", "DEBUG", (char *)NULL};
int             caught_signal = FALSE;
int             sig_id = 0;

int             restarting = FALSE;

int             verify_config = 0;
int             verify_object_relationships = TRUE;
int             verify_circular_paths = TRUE;
int             test_scheduling = FALSE;
int             show_schedule = FALSE;
int             precache_objects = FALSE;
int             use_precached_objects = FALSE;

int             daemon_mode = FALSE;
int             daemon_dumps_core = TRUE;

int             max_parallel_service_checks = DEFAULT_MAX_PARALLEL_SERVICE_CHECKS;
int             currently_running_service_checks = 0;
int             currently_running_host_checks = 0;

time_t          program_start = 0L;
time_t          event_start = 0L;
int             nagios_pid = 0;
int             enable_notifications = TRUE;
time_t		disable_notifications_expire_time = 0L;
int             execute_service_checks = TRUE;
int             accept_passive_service_checks = TRUE;
int             execute_host_checks = TRUE;
int             accept_passive_host_checks = TRUE;
int             enable_event_handlers = TRUE;
int             obsess_over_services = FALSE;
int             obsess_over_hosts = FALSE;
int             enable_failure_prediction = TRUE;

int             translate_passive_host_checks = DEFAULT_TRANSLATE_PASSIVE_HOST_CHECKS;
int             passive_host_checks_are_soft = DEFAULT_PASSIVE_HOST_CHECKS_SOFT;

int             aggregate_status_updates = TRUE;
int             status_update_interval = DEFAULT_STATUS_UPDATE_INTERVAL;

int             time_change_threshold = DEFAULT_TIME_CHANGE_THRESHOLD;

unsigned long   event_broker_options = BROKER_NOTHING;

int             process_performance_data = DEFAULT_PROCESS_PERFORMANCE_DATA;

int             enable_flap_detection = DEFAULT_ENABLE_FLAP_DETECTION;

double          low_service_flap_threshold = DEFAULT_LOW_SERVICE_FLAP_THRESHOLD;
double          high_service_flap_threshold = DEFAULT_HIGH_SERVICE_FLAP_THRESHOLD;
double          low_host_flap_threshold = DEFAULT_LOW_HOST_FLAP_THRESHOLD;
double          high_host_flap_threshold = DEFAULT_HIGH_HOST_FLAP_THRESHOLD;

int             use_large_installation_tweaks = DEFAULT_USE_LARGE_INSTALLATION_TWEAKS;
int             enable_environment_macros = TRUE;
int             free_child_process_memory = -1;
int             child_processes_fork_twice = -1;

int             enable_embedded_perl = DEFAULT_ENABLE_EMBEDDED_PERL;
int             use_embedded_perl_implicitly = DEFAULT_USE_EMBEDDED_PERL_IMPLICITLY;
int             embedded_perl_initialized = FALSE;

int             stalking_event_handlers_for_hosts = DEFAULT_STALKING_EVENT_HANDLERS_FOR_HOSTS;
int             stalking_event_handlers_for_services = DEFAULT_STALKING_EVENT_HANDLERS_FOR_SERVICES;
int             stalking_notifications_for_hosts = DEFAULT_STALKING_NOTIFICATIONS_FOR_HOSTS;
int             stalking_notifications_for_services = DEFAULT_STALKING_NOTIFICATIONS_FOR_SERVICES;

int             date_format = DATE_FORMAT_US;
char            *use_timezone = NULL;

int             allow_empty_hostgroup_assignment = DEFAULT_ALLOW_EMPTY_HOSTGROUP_ASSIGNMENT;

int             command_file_fd;
FILE            *command_file_fp;
int             command_file_created = FALSE;

int		keep_unknown_macros = FALSE;

extern contact	       *contact_list;
extern contactgroup    *contactgroup_list;
extern hostgroup       *hostgroup_list;
extern command         *command_list;
extern timeperiod      *timeperiod_list;
extern serviceescalation *serviceescalation_list;
extern module          *module_list;

notification    *notification_list;

check_result    check_result_info;
check_result    *check_result_list = NULL;
unsigned long	max_check_result_file_age = DEFAULT_MAX_CHECK_RESULT_AGE;

dbuf            check_result_dbuf;

circular_buffer external_command_buffer;
circular_buffer check_result_buffer;
pthread_t       worker_threads[TOTAL_WORKER_THREADS];
int             external_command_buffer_slots = DEFAULT_EXTERNAL_COMMAND_BUFFER_SLOTS;

check_stats     check_statistics[MAX_CHECK_STATS_TYPES];

char            *debug_file;
int             debug_level = DEFAULT_DEBUG_LEVEL;
int             debug_verbosity = DEFAULT_DEBUG_VERBOSITY;
unsigned long   max_debug_file_size = DEFAULT_MAX_DEBUG_FILE_SIZE;

unsigned long   max_check_result_list_items = DEFAULT_MAX_CHECK_RESULT_LIST_ITEMS;

int		enable_state_based_escalation_ranges = FALSE;


/* Following main() declaration required by older versions of Perl ut 5.00503 */
int main(int argc, char **argv, char **env) {
	int result;
	int error = FALSE;
	char *buffer = NULL;
	int display_license = FALSE;
	int display_help = FALSE;
	int c = 0;
	struct tm *tm, tm_s;
	time_t now;
	char datestring[256];
	icinga_macros *mac;

#ifdef HAVE_GETOPT_H
	int option_index = 0;
	static struct option long_options[] = {
		{"help", no_argument, 0, 'h'},
		{"version", no_argument, 0, 'V'},
		{"license", no_argument, 0, 'V'},
		{"verify-config", no_argument, 0, 'v'},
		{"daemon", no_argument, 0, 'd'},
		{"test-scheduling", no_argument, 0, 's'},
		{"show-scheduling", no_argument, 0, 'S'},
		{"dont-verify-objects", no_argument, 0, 'o'},
		{"dont-verify-paths", no_argument, 0, 'x'},
		{"precache-objects", no_argument, 0, 'p'},
		{"use-precached-objects", no_argument, 0, 'u'},
		{0, 0, 0, 0}
	};
#endif

	mac = get_global_macros();

	/* make sure we have the correct number of command line arguments */
	if (argc < 2)
		error = TRUE;


	/* get all command line arguments */
	while (1) {

#ifdef HAVE_GETOPT_H
		c = getopt_long(argc, argv, "+hVvdsoxpuS", long_options, &option_index);
#else
		c = getopt(argc, argv, "+hVvdsoxpuS");
#endif

		if (c == -1 || c == EOF)
			break;

		switch (c) {

		case '?': /* usage */
		case 'h':
			display_help = TRUE;
			break;

		case 'V': /* version */
			display_license = TRUE;
			break;

		case 'v': /* verify */
			verify_config++;
			break;

		case 's': /* scheduling check */
			test_scheduling = TRUE;
			break;

		case 'S': /* scheduling check and show queue*/
			show_schedule = TRUE;
			test_scheduling = TRUE;
			break;

		case 'd': /* daemon mode */
			daemon_mode = TRUE;
			break;

		case 'o': /* don't verify objects */
			/*
			verify_object_relationships=FALSE;
			*/
			break;

		case 'x': /* don't verify circular paths */
			verify_circular_paths = FALSE;
			break;

		case 'p': /* precache object config */
			precache_objects = TRUE;
			break;

		case 'u': /* use precached object config */
			use_precached_objects = TRUE;
			break;

		default:
			break;
		}

	}

	/* make sure we have the right combination of arguments */
	if (precache_objects == TRUE && (test_scheduling == FALSE && verify_config == 0)) {
		error = TRUE;
		display_help = TRUE;
	}

#ifdef DEBUG_MEMORY
	mtrace();
#endif

	if (daemon_mode == FALSE) {
		printf("\n%s %s\n", PROGRAM_NAME , PROGRAM_VERSION);
		printf("Copyright (c) 2009-2015 Icinga Development Team (http://www.icinga.org)\n");
		printf("Copyright (c) 2009-2013 Nagios Core Development Team and Community Contributors\n");
		printf("Copyright (c) 1999-2009 Ethan Galstad\n");
		printf("Last Modified: %s\n", PROGRAM_MODIFICATION_DATE);
		printf("License: GPL\n\n");
	}

	/* just display the license */
	if (display_license == TRUE) {

		printf("This program is free software; you can redistribute it and/or modify\n");
		printf("it under the terms of the GNU General Public License version 2 as\n");
		printf("published by the Free Software Foundation.\n\n");
		printf("This program is distributed in the hope that it will be useful,\n");
		printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
		printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
		printf("GNU General Public License for more details.\n\n");
		printf("You should have received a copy of the GNU General Public License\n");
		printf("along with this program; if not, write to the Free Software\n");
		printf("Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\n");

		exit(OK);
	}

	/* make sure we got the main config file on the command line... */
	if (optind >= argc)
		error = TRUE;

	/* if there are no command line options (or if we encountered an error), print usage */
	if (error == TRUE || display_help == TRUE) {

		printf("Usage: %s [options] <main_config_file>\n", argv[0]);
		printf("\n");
		printf("Options:\n");
		printf("\n");
		printf("  -v, --verify-config          Verify all configuration data\n");
		printf("  -s, --test-scheduling        Shows projected/recommended check scheduling and other\n");
		printf("                               diagnostic info based on the current configuration files.\n");
		printf("  -S, --show-scheduling        Same as -s, but also show the scheduling queue\n");
		/*printf("  -o, --dont-verify-objects    Don't verify object relationships - USE WITH CAUTION!\n");*/
		printf("  -x, --dont-verify-paths      Don't check for circular object paths - USE WITH CAUTION!\n");
		printf("  -p, --precache-objects       Precache object configuration - use with -v or -s options\n");
		printf("  -u, --use-precached-objects  Use precached object config file\n");
		printf("  -d, --daemon                 Starts %s in daemon mode, instead of as a foreground process\n", PROGRAM_NAME);
		printf("\n");
		printf("Visit the %s website at http://www.icinga.org/ for bug fixes, new\n", PROGRAM_NAME);
		printf("releases, online documentation, FAQs, information on subscribing to\n");
		printf("the mailing lists, and commercial support options for %s.\n", PROGRAM_NAME);
		printf("\n");

		exit(ERROR);
	}


	/* config file is last argument specified */
	config_file = (char *)strdup(argv[optind]);
	if (config_file == NULL) {
		printf("Error allocating memory.\n");
		exit(ERROR);
	}

	/* make sure the config file uses an absolute path */
	if (config_file[0] != '/') {

		/* save the name of the config file */
		buffer = (char *)strdup(config_file);

		/* reallocate a larger chunk of memory */
		config_file = (char *)realloc(config_file, MAX_FILENAME_LENGTH);
		if (config_file == NULL) {
			printf("Error allocating memory.\n");
			exit(ERROR);
		}

		/* get absolute path of current working directory */
		getcwd(config_file, MAX_FILENAME_LENGTH);

		/* append a forward slash */
		strncat(config_file, "/", 1);
		config_file[MAX_FILENAME_LENGTH-1] = '\x0';

		/* append the config file to the path */
		strncat(config_file, buffer, MAX_FILENAME_LENGTH - strlen(config_file) - 1);
		config_file[MAX_FILENAME_LENGTH-1] = '\x0';

		my_free(buffer);
	}


	/* we're just verifying the configuration... */
	if (verify_config) {

		/* reset program variables */
		reset_variables();

		printf("Reading configuration data...\n");

		/* read in the configuration files (main config file, resource and object config files) */
		if ((result = read_main_config_file(config_file)) == OK) {

			printf("   Read main config file okay...\n");

			/* drop privileges */
			if ((result = drop_privileges(nagios_user, nagios_group)) == ERROR)
				printf("   Failed to drop privileges.  Aborting.");
			else {
				/* read object config files */
				if ((result = read_all_object_data(config_file)) == OK)
					printf("   Read object config files okay...\n");
				else
					printf("   Error processing object config files!\n");
			}
		} else
			printf("   Error processing main config file!\n\n");

		printf("\n");

		/* there was a problem reading the config files */
		if (result != OK) {

			/* if the config filename looks fishy, warn the user */
			if (!strstr(config_file, "nagios.cfg") && !strstr(config_file, "icinga.cfg")) {
				printf("\n***> The name of the main configuration file looks suspicious...\n");
				printf("\n");
				printf("     Make sure you are specifying the name of the MAIN configuration file on\n");
				printf("     the command line and not the name of another configuration file.  The\n");
				printf("     main configuration file is typically '/usr/local/icinga/etc/icinga.cfg'\n");
				printf("     or if using packages, most likely '/etc/icinga/icinga.cfg'\n");
			}

			printf("\n***> One or more problems was encountered while processing the config files...\n");
			printf("\n");
			printf("     Check your configuration file(s) to ensure that they contain valid\n");
			printf("     directives and data definitions.  If you are upgrading from a previous\n");
			printf("     version of %s, you should be aware that some variables/definitions\n", PROGRAM_NAME);
			printf("     may have been removed or modified in this version.  Make sure to read\n");
			printf("     the HTML documentation regarding the config files, as well as the\n");
			printf("     'Whats New' section and the Changelog CHANGES section as well to find\n");
			printf("     out what has changed.\n\n");
		}

		/* the config files were okay, so run the pre-flight check */
		else {

			printf("Running pre-flight check on configuration data...\n\n");

			/* run the pre-flight check to make sure things look okay... */
			result = pre_flight_check();

			if (result == OK)
				printf("\nThings look okay - No serious problems were detected during the pre-flight check\n");
			else {
				printf("\n***> One or more problems was encountered while running the pre-flight check...\n");
				printf("\n");
				printf("     Check your configuration file(s) to ensure that they contain valid\n");
				printf("     directives and data definitions.  If you are upgrading from a previous\n");
				printf("     version of %s, you should be aware that some variables/definitions\n", PROGRAM_NAME);
				printf("     may have been removed or modified in this version.  Make sure to read\n");
				printf("     the HTML documentation regarding the config files, as well as the\n");
				printf("     'Whats New' section to find out what has changed.\n\n");
			}
		}

		/* clean up after ourselves */
		cleanup();

		/* free config_file */
		my_free(config_file);

		/* exit */
		exit(result);
	}


	/* we're just testing scheduling... */
	else if (test_scheduling == TRUE) {

		/* reset program variables */
		reset_variables();

		/* read in the configuration files (main config file and all host config files) */
		result = read_main_config_file(config_file);

		/* drop privileges */
		if (result == OK)
			if ((result = drop_privileges(nagios_user, nagios_group)) == ERROR)
				printf("Failed to drop privileges.  Aborting.");

		/* read object config files */
		if (result == OK)
			result = read_all_object_data(config_file);

		/* read initial service and host state information */
		if (result == OK) {
			initialize_retention_data(config_file);
			read_initial_state_information();
		}

		if (result != OK)
			printf("***> One or more problems was encountered while reading configuration data...\n");

		/* run the pre-flight check to make sure everything looks okay */
		if (result == OK) {
			if ((result = pre_flight_check()) != OK)
				printf("***> One or more problems was encountered while running the pre-flight check...\n");
		}

		if (result == OK) {

			/* initialize the event timing loop */
			init_timing_loop();

			/* display schedule */
			if (show_schedule == TRUE)
				display_schedule();

			/* display scheduling information */
			display_scheduling_info();

			if (precache_objects == TRUE) {
				printf("\n");
				printf("OBJECT PRECACHING\n");
				printf("-----------------\n");
				printf("Object config files were precached.\n");
			}
		}

#undef TEST_TIMEPERIODS
#ifdef TEST_TIMEPERIODS
		/* DO SOME TIMEPERIOD TESTING - ADDED 08/11/2009 */
		time_t now, pref_time, valid_time;
		timeperiod *tp;
		tp = find_timeperiod("247_exclusion");
		time(&now);
		pref_time = now;
		get_next_valid_time(pref_time, &valid_time, tp);
		printf("=====\n");
		printf("CURRENT:   %lu = %s", (unsigned long)now, ctime(&now));
		printf("PREFERRED: %lu = %s", (unsigned long)pref_time, ctime(&pref_time));
		printf("NEXT:      %lu = %s", (unsigned long)valid_time, ctime(&valid_time));
		printf("=====\n");
#endif

		/* clean up after ourselves */
		cleanup();

		/* exit */
		exit(result);
	}


	/* else start to monitor things... */
	else {

		/* keep monitoring things until we get a shutdown command */
		do {

			/* reset program variables */
			reset_variables();

			/* get PID */
			nagios_pid = (int)getpid();

			/* read in the configuration files (main and resource config files) */
			if (read_main_config_file(config_file) == ERROR) {
				logit(NSLOG_PROCESS_INFO | NSLOG_RUNTIME_ERROR | NSLOG_CONFIG_ERROR, TRUE, "Failed to read main config file.  Aborting.");
				cleanup();
				exit(EXIT_FAILURE);
			}

			/* we need to read the modules in the first place as object configuration before neb modules are initialized/loaded */
			result = read_object_config_data(config_file, READ_MODULES, FALSE, FALSE);

			/* add modules to neb */
			result = add_module_objects_to_neb();

			/* NOTE 11/06/07 EG moved to after we read config files, as user may have overridden timezone offset */
			/* get program (re)start time and save as macro */
			program_start = time(NULL);
			my_free(mac->x[MACRO_PROCESSSTARTTIME]);
			asprintf(&mac->x[MACRO_PROCESSSTARTTIME], "%lu", (unsigned long)program_start);

			/* drop privileges */
			if (drop_privileges(nagios_user, nagios_group) == ERROR) {

				logit(NSLOG_PROCESS_INFO | NSLOG_RUNTIME_ERROR | NSLOG_CONFIG_ERROR, TRUE, "Failed to drop privileges.  Aborting.");

				cleanup();
				exit(ERROR);
			}

			/* open debug log */
			open_debug_log();

#ifdef USE_EVENT_BROKER
			/* initialize modules */
			neb_init_modules();
			neb_init_callback_list();
#endif

			/* this must be logged after we read config data, as user may have changed location of main log file */
			logit(NSLOG_PROCESS_INFO, TRUE, "%s %s starting... (PID=%d)\n", PROGRAM_NAME, PROGRAM_VERSION, (int)getpid());

			/* log the local time - may be different than clock time due to timezone offset */
			now = time(NULL);
			tm = localtime_r(&now, &tm_s);
			strftime(datestring, sizeof(datestring), "%a %b %d %H:%M:%S %Z %Y", tm);
			logit(NSLOG_PROCESS_INFO, TRUE, "Local time is %s", datestring);

			/* write log version/info */
			write_log_file_info(NULL);

			/* set up the file descriptor registry, for use by even brokers */
			init_registered_fds();

#ifdef USE_EVENT_BROKER
			/* load modules */
			if (neb_load_all_modules() != OK) {
                logit(NSLOG_CONFIG_ERROR, ERROR, "Error: NEB module loading failed. Aborting.\n");

                if (daemon_dumps_core)
                    neb_unload_all_modules(NEBMODULE_FORCE_UNLOAD, NEBMODULE_NEB_SHUTDOWN);

                exit(EXIT_FAILURE);
            }

			/* forcibly send a program status update
			 * for later updates of PROCESS_* */
			broker_program_status(NEBTYPE_PROGRAMSTATUS_UPDATE, NEBFLAG_NONE, NEBATTR_NONE, NULL);

			/* send program data to broker */
			broker_program_state(NEBTYPE_PROCESS_PRELAUNCH, NEBFLAG_NONE, NEBATTR_NONE, NULL);
#endif

			/* read in all object config data */
			if (result == OK)
				result = read_all_object_data(config_file);

			/* there was a problem reading the config files */
			if (result != OK)
				logit(NSLOG_PROCESS_INFO | NSLOG_RUNTIME_ERROR | NSLOG_CONFIG_ERROR, TRUE, "Bailing out due to one or more errors encountered in the configuration files. Run %s from the command line with the -v option to verify your config before restarting. (PID=%d)", PROGRAM_NAME , (int)getpid());

			else {

				/* run the pre-flight check to make sure everything looks okay*/
				if ((result = pre_flight_check()) != OK)
					logit(NSLOG_PROCESS_INFO | NSLOG_RUNTIME_ERROR | NSLOG_VERIFICATION_ERROR, TRUE, "Bailing out due to errors encountered while running the pre-flight check.  Run %s from the command line with the -v option to verify your config before restarting. (PID=%d)\n", PROGRAM_NAME , (int)getpid());
			}

			/* an error occurred that prevented us from (re)starting */
			if (result != OK) {

				/* if we were restarting, we need to cleanup from the previous run */
				if (sigrestart == TRUE) {

					/* clean up the status data */
					cleanup_status_data(config_file, TRUE);

					/* shutdown the external command worker thread */
					shutdown_command_file_worker_thread();

					/* close and delete the external command file FIFO */
					close_command_file();

					/* cleanup embedded perl interpreter */
					if (embedded_perl_initialized == TRUE)
						deinit_embedded_perl();
				}

#ifdef USE_EVENT_BROKER
				/* send program data to broker */
				broker_program_state(NEBTYPE_PROCESS_SHUTDOWN, NEBFLAG_PROCESS_INITIATED, NEBATTR_SHUTDOWN_ABNORMAL, NULL);
#endif
				cleanup();
				exit(ERROR);
			}



			/* initialize embedded Perl interpreter */
			/* NOTE 02/15/08 embedded Perl must be initialized if compiled in, regardless of whether or not its enabled in the config file */
			/* It compiled it, but not initialized, Icinga will segfault in readdir() calls, as libperl takes this function over */
			if (embedded_perl_initialized == FALSE) {
				/*				if(enable_embedded_perl==TRUE){*/
#ifdef EMBEDDEDPERL
				init_embedded_perl(env);
#else
				init_embedded_perl(NULL);
#endif
				embedded_perl_initialized = TRUE;
				/*					}*/
			}

			/* handle signals (interrupts) */
			setup_sighandler();


#ifdef USE_EVENT_BROKER
			/* send program data to broker */
			broker_program_state(NEBTYPE_PROCESS_START, NEBFLAG_NONE, NEBATTR_NONE, NULL);
#endif

			/* enter daemon mode (unless we're restarting...) */
			if (daemon_mode == TRUE && sigrestart == FALSE) {

				result = daemon_init();

				/* we had an error daemonizing, so bail... */
				if (result == ERROR) {
					logit(NSLOG_PROCESS_INFO | NSLOG_RUNTIME_ERROR, TRUE, "Bailing out due to failure to daemonize. (PID=%d)", (int)getpid());

#ifdef USE_EVENT_BROKER
					/* send program data to broker */
					broker_program_state(NEBTYPE_PROCESS_SHUTDOWN, NEBFLAG_PROCESS_INITIATED, NEBATTR_SHUTDOWN_ABNORMAL, NULL);
#endif
					cleanup();
					exit(ERROR);
				}

				asprintf(&buffer, "Finished daemonizing... (New PID=%d)\n", (int)getpid());
				write_to_all_logs(buffer, NSLOG_PROCESS_INFO);
				my_free(buffer);

				/* get new PID */
				nagios_pid = (int)getpid();
			}

			/* open the command file (named pipe) for reading */
			result = open_command_file();
			if (result != OK) {

				logit(NSLOG_PROCESS_INFO | NSLOG_RUNTIME_ERROR, TRUE, "Bailing out due to errors encountered while trying to initialize the external command file... (PID=%d)\n", (int)getpid());

#ifdef USE_EVENT_BROKER
				/* send program data to broker */
				broker_program_state(NEBTYPE_PROCESS_SHUTDOWN, NEBFLAG_PROCESS_INITIATED, NEBATTR_SHUTDOWN_ABNORMAL, NULL);
#endif
				cleanup();
				exit(ERROR);
			}

			/* initialize status data unless we're starting */
			if (sigrestart == FALSE)
				initialize_status_data(config_file);

			/* read initial service and host state information  */
			initialize_retention_data(config_file);
			read_initial_state_information();
			sync_state_information();

			/* initialize comment data */
			initialize_comment_data(config_file);

			/* initialize scheduled downtime data */
			initialize_downtime_data(config_file);

			/* initialize performance data */
			initialize_performance_data(config_file);

			/* initialize the event timing loop */
			init_timing_loop();

			/* initialize check statistics */
			init_check_stats();

			/* update all status data (with retained information) */
			update_all_status_data();

			/* log initial host and service state */
			log_host_states(INITIAL_STATES, NULL);
			log_service_states(INITIAL_STATES, NULL);

			/* reset the restart flag */
			sigrestart = FALSE;

#ifdef USE_EVENT_BROKER
			/* send program data to broker */
			broker_program_state(NEBTYPE_PROCESS_EVENTLOOPSTART, NEBFLAG_NONE, NEBATTR_NONE, NULL);
#endif

			/* get event start time and save as macro */
			event_start = time(NULL);
			my_free(mac->x[MACRO_EVENTSTARTTIME]);
			asprintf(&mac->x[MACRO_EVENTSTARTTIME], "%lu", (unsigned long)event_start);

			/* print event loop start */
			asprintf(&buffer, "Event loop started...\n");
			write_to_all_logs(buffer, NSLOG_PROCESS_INFO);
			my_free(buffer);

			/***** start monitoring all services *****/
			/* (doesn't return until a restart or shutdown signal is encountered) */
			event_execution_loop();

			/* 03/01/2007 EG Moved from sighandler() to prevent FUTEX locking problems under NPTL */
			/* 03/21/2007 EG SIGSEGV signals are still logged in sighandler() so we don't loose them */
			/* did we catch a signal? */
			if (caught_signal == TRUE) {

				if (sig_id == SIGHUP)
					asprintf(&buffer, "Caught SIGHUP, restarting...\n");
				else if (sig_id != SIGSEGV)
					asprintf(&buffer, "Caught SIG%s, shutting down...\n", sigs[sig_id]);

				write_to_all_logs(buffer, NSLOG_PROCESS_INFO);
				my_free(buffer);
			}

#ifdef USE_EVENT_BROKER
			/* send program data to broker */
			broker_program_state(NEBTYPE_PROCESS_EVENTLOOPEND, NEBFLAG_NONE, NEBATTR_NONE, NULL);
			if (sigshutdown == TRUE)
				broker_program_state(NEBTYPE_PROCESS_SHUTDOWN, NEBFLAG_USER_INITIATED, NEBATTR_SHUTDOWN_NORMAL, NULL);
			else if (sigrestart == TRUE)
				broker_program_state(NEBTYPE_PROCESS_RESTART, NEBFLAG_USER_INITIATED, NEBATTR_RESTART_NORMAL, NULL);
#endif

			/* save service and host state information */
			save_state_information(FALSE);
			cleanup_retention_data(config_file);

			/* clean up performance data */
			cleanup_performance_data(config_file);

			/* clean up the scheduled downtime data */
			cleanup_downtime_data(config_file);

			/* clean up the comment data */
			cleanup_comment_data(config_file);

			/* clean up the status data unless we're restarting */
			if (sigrestart == FALSE)
				cleanup_status_data(config_file, TRUE);

			/* close and delete the external command file FIFO unless we're restarting */
			if (sigrestart == FALSE) {
				shutdown_command_file_worker_thread();
				close_command_file();
			}

			/* cleanup embedded perl interpreter */
			if (sigrestart == FALSE)
				deinit_embedded_perl();

			/* shutdown stuff... */
			if (sigshutdown == TRUE) {

				/* make sure lock file has been removed - it may not have been if we received a shutdown command */
				if (daemon_mode == TRUE)
					unlink(lock_file);

				/* log a shutdown message */
				logit(NSLOG_PROCESS_INFO, TRUE, "Successfully shutdown... (PID=%d)\n", (int)getpid());
			}

			/* clean up after ourselves */
			cleanup();

			/* close debug log */
			close_debug_log();

		} while (sigrestart == TRUE && sigshutdown == FALSE);

		/* free misc memory */
		my_free(config_file);
	}

	return OK;
}


