Ejemplo n.º 1
0
/* handles a host that is flapping */
void set_host_flap(host *hst, double percent_change, double high_threshold, double low_threshold)
{
	char *temp_buffer = NULL;

	if (hst == NULL)
		return;

	log_debug_info(DEBUGL_FLAPPING, 1, "Host '%s' started flapping!\n", hst->name);

	/* log a notice - this one is parsed by the history CGI */
	nm_log(NSLOG_RUNTIME_WARNING, "HOST FLAPPING ALERT: %s;STARTED; Host appears to have started flapping (%2.1f%% change > %2.1f%% threshold)\n", hst->name, percent_change, high_threshold);

	/* add a non-persistent comment to the host */
	nm_asprintf(&temp_buffer, "Notifications for this host are being suppressed because it was detected as having been flapping between different states (%2.1f%% change > %2.1f%% threshold).  When the host state stabilizes and the flapping stops, notifications will be re-enabled.", percent_change, high_threshold);
	add_new_host_comment(FLAPPING_COMMENT, hst->name, time(NULL), "(Naemon Process)", temp_buffer, 0, COMMENTSOURCE_INTERNAL, FALSE, (time_t)0, &(hst->flapping_comment_id));
	nm_free(temp_buffer);

	/* set the flapping indicator */
	hst->is_flapping = TRUE;

	broker_flapping_data(NEBTYPE_FLAPPING_START, NEBFLAG_NONE, NEBATTR_NONE, HOST_FLAPPING, hst, percent_change, high_threshold, low_threshold);

	/* see if we should check to send a recovery notification out when flapping stops */
	if (hst->current_state != STATE_UP && hst->current_notification_number > 0)
		hst->check_flapping_recovery_notification = TRUE;
	else
		hst->check_flapping_recovery_notification = FALSE;

	/* send a notification */
	host_notification(hst, NOTIFICATION_FLAPPINGSTART, NULL, NULL, NOTIFICATION_OPTION_NONE);

	return;
}
Ejemplo n.º 2
0
/* sets or unsets an environment variable */
int set_environment_var(char *name, char *value, int set)
{
#ifndef HAVE_SETENV
	char *env_string = NULL;
#endif

	/* we won't mess with null variable names */
	if (name == NULL)
		return ERROR;

	/* set the environment variable */
	if (set == TRUE) {

#ifdef HAVE_SETENV
		setenv(name, (value == NULL) ? "" : value, 1);
#else
		/* needed for Solaris and systems that don't have setenv() */
		/* this will leak memory, but in a "controlled" way, since lost memory should be freed when the child process exits */
		nm_asprintf(&env_string, "%s=%s", name, (value == NULL) ? "" : value);
		if (env_string)
			putenv(env_string);
#endif
	}
	/* clear the variable */
	else {
#ifdef HAVE_UNSETENV
		unsetenv(name);
#endif
	}

	return OK;
}
Ejemplo n.º 3
0
static int test_path_access(const char *program, int mode)
{
	char *envpath, *p, *colon;
	int ret, our_errno = 1500; /* outside errno range */

	if (program[0] == '/' || !(envpath = getenv("PATH")))
		return access(program, mode);

	if (!(envpath = strdup(envpath))) {
		errno = ENOMEM;
		return -1;
	}

	for (p = envpath; p; p = colon + 1) {
		char *path;

		colon = strchr(p, ':');
		if (colon)
			*colon = 0;
		nm_asprintf(&path, "%s/%s", p, program);
		ret = access(path, mode);
		free(path);
		if (!ret)
			break;

		if (ret < 0) {
			if (errno == ENOENT)
				continue;
			if (our_errno > errno)
				our_errno = errno;
		}
		if (!colon)
			break;
	}

	free(envpath);

	if (!ret)
		errno = 0;
	else
		errno = our_errno;

	return ret;
}
Ejemplo n.º 4
0
/* handles a service that is flapping */
void set_service_flap(service *svc, double percent_change, double high_threshold, double low_threshold, int allow_flapstart_notification)
{
	char *temp_buffer = NULL;

	log_debug_info(DEBUGL_FUNCTIONS, 0, "set_service_flap()\n");

	if (svc == NULL)
		return;

	log_debug_info(DEBUGL_FLAPPING, 1, "Service '%s' on host '%s' started flapping!\n", svc->description, svc->host_name);

	/* log a notice - this one is parsed by the history CGI */
	logit(NSLOG_RUNTIME_WARNING, FALSE, "SERVICE FLAPPING ALERT: %s;%s;STARTED; Service appears to have started flapping (%2.1f%% change >= %2.1f%% threshold)\n", svc->host_name, svc->description, percent_change, high_threshold);

	/* add a non-persistent comment to the service */
	nm_asprintf(&temp_buffer, "Notifications for this service are being suppressed because it was detected as having been flapping between different states (%2.1f%% change >= %2.1f%% threshold).  When the service state stabilizes and the flapping stops, notifications will be re-enabled.", percent_change, high_threshold);
	add_new_service_comment(FLAPPING_COMMENT, svc->host_name, svc->description, time(NULL), "(Naemon Process)", temp_buffer, 0, COMMENTSOURCE_INTERNAL, FALSE, (time_t)0, &(svc->flapping_comment_id));
	my_free(temp_buffer);

	/* set the flapping indicator */
	svc->is_flapping = TRUE;

#ifdef USE_EVENT_BROKER
	/* send data to event broker */
	broker_flapping_data(NEBTYPE_FLAPPING_START, NEBFLAG_NONE, NEBATTR_NONE, SERVICE_FLAPPING, svc, percent_change, high_threshold, low_threshold, NULL);
#endif

	/* see if we should check to send a recovery notification out when flapping stops */
	if (svc->current_state != STATE_OK && svc->current_notification_number > 0)
		svc->check_flapping_recovery_notification = TRUE;
	else
		svc->check_flapping_recovery_notification = FALSE;

	/* send a notification */
	if (allow_flapstart_notification == TRUE)
		service_notification(svc, NOTIFICATION_FLAPPINGSTART, NULL, NULL, NOTIFICATION_OPTION_NONE);

	return;
}
Ejemplo n.º 5
0
/* runs a host event handler command */
static int run_host_event_handler(nagios_macros *mac, const host * const hst)
{
	char *raw_command = NULL;
	char *processed_command = NULL;
	char *raw_logentry = NULL;
	char *processed_logentry = NULL;
	char *command_output = NULL;
	int early_timeout = FALSE;
	double exectime = 0.0;
	int result = 0;
	struct timeval start_time;
	struct timeval end_time;
	int neb_result = OK;
	int macro_options = STRIP_ILLEGAL_MACRO_CHARS | ESCAPE_MACRO_CHARS;

	if (hst == NULL)
		return ERROR;

	/* bail if there's no command */
	if (hst->event_handler == NULL)
		return ERROR;

	log_debug_info(DEBUGL_EVENTHANDLERS, 1, "Running event handler for host '%s'..\n", hst->name);

	/* get start time */
	gettimeofday(&start_time, NULL);

	get_raw_command_line_r(mac, hst->event_handler_ptr, hst->event_handler, &raw_command, macro_options);
	if (raw_command == NULL)
		return ERROR;

	log_debug_info(DEBUGL_EVENTHANDLERS, 2, "Raw host event handler command line: %s\n", raw_command);

	/* process any macros in the raw command line */
	process_macros_r(mac, raw_command, &processed_command, macro_options);
	nm_free(raw_command);
	if (processed_command == NULL)
		return ERROR;

	log_debug_info(DEBUGL_EVENTHANDLERS, 2, "Processed host event handler command line: %s\n", processed_command);

	if (log_event_handlers == TRUE) {
		nm_asprintf(&raw_logentry, "HOST EVENT HANDLER: %s;$HOSTSTATE$;$HOSTSTATETYPE$;$HOSTATTEMPT$;%s\n", hst->name, hst->event_handler);
		process_macros_r(mac, raw_logentry, &processed_logentry, macro_options);
		nm_log(NSLOG_EVENT_HANDLER, "%s", processed_logentry);
	}

	end_time.tv_sec = 0L;
	end_time.tv_usec = 0L;
	neb_result = broker_event_handler(NEBTYPE_EVENTHANDLER_START, NEBFLAG_NONE, NEBATTR_NONE, HOST_EVENTHANDLER, (void *)hst, hst->current_state, hst->state_type, start_time, end_time, exectime, event_handler_timeout, early_timeout, result, hst->event_handler, processed_command, NULL);

	/* neb module wants to override (or cancel) the event handler - perhaps it will run the eventhandler itself */
	if (neb_result == NEBERROR_CALLBACKOVERRIDE) {
		nm_free(processed_command);
		nm_free(raw_logentry);
		nm_free(processed_logentry);
		return OK;
	}

	/* run the command through a worker */
	result = wproc_run_callback(processed_command, event_handler_timeout, event_handler_job_handler, "Host", mac);

	/* check to see if the event handler timed out */
	if (early_timeout == TRUE)
		nm_log(NSLOG_EVENT_HANDLER | NSLOG_RUNTIME_WARNING, "Warning: Host event handler command '%s' timed out after %d seconds\n", processed_command, event_handler_timeout);

	/* get end time */
	gettimeofday(&end_time, NULL);

	broker_event_handler(NEBTYPE_EVENTHANDLER_END, NEBFLAG_NONE, NEBATTR_NONE, HOST_EVENTHANDLER, (void *)hst, hst->current_state, hst->state_type, start_time, end_time, exectime, event_handler_timeout, early_timeout, result, hst->event_handler, processed_command, command_output);

	nm_free(command_output);
	nm_free(processed_command);
	nm_free(raw_logentry);
	nm_free(processed_logentry);

	return OK;
}
Ejemplo n.º 6
0
/* runs the global service event handler */
static int run_global_service_event_handler(nagios_macros *mac, service *svc)
{
	char *raw_command = NULL;
	char *processed_command = NULL;
	char *raw_logentry = NULL;
	char *processed_logentry = NULL;
	char *command_output = NULL;
	int early_timeout = FALSE;
	double exectime = 0.0;
	int result = 0;
	struct timeval start_time;
	struct timeval end_time;
	int neb_result = OK;
	int macro_options = STRIP_ILLEGAL_MACRO_CHARS | ESCAPE_MACRO_CHARS;

	if (svc == NULL)
		return ERROR;

	/* bail out if we shouldn't be running event handlers */
	if (enable_event_handlers == FALSE)
		return OK;

	/* a global service event handler command has not been defined */
	if (global_service_event_handler == NULL)
		return ERROR;

	log_debug_info(DEBUGL_EVENTHANDLERS, 1, "Running global event handler for service '%s' on host '%s'...\n", svc->description, svc->host_name);

	/* get start time */
	gettimeofday(&start_time, NULL);

	get_raw_command_line_r(mac, global_service_event_handler_ptr, global_service_event_handler, &raw_command, macro_options);
	if (raw_command == NULL) {
		return ERROR;
	}

	log_debug_info(DEBUGL_EVENTHANDLERS, 2, "Raw global service event handler command line: %s\n", raw_command);

	/* process any macros in the raw command line */
	process_macros_r(mac, raw_command, &processed_command, macro_options);
	nm_free(raw_command);
	if (processed_command == NULL)
		return ERROR;

	log_debug_info(DEBUGL_EVENTHANDLERS, 2, "Processed global service event handler command line: %s\n", processed_command);

	if (log_event_handlers == TRUE) {
		nm_asprintf(&raw_logentry, "GLOBAL SERVICE EVENT HANDLER: %s;%s;$SERVICESTATE$;$SERVICESTATETYPE$;$SERVICEATTEMPT$;%s\n", svc->host_name, svc->description, global_service_event_handler);
		process_macros_r(mac, raw_logentry, &processed_logentry, macro_options);
		nm_log(NSLOG_EVENT_HANDLER, "%s", processed_logentry);
	}

	end_time.tv_sec = 0L;
	end_time.tv_usec = 0L;
	neb_result = broker_event_handler(NEBTYPE_EVENTHANDLER_START, NEBFLAG_NONE, NEBATTR_NONE, GLOBAL_SERVICE_EVENTHANDLER, (void *)svc, svc->current_state, svc->state_type, start_time, end_time, exectime, event_handler_timeout, early_timeout, result, global_service_event_handler, processed_command, NULL);

	/* neb module wants to override (or cancel) the event handler - perhaps it will run the eventhandler itself */
	if (neb_result == NEBERROR_CALLBACKOVERRIDE) {
		nm_free(processed_command);
		nm_free(raw_logentry);
		nm_free(processed_logentry);
		return OK;
	}

	/* run the command through a worker */
	result = wproc_run_callback(processed_command, event_handler_timeout, event_handler_job_handler, "Global service", mac);

	/* check to see if the event handler timed out */
	if (early_timeout == TRUE)
		nm_log(NSLOG_EVENT_HANDLER | NSLOG_RUNTIME_WARNING, "Warning: Global service event handler command '%s' timed out after %d seconds\n", processed_command, event_handler_timeout);

	/* get end time */
	gettimeofday(&end_time, NULL);

	broker_event_handler(NEBTYPE_EVENTHANDLER_END, NEBFLAG_NONE, NEBATTR_NONE, GLOBAL_SERVICE_EVENTHANDLER, (void *)svc, svc->current_state, svc->state_type, start_time, end_time, exectime, event_handler_timeout, early_timeout, result, global_service_event_handler, processed_command, command_output);

	nm_free(command_output);
	nm_free(processed_command);
	nm_free(raw_logentry);
	nm_free(processed_logentry);

	return OK;
}
Ejemplo n.º 7
0
int main(int argc, char **argv)
{
	int result;
	int error = FALSE;
	int display_license = FALSE;
	int display_help = FALSE;
	int c = 0;
	int allow_root = FALSE;
	struct tm *tm, tm_s;
	time_t now;
	char datestring[256];
	nagios_macros *mac;
	const char *worker_socket = NULL;
	int i;

#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'},
		{"precache-objects", no_argument, 0, 'p'},
		{"use-precached-objects", no_argument, 0, 'u'},
		{"enable-timing-point", no_argument, 0, 'T'},
		{"worker", required_argument, 0, 'W'},
		{"allow-root", no_argument, 0, 'R'},
		{0, 0, 0, 0}
	};
#define getopt(argc, argv, o) getopt_long(argc, argv, o, long_options, &option_index)
#endif

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

	/* get all command line arguments */
	while (1) {
		c = getopt(argc, argv, "+hVvdspuxTW");

		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 */
			printf("Warning: -s is deprecated and will be removed\n");
			break;

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

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

		case 'u': /* use precached object config */
			use_precached_objects = TRUE;
			break;
		case 'T':
			enable_timing_point = TRUE;
			break;
		case 'W':
			worker_socket = optarg;
			break;
		case 'R':
			allow_root = TRUE;
			break;

		case 'x':
			printf("Warning: -x is deprecated and will be removed\n");
			break;

		default:
			break;
		}

	}

	/* Make all GLib domain messages go to the usual places. This also maps
	 * GLib levels to an approximation of their corresponding Naemon levels
	 * (including debug).
	 *
	 * Note that because of the GLib domain restriction, log messages from
	 * other domains (such as if we did g_message(...) ourselves from inside
	 * Naemon) do not currently go to this handler.
	 **/
	nm_g_log_handler_id = g_log_set_handler("GLib", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL |
			G_LOG_FLAG_RECURSION, nm_g_log_handler, NULL);
	mac = get_global_macros();

	/* if we're a worker we can skip everything below */
	if (worker_socket) {
		exit(nm_core_worker(worker_socket));
	}

	if (daemon_mode == FALSE) {
		printf("\nNaemon Core " VERSION "\n");
		printf("Copyright (c) 2013-present Naemon Core Development Team and Community Contributors\n");
		printf("Copyright (c) 2009-2013 Nagios Core Development Team and Community Contributors\n");
		printf("Copyright (c) 1999-2009 Ethan Galstad\n");
		printf("License: GPL\n\n");
		printf("Website: http://www.naemon.org\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., 675 Mass Ave, Cambridge, MA 02139, 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 (-v -v for more info)\n");
		printf("  -T, --enable-timing-point    Enable timed commentary on initialization\n");
		printf("  -x, --dont-verify-paths      Deprecated (Don't check for circular object paths)\n");
		printf("  -p, --precache-objects       Precache object configuration\n");
		printf("  -u, --use-precached-objects  Use precached object config file\n");
		printf("  -d, --daemon                 Starts Naemon in daemon mode, instead of as a foreground process\n");
		printf("  -W, --worker /path/to/socket Act as a worker for an already running daemon\n");
		printf("  --allow-root                 Let naemon run as root. THIS IS NOT RECOMMENDED AT ALL.\n");
		printf("\n");
		printf("Visit the Naemon website at http://www.naemon.org/ for bug fixes, new\n");
		printf("releases, online documentation, FAQs and more...\n");
		printf("\n");

		exit(ERROR);
	}

	if (getuid() == 0) {
		if (allow_root == FALSE) {
			printf("ERROR: do not start naemon as root user.\n");
			exit(EXIT_FAILURE);
		} else {
			printf("WARNING: you are running as root which is not recommended.\n");
		}
	}



	/*
	 * config file is last argument specified.
	 * Make sure it uses an absolute path
	 */
	config_file = nspath_absolute(argv[optind], NULL);
	if (config_file == NULL) {
		printf("Error allocating memory.\n");
		exit(ERROR);
	}

	config_file_dir = nspath_absolute_dirname(config_file, NULL);

	/*
	 * Set the signal handler for the SIGXFSZ signal here because
	 * we may encounter this signal before the other signal handlers
	 * are set.
	 */
	signal(SIGXFSZ, sighandler);


	/*
	 * Setup rand and srand. Don't bother with better resolution than second
	 */
	srand(time(NULL));

	/*
	 * let's go to town. We'll be noisy if we're verifying config
	 * or running scheduling tests.
	 */
	if (verify_config || precache_objects) {
		reset_variables();

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

		/* read our config file */
		result = read_main_config_file(config_file);
		if (result != OK) {
			printf("   Error processing main config file!\n\n");
			exit(EXIT_FAILURE);
		}

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

		/*
		 * this must come after dropping privileges, so we make
		 * sure to test access permissions as the right user.
		 */
		if (test_configured_paths() == ERROR) {
			printf("   One or more path problems detected. Aborting.\n");
			exit(EXIT_FAILURE);
		}

		/* read object config files */
		result = read_all_object_data(config_file);
		if (result != OK) {
			printf("   Error processing object config files!\n\n");
			/* if the config filename looks fishy, warn the user */
			if (!strstr(config_file, "naemon.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 '%s'\n", get_default_config_file());
			}

			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 Naemon, you should be aware that some variables/definitions\n");
			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");
			exit(EXIT_FAILURE);
		}

		if (verify_config) {
			printf("   Read object config files okay...\n\n");
			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("\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 Naemon, you should be aware that some variables/definitions\n");
			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");
			exit(EXIT_FAILURE);
		}

		if (verify_config) {
			printf("\nThings look okay - No serious problems were detected during the pre-flight check\n");
		}

		if (precache_objects) {
			result = fcache_objects(object_precache_file);
			timing_point("Done precaching objects\n");
			if (result == OK) {
				printf("Object precache file created:\n%s\n", object_precache_file);
			} else {
				printf("Failed to precache objects to '%s': %s\n", object_precache_file, strerror(errno));
			}
		}

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

		/* exit */
		timing_point("Exiting\n");

		/* make valgrind shut up about still reachable memory */
		neb_free_module_list();
		free(config_file_dir);
		free(config_file);

		exit(result);
	}


	/* start to monitor things... */

	/*
	 * if we're called with a relative path we must make
	 * it absolute so we can launch our workers.
	 * If not, we needn't bother, as we're using execvp()
	 */
	if (strchr(argv[0], '/'))
		naemon_binary_path = nspath_absolute(argv[0], NULL);
	else
		naemon_binary_path = nm_strdup(argv[0]);

	if (!(nagios_iobs = iobroker_create())) {
		nm_log(NSLOG_RUNTIME_ERROR, "Error: Failed to create IO broker set: %s\n",
		       strerror(errno));
		exit(EXIT_FAILURE);
	}

	/* keep monitoring things until we get a shutdown command */
	sigshutdown = sigrestart = FALSE;
	do {
		/* reset internal book-keeping (in case we're restarting) */
		wproc_num_workers_spawned = wproc_num_workers_online = 0;

		/* reset program variables */
		timing_point("Reseting variables\n");
		reset_variables();
		timing_point("Reset variables\n");

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

		/* read in the configuration files (main and resource config files) */
		timing_point("Reading main config file\n");
		result = read_main_config_file(config_file);
		if (result != OK) {
			nm_log(NSLOG_CONFIG_ERROR, "Error: Failed to process config file '%s'. Aborting\n", config_file);
			exit(EXIT_FAILURE);
		}
		timing_point("Read main config file\n");

		/* 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);
		nm_free(mac->x[MACRO_PROCESSSTARTTIME]);
		nm_asprintf(&mac->x[MACRO_PROCESSSTARTTIME], "%lu", (unsigned long)program_start);

		if (test_path_access(naemon_binary_path, X_OK)) {
			nm_log(NSLOG_RUNTIME_ERROR, "Error: failed to access() %s: %s\n", naemon_binary_path, strerror(errno));
			nm_log(NSLOG_RUNTIME_ERROR, "Error: Spawning workers will be impossible. Aborting.\n");
			exit(EXIT_FAILURE);
		}

		if (test_configured_paths() == ERROR) {
			/* error has already been logged */
			exit(EXIT_FAILURE);
		}
		/* 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) {
				nm_log(NSLOG_PROCESS_INFO | NSLOG_RUNTIME_ERROR, "Bailing out due to failure to daemonize. (PID=%d)", (int)getpid());
				cleanup();
				exit(EXIT_FAILURE);
			}

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

		/* this must be logged after we read config data, as user may have changed location of main log file */
		nm_log(NSLOG_PROCESS_INFO, "Naemon "VERSION" starting... (PID=%d)\n", (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);
		nm_log(NSLOG_PROCESS_INFO, "Local time is %s", datestring);

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

		/* open debug log now that we're the right user */
		open_debug_log();

		/* initialize modules */
		timing_point("Initializing NEB module API\n");
		neb_init_modules();
		neb_init_callback_list();
		timing_point("Initialized NEB module API\n");

		/* handle signals (interrupts) before we do any socket I/O */
		setup_sighandler();

		/*
		 * Initialize query handler and event subscription service.
		 * This must be done before modules are initialized, so
		 * the modules can use our in-core stuff properly
		 */
		timing_point("Initializing Query handler\n");
		if (qh_init(qh_socket_path) != OK) {
			nm_log(NSLOG_RUNTIME_ERROR, "Error: Failed to initialize query handler. Aborting\n");
			exit(EXIT_FAILURE);
		}
		timing_point("Initialized Query handler\n");

		timing_point("Initializing NERD\n");
		nerd_init();
		timing_point("Initialized NERD\n");

		/* initialize check workers */
		timing_point("Spawning %u workers\n", wproc_num_workers_spawned);
		if (init_workers(num_check_workers) < 0) {
			nm_log(NSLOG_RUNTIME_ERROR, "Failed to spawn workers. Aborting\n");
			exit(EXIT_FAILURE);
		}
		timing_point("Spawned %u workers\n", wproc_num_workers_spawned);

		timing_point("Connecting %u workers\n", wproc_num_workers_online);
		i = 0;
		while (i < 50 && wproc_num_workers_online < wproc_num_workers_spawned) {
			iobroker_poll(nagios_iobs, 50);
			i++;
		}
		timing_point("Connected %u workers\n", wproc_num_workers_online);

		/* read in all object config data */
		if (result == OK) {
			timing_point("Reading all object data\n");
			result = read_all_object_data(config_file);
			timing_point("Read all object data\n");
		}

		/*
		 * the queue has to be initialized before loading the neb modules
		 * to give them the chance to register user events.
		 * (initializing event queue requires number of objects, so do
		 * this after parsing the objects)
		 */
		timing_point("Initializing Event queue\n");
		init_event_queue();
		timing_point("Initialized Event queue\n");

		/* load modules */
		timing_point("Loading modules\n");
		if (neb_load_all_modules() != OK) {
			nm_log(NSLOG_CONFIG_ERROR, "Error: Module loading failed. Aborting.\n");
			/* give already loaded modules a chance to deinitialize */
			neb_unload_all_modules(NEBMODULE_FORCE_UNLOAD, NEBMODULE_NEB_SHUTDOWN);
			exit(EXIT_FAILURE);
		}
		timing_point("Loaded modules\n");

		timing_point("Making first callback\n");
		broker_program_state(NEBTYPE_PROCESS_PRELAUNCH, NEBFLAG_NONE, NEBATTR_NONE);
		timing_point("Made first callback\n");

		/* there was a problem reading the config files */
		if (result != OK) {
			nm_log(NSLOG_PROCESS_INFO | NSLOG_RUNTIME_ERROR | NSLOG_CONFIG_ERROR, "Bailing out due to one or more errors encountered in the configuration files. Run Naemon from the command line with the -v option to verify your config before restarting. (PID=%d)", (int)getpid());
		} else {
			/* run the pre-flight check to make sure everything looks okay*/
			timing_point("Running pre flight check\n");
			if ((result = pre_flight_check()) != OK) {
				nm_log(NSLOG_PROCESS_INFO | NSLOG_RUNTIME_ERROR | NSLOG_VERIFICATION_ERROR, "Bailing out due to errors encountered while running the pre-flight check.  Run Naemon from the command line with the -v option to verify your config before restarting. (PID=%d)\n", (int)getpid());
			}
			timing_point("Ran pre flight check\n");
		}

		/* 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(TRUE);
			}

			broker_program_state(NEBTYPE_PROCESS_SHUTDOWN, NEBFLAG_PROCESS_INITIATED, NEBATTR_SHUTDOWN_ABNORMAL);

			cleanup();
			exit(ERROR);
		}

		/* write the objects.cache file */
		timing_point("Caching objects\n");
		fcache_objects(object_cache_file);
		timing_point("Cached objects\n");

		broker_program_state(NEBTYPE_PROCESS_START, NEBFLAG_NONE, NEBATTR_NONE);

		timing_point("Initializing status data\n");
		initialize_status_data(config_file);
		timing_point("Initialized status data\n");

		/* initialize scheduled downtime data */
		timing_point("Initializing downtime data\n");
		initialize_downtime_data();
		timing_point("Initialized downtime data\n");

		/* read initial service and host state information  */
		timing_point("Initializing retention data\n");
		initialize_retention_data();
		timing_point("Initialized retention data\n");

		timing_point("Reading initial state information\n");
		read_initial_state_information();
		timing_point("Read initial state information\n");

		/* initialize comment data */
		timing_point("Initializing comment data\n");
		initialize_comment_data();
		timing_point("Initialized comment data\n");

		/* initialize performance data */
		timing_point("Initializing performance data\n");
		initialize_performance_data(config_file);
		timing_point("Initialized performance data\n");

		/* initialize the check execution subsystem */
		timing_point("Initializing check execution scheduling\n");
		checks_init();
		timing_point("Initialized check execution scheduling\n");

		/* initialize check statistics */
		timing_point("Initializing check stats\n");
		init_check_stats();
		timing_point("Initialized check stats\n");

		/* update all status data (with retained information) */
		timing_point("Updating status data\n");
		update_all_status_data();
		timing_point("Updated status data\n");

		/* log initial host and service state */
		timing_point("Logging initial states\n");
		log_host_states(INITIAL_STATES, NULL);
		log_service_states(INITIAL_STATES, NULL);
		timing_point("Logged initial states\n");

		registered_commands_init(200);
		register_core_commands();
		/* fire up command file worker */
		timing_point("Launching command file worker\n");
		launch_command_file_worker();
		timing_point("Launched command file worker\n");

		broker_program_state(NEBTYPE_PROCESS_EVENTLOOPSTART, NEBFLAG_NONE, NEBATTR_NONE);

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

		/* let the parent know we're good to go and that it can let go */
		if (daemon_mode == TRUE && sigrestart == FALSE) {
			if ((result = signal_parent(OK)) != OK) {
				broker_program_state(NEBTYPE_PROCESS_SHUTDOWN, NEBFLAG_PROCESS_INITIATED, NEBATTR_SHUTDOWN_ABNORMAL);
				cleanup();
				exit(ERROR);
			}
		}

		timing_point("Entering event execution loop\n");
		/***** start monitoring all services *****/
		/* (doesn't return until a restart or shutdown signal is encountered) */
		sigshutdown = sigrestart = FALSE;
		event_execution_loop();

		/*
		 * immediately deinitialize the query handler so it
		 * can remove modules that have stashed data with it
		 */
		qh_deinit(qh_socket_path);

		/*
		 * handle any incoming signals
		 */
		signal_react();

		broker_program_state(NEBTYPE_PROCESS_EVENTLOOPEND, NEBFLAG_NONE, NEBATTR_NONE);
		if (sigshutdown == TRUE)
			broker_program_state(NEBTYPE_PROCESS_SHUTDOWN, NEBFLAG_USER_INITIATED, NEBATTR_SHUTDOWN_NORMAL);
		else if (sigrestart == TRUE)
			broker_program_state(NEBTYPE_PROCESS_RESTART, NEBFLAG_USER_INITIATED, NEBATTR_RESTART_NORMAL);

		disconnect_command_file_worker();

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

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

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

		/* clean up the status data unless we're restarting */
		cleanup_status_data(!sigrestart);

		registered_commands_deinit();
		free_worker_memory(WPROC_FORCE);
		/* shutdown stuff... */
		if (sigshutdown == TRUE) {
			iobroker_destroy(nagios_iobs, IOBROKER_CLOSE_SOCKETS);
			nagios_iobs = NULL;

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

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

		/* close debug log */
		close_debug_log();

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

	shutdown_command_file_worker();

	if (daemon_mode == TRUE)
		unlink(lock_file);

	/* free misc memory */
	nm_free(lock_file);
	nm_free(config_file);
	nm_free(config_file_dir);
	nm_free(naemon_binary_path);

	return OK;
}
Ejemplo n.º 8
0
void test_host_commands(void) {
	char *host_name = "host1";
	host *target_host = NULL;
	int pre = 0, prev_comment_id = next_comment_id;
	unsigned int prev_downtime_id;
	time_t check_time =0;
	char *cmdstr = NULL;
	target_host = find_host(host_name);
	target_host->obsess = FALSE;
	pre = number_of_host_comments(host_name);
	ok(CMD_ERROR_OK == process_external_command2(CMD_ADD_HOST_COMMENT, check_time, "host1;0;myself;my comment"), "process_external_command2: ADD_HOST_COMMENT");
	ok(pre+1 == number_of_host_comments(host_name), "ADD_HOST_COMMENT (through process_external_command2) adds a host comment");
	++pre;
	ok(CMD_ERROR_OK == process_external_command1("[1234567890] ADD_HOST_COMMENT;host1;0;myself;my comment"), "core command: ADD_HOST_COMMENT");
	ok(pre+1 == number_of_host_comments(host_name), "ADD_HOST_COMMENT adds a host comment");
	nm_asprintf(&cmdstr, "[1234567890] DEL_HOST_COMMENT;%i", prev_comment_id);
	ok(CMD_ERROR_OK == process_external_command1(cmdstr), "core command: DEL_HOST_COMMENT");
	free(cmdstr);
	ok(pre == number_of_host_comments(host_name), "DEL_HOST_COMMENT deletes a host comment");

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] DELAY_HOST_NOTIFICATION;host1;1927587190"), "core command: DELAY_HOST_NOTIFICATION");
	ok(1927587190 == target_host->next_notification, "DELAY_HOST_NOTIFICATION delays host notifications");

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] DISABLE_HOST_SVC_CHECKS;host1"), "core command: DISABLE_HOST_SVC_CHECKS");
	ok(!target_host->services->service_ptr->checks_enabled, "DISABLE_HOST_SVC_CHECKS disables active checks for services on a host");

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] ENABLE_HOST_SVC_CHECKS;host1"), "core command: ENABLE_HOST_SVC_CHECKS");
	ok(target_host->services->service_ptr->checks_enabled, "ENABLE_HOST_SVC_CHECKS enables active checks for services on a host");

	check_time = target_host->services->service_ptr->next_check - 20;
	nm_asprintf(&cmdstr, "[1234567890] SCHEDULE_HOST_SVC_CHECKS;host1;%llu", (long long unsigned int)check_time);
	ok(CMD_ERROR_OK == process_external_command1(cmdstr), "core command: SCHEDULE_HOST_SVC_CHECKS");
	ok(check_time == target_host->services->service_ptr->next_check, "SCHEDULE_HOST_SVC_CHECKS schedules host service checks");
	free(cmdstr);

	assert(CMD_ERROR_OK == process_external_command1("[1234567890] ADD_HOST_COMMENT;host1;0;myself;comment 1"));
	assert(CMD_ERROR_OK == process_external_command1("[1234567890] ADD_HOST_COMMENT;host1;1;myself;comment 2"));
	assert(CMD_ERROR_OK == process_external_command1("[1234567890] ADD_HOST_COMMENT;host1;0;myself;comment 3"));
	ok(CMD_ERROR_OK == process_external_command1("[1234567890] DEL_ALL_HOST_COMMENTS;host1"), "core command: DEL_ALL_HOST_COMMENTS");
	ok(0 == number_of_host_comments(host_name), "DEL_ALL_HOST_COMMENTS deletes all host comments");

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] DISABLE_HOST_NOTIFICATIONS;host1"), "core command: DISABLE_HOST_NOTIFICATIONS");
	ok(!target_host->notifications_enabled, "DISABLE_HOST_NOTIFICATIONS disables host notifications");

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] ENABLE_HOST_NOTIFICATIONS;host1"), "core command: ENABLE_HOST_NOTIFICATIONS");
	ok(target_host->notifications_enabled, "ENABLE_HOST_NOTIFICATIONS enables host notifications");

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] DISABLE_ALL_NOTIFICATIONS_BEYOND_HOST;host1"), "core command: DISABLE_ALL_NOTIFICATIONS_BEYOND_HOST");
	ok(!((find_host("childofhost1"))->notifications_enabled), "DISABLE_ALL_NOTIFICATIONS_BEYOND_HOST disables notifications beyond host");

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] ENABLE_ALL_NOTIFICATIONS_BEYOND_HOST;host1"), "core command: ENABLE_ALL_NOTIFICATIONS_BEYOND_HOST");
	ok(((find_host("childofhost1"))->notifications_enabled), "ENABLE_ALL_NOTIFICATIONS_BEYOND_HOST enables notifications beyond host");

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] DISABLE_HOST_SVC_NOTIFICATIONS;host1"), "core command: DISABLE_HOST_SVC_NOTIFICATIONS");
	ok(!(target_host->services->service_ptr->notifications_enabled), "DISABLE_HOST_SVC_NOTIFICATIONS disables notifications for services on a host");

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] ENABLE_HOST_SVC_NOTIFICATIONS;host1"), "core command: ENABLE_HOST_SVC_NOTIFICATIONS");
	ok(target_host->services->service_ptr->notifications_enabled, "ENABLE_HOST_SVC_NOTIFICATIONS enables notifications for services on a host");

	target_host->current_state = STATE_DOWN;
	ok(CMD_ERROR_OK == process_external_command1("[1234567890] ACKNOWLEDGE_HOST_PROBLEM;host1;2;0;0;myself;my ack comment"), "core command: ACKNOWLEDGE_HOST_PROBLEM");
	ok(target_host->problem_has_been_acknowledged, "ACKNOWLEDGE_HOST_PROBLEM acknowledges a host problem");

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] REMOVE_HOST_ACKNOWLEDGEMENT;host1"), "core command: REMOVE_HOST_ACKNOWLEDGEMENT");
	ok(!target_host->problem_has_been_acknowledged, "REMOVE_HOST_ACKNOWLEDGEMENT removes a host acknowledgement");
	target_host->current_state = STATE_UP;

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] DISABLE_HOST_EVENT_HANDLER;host1"), "core command: DISABLE_HOST_EVENT_HANDLER");
	ok(!target_host->event_handler_enabled, "DISABLE_HOST_EVENT_HANDLER disables event handler for a host");

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] ENABLE_HOST_EVENT_HANDLER;host1"), "core command: ENABLE_HOST_EVENT_HANDLER");
	ok(target_host->event_handler_enabled, "ENABLE_HOST_EVENT_HANDLER enables event handler for a host");

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] DISABLE_HOST_CHECK;host1"), "core command: DISABLE_HOST_CHECK");
	ok(!target_host->checks_enabled, "DISABLE_HOST_CHECK disables active host checks");

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] ENABLE_HOST_CHECK;host1"), "core command: ENABLE_HOST_CHECK");
	ok(target_host->checks_enabled, "ENABLE_HOST_CHECK enables active host checks");

	check_time = target_host->services->service_ptr->next_check + 2000;
	nm_asprintf(&cmdstr, "[1234567890] SCHEDULE_FORCED_HOST_SVC_CHECKS;host1;%llu", (unsigned long long int)check_time);
	ok(CMD_ERROR_OK == process_external_command1(cmdstr), "core command: SCHEDULE_FORCED_HOST_SVC_CHECKS");
	ok(check_time == target_host->services->service_ptr->next_check, "SCHEDULE_FORCED_HOST_SVC_CHECKS schedules forced checks for services on a host");
	free(cmdstr);

	prev_downtime_id = next_downtime_id;
	nm_asprintf(&cmdstr, "[1234567890] SCHEDULE_HOST_DOWNTIME;host1;%llu;%llu;1;0;0;myself;my downtime comment", (unsigned long long int)time(NULL), (unsigned long long int)time(NULL) + 1500);
	ok(CMD_ERROR_OK == process_external_command1(cmdstr), "core command: SCHEDULE_HOST_DOWNTIME");
	ok(prev_downtime_id != next_downtime_id, "SCHEDULE_HOST_DOWNTIME schedules one new downtime");
	ok(NULL != find_host_downtime(prev_downtime_id), "SCHEDULE_HOST_DOWNTIME schedules downtime for a host");
	free(cmdstr);

	nm_asprintf(&cmdstr, "[1234567890] DEL_HOST_DOWNTIME;%i", prev_downtime_id);
	ok(CMD_ERROR_OK == process_external_command1(cmdstr), "core command: DEL_HOST_DOWNTIME");
	ok(!find_host_downtime(prev_downtime_id), "DEL_HOST_DOWNTIME deletes a scheduled host downtime");
	free(cmdstr);

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] DISABLE_HOST_FLAP_DETECTION;host1"), "core command: DISABLE_HOST_FLAP_DETECTION");
	ok(!target_host->flap_detection_enabled, "DISABLE_HOST_FLAP_DETECTION disables host flap detection");

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] ENABLE_HOST_FLAP_DETECTION;host1"), "core command: ENABLE_HOST_FLAP_DETECTION");
	ok(target_host->flap_detection_enabled, "ENABLE_HOST_FLAP_DETECTION enables host flap detection");

	assert(NULL == find_service_downtime(0));
	nm_asprintf(&cmdstr, "[1234567890] SCHEDULE_HOST_SVC_DOWNTIME;host1;%llu;%llu;1;0;0;myself;my downtime comment", (unsigned long long int)time(NULL), (unsigned long long int)time(NULL) + 1500);
	ok(CMD_ERROR_OK == process_external_command1(cmdstr), "core command: SCHEDULE_HOST_SVC_DOWNTIME");
	strcmp(host_name, find_service_downtime(0)->host_name);
	ok(0 == 0, "SCHEDULE_HOST_SVC_DOWNTIME schedules downtime for services on a host");
	free(cmdstr);

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] PROCESS_HOST_CHECK_RESULT;host1;1;some plugin output"), "core command: PROCESS_HOST_CHECK_RESULT");
	ok(target_host->current_state == STATE_DOWN, "PROCESS_HOST_CHECK_RESULT processes host check results");

	check_time = target_host->next_check - 20;
	nm_asprintf(&cmdstr, "[1234567890] SCHEDULE_HOST_CHECK;host1;%llu", (unsigned long long int)check_time);
	ok(CMD_ERROR_OK == process_external_command1(cmdstr), "core command: SCHEDULE_HOST_CHECK");
	ok(check_time == target_host->next_check, "SCHEDULE_HOST_CHECK schedules a host check");
	free(cmdstr);

	nm_asprintf(&cmdstr, "[1234567890] SCHEDULE_HOST_CHECK;host1;%llu", (unsigned long long int)check_time);
	ok(CMD_ERROR_OK == process_external_command1(cmdstr), "core command: SCHEDULE_FORCED_HOST_CHECK");
	ok(check_time == target_host->next_check, "SCHEDULE_FORCED_HOST_CHECK schedules a host check");
	free(cmdstr);

	assert(!(target_host->obsess));
	ok(CMD_ERROR_OK == process_external_command1("[1234567890] START_OBSESSING_OVER_HOST;host1"), "core command: START_OBSESSING_OVER_HOST");
	ok(target_host->obsess, "START_OBSESSING_OVER_HOST enables OCHP for host");

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] STOP_OBSESSING_OVER_HOST;host1"), "core command: STOP_OBSESSING_OVER_HOST");
	ok(!target_host->obsess, "STOP_OBSESSING_OVER_HOST disables OCHP for host");

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] CHANGE_NORMAL_HOST_CHECK_INTERVAL;host1;42"), "core command: CHANGE_NORMAL_HOST_CHECK_INTERVAL");
	ok(42 == target_host->check_interval, "CHANGE_NORMAL_HOST_CHECK_INTERVAL changes the host check inteval for host");

	ok(CMD_ERROR_OK == process_external_command1("[1234567890] CHANGE_MAX_HOST_CHECK_ATTEMPTS;host1;9"), "core command: CHANGE_MAX_HOST_CHECK_ATTEMPTS");
	ok(9 == target_host->max_attempts, "CHANGE_MAX_HOST_CHECK_ATTEMPTS changes the maximum number of check attempts for host");
}
Ejemplo n.º 9
0
/* write all status data to file */
int xsddefault_save_status_data(void)
{
	char *tmp_log = NULL;
	customvariablesmember *temp_customvariablesmember = NULL;
	host *temp_host = NULL;
	service *temp_service = NULL;
	contact *temp_contact = NULL;
	comment *temp_comment = NULL;
	scheduled_downtime *temp_downtime = NULL;
	time_t current_time;
	int fd = 0;
	FILE *fp = NULL;
	int result = OK;

	/* users may not want us to write status data */
	if (!status_file || !strcmp(status_file, "/dev/null"))
		return OK;

	nm_asprintf(&tmp_log, "%sXXXXXX", temp_file);
	if (tmp_log == NULL)
		return ERROR;

	log_debug_info(DEBUGL_STATUSDATA, 2, "Writing status data to temp file '%s'\n", tmp_log);

	if ((fd = mkstemp(tmp_log)) == -1) {

		/* log an error */
		nm_log(NSLOG_RUNTIME_ERROR, "Error: Unable to create temp file '%s' for writing status data: %s\n", tmp_log, strerror(errno));

		nm_free(tmp_log);

		return ERROR;
	}
	fp = (FILE *)fdopen(fd, "w");
	if (fp == NULL) {

		close(fd);
		unlink(tmp_log);

		/* log an error */
		nm_log(NSLOG_RUNTIME_ERROR, "Error: Unable to open temp file '%s' for writing status data: %s\n", tmp_log, strerror(errno));

		nm_free(tmp_log);

		return ERROR;
	}

	/* generate check statistics */
	generate_check_stats();

	/* write version info to status file */
	fprintf(fp, "########################################\n");
	fprintf(fp, "#          NAGIOS STATUS FILE\n");
	fprintf(fp, "#\n");
	fprintf(fp, "# THIS FILE IS AUTOMATICALLY GENERATED\n");
	fprintf(fp, "# BY NAGIOS.  DO NOT MODIFY THIS FILE!\n");
	fprintf(fp, "########################################\n\n");

	time(&current_time);

	/* write file info */
	fprintf(fp, "info {\n");
	fprintf(fp, "\tcreated=%lu\n", current_time);
	fprintf(fp, "\tversion=" VERSION "\n");
	fprintf(fp, "\t}\n\n");

	/* save program status data */
	fprintf(fp, "programstatus {\n");
	fprintf(fp, "\tmodified_host_attributes=%lu\n", modified_host_process_attributes);
	fprintf(fp, "\tmodified_service_attributes=%lu\n", modified_service_process_attributes);
	fprintf(fp, "\tnagios_pid=%d\n", nagios_pid);
	fprintf(fp, "\tdaemon_mode=%d\n", daemon_mode);
	fprintf(fp, "\tprogram_start=%lu\n", program_start);
	fprintf(fp, "\tlast_log_rotation=%lu\n", last_log_rotation);
	fprintf(fp, "\tenable_notifications=%d\n", enable_notifications);
	fprintf(fp, "\tactive_service_checks_enabled=%d\n", execute_service_checks);
	fprintf(fp, "\tpassive_service_checks_enabled=%d\n", accept_passive_service_checks);
	fprintf(fp, "\tactive_host_checks_enabled=%d\n", execute_host_checks);
	fprintf(fp, "\tpassive_host_checks_enabled=%d\n", accept_passive_host_checks);
	fprintf(fp, "\tenable_event_handlers=%d\n", enable_event_handlers);
	fprintf(fp, "\tobsess_over_services=%d\n", obsess_over_services);
	fprintf(fp, "\tobsess_over_hosts=%d\n", obsess_over_hosts);
	fprintf(fp, "\tcheck_service_freshness=%d\n", check_service_freshness);
	fprintf(fp, "\tcheck_host_freshness=%d\n", check_host_freshness);
	fprintf(fp, "\tenable_flap_detection=%d\n", enable_flap_detection);
	fprintf(fp, "\tprocess_performance_data=%d\n", process_performance_data);
	fprintf(fp, "\tglobal_host_event_handler=%s\n", (global_host_event_handler == NULL) ? "" : global_host_event_handler);
	fprintf(fp, "\tglobal_service_event_handler=%s\n", (global_service_event_handler == NULL) ? "" : global_service_event_handler);
	fprintf(fp, "\tnext_comment_id=%lu\n", next_comment_id);
	fprintf(fp, "\tnext_downtime_id=%lu\n", next_downtime_id);
	fprintf(fp, "\tnext_event_id=%lu\n", next_event_id);
	fprintf(fp, "\tnext_problem_id=%lu\n", next_problem_id);
	fprintf(fp, "\tnext_notification_id=%lu\n", next_notification_id);
	fprintf(fp, "\tactive_scheduled_host_check_stats=%d,%d,%d\n", check_statistics[ACTIVE_SCHEDULED_HOST_CHECK_STATS].minute_stats[0], check_statistics[ACTIVE_SCHEDULED_HOST_CHECK_STATS].minute_stats[1], check_statistics[ACTIVE_SCHEDULED_HOST_CHECK_STATS].minute_stats[2]);
	fprintf(fp, "\tactive_ondemand_host_check_stats=%d,%d,%d\n", check_statistics[ACTIVE_ONDEMAND_HOST_CHECK_STATS].minute_stats[0], check_statistics[ACTIVE_ONDEMAND_HOST_CHECK_STATS].minute_stats[1], check_statistics[ACTIVE_ONDEMAND_HOST_CHECK_STATS].minute_stats[2]);
	fprintf(fp, "\tpassive_host_check_stats=%d,%d,%d\n", check_statistics[PASSIVE_HOST_CHECK_STATS].minute_stats[0], check_statistics[PASSIVE_HOST_CHECK_STATS].minute_stats[1], check_statistics[PASSIVE_HOST_CHECK_STATS].minute_stats[2]);
	fprintf(fp, "\tactive_scheduled_service_check_stats=%d,%d,%d\n", check_statistics[ACTIVE_SCHEDULED_SERVICE_CHECK_STATS].minute_stats[0], check_statistics[ACTIVE_SCHEDULED_SERVICE_CHECK_STATS].minute_stats[1], check_statistics[ACTIVE_SCHEDULED_SERVICE_CHECK_STATS].minute_stats[2]);
	fprintf(fp, "\tactive_ondemand_service_check_stats=%d,%d,%d\n", check_statistics[ACTIVE_ONDEMAND_SERVICE_CHECK_STATS].minute_stats[0], check_statistics[ACTIVE_ONDEMAND_SERVICE_CHECK_STATS].minute_stats[1], check_statistics[ACTIVE_ONDEMAND_SERVICE_CHECK_STATS].minute_stats[2]);
	fprintf(fp, "\tpassive_service_check_stats=%d,%d,%d\n", check_statistics[PASSIVE_SERVICE_CHECK_STATS].minute_stats[0], check_statistics[PASSIVE_SERVICE_CHECK_STATS].minute_stats[1], check_statistics[PASSIVE_SERVICE_CHECK_STATS].minute_stats[2]);
	fprintf(fp, "\tcached_host_check_stats=%d,%d,%d\n", check_statistics[ACTIVE_CACHED_HOST_CHECK_STATS].minute_stats[0], check_statistics[ACTIVE_CACHED_HOST_CHECK_STATS].minute_stats[1], check_statistics[ACTIVE_CACHED_HOST_CHECK_STATS].minute_stats[2]);
	fprintf(fp, "\tcached_service_check_stats=%d,%d,%d\n", check_statistics[ACTIVE_CACHED_SERVICE_CHECK_STATS].minute_stats[0], check_statistics[ACTIVE_CACHED_SERVICE_CHECK_STATS].minute_stats[1], check_statistics[ACTIVE_CACHED_SERVICE_CHECK_STATS].minute_stats[2]);
	fprintf(fp, "\texternal_command_stats=%d,%d,%d\n", check_statistics[EXTERNAL_COMMAND_STATS].minute_stats[0], check_statistics[EXTERNAL_COMMAND_STATS].minute_stats[1], check_statistics[EXTERNAL_COMMAND_STATS].minute_stats[2]);

	fprintf(fp, "\tparallel_host_check_stats=%d,%d,%d\n", check_statistics[PARALLEL_HOST_CHECK_STATS].minute_stats[0], check_statistics[PARALLEL_HOST_CHECK_STATS].minute_stats[1], check_statistics[PARALLEL_HOST_CHECK_STATS].minute_stats[2]);
	fprintf(fp, "\tserial_host_check_stats=%d,%d,%d\n", check_statistics[SERIAL_HOST_CHECK_STATS].minute_stats[0], check_statistics[SERIAL_HOST_CHECK_STATS].minute_stats[1], check_statistics[SERIAL_HOST_CHECK_STATS].minute_stats[2]);
	fprintf(fp, "\t}\n\n");


	/* save host status data */
	for (temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {

		fprintf(fp, "hoststatus {\n");
		fprintf(fp, "\thost_name=%s\n", temp_host->name);

		fprintf(fp, "\tmodified_attributes=%lu\n", temp_host->modified_attributes);
		fprintf(fp, "\tcheck_command=%s\n", (temp_host->check_command == NULL) ? "" : temp_host->check_command);
		fprintf(fp, "\tcheck_period=%s\n", (temp_host->check_period == NULL) ? "" : temp_host->check_period);
		fprintf(fp, "\tnotification_period=%s\n", (temp_host->notification_period == NULL) ? "" : temp_host->notification_period);
		fprintf(fp, "\tcheck_interval=%f\n", temp_host->check_interval);
		fprintf(fp, "\tretry_interval=%f\n", temp_host->retry_interval);
		fprintf(fp, "\tevent_handler=%s\n", (temp_host->event_handler == NULL) ? "" : temp_host->event_handler);

		fprintf(fp, "\thas_been_checked=%d\n", temp_host->has_been_checked);
		fprintf(fp, "\tcheck_execution_time=%.3f\n", temp_host->execution_time);
		fprintf(fp, "\tcheck_latency=%.3f\n", temp_host->latency);
		fprintf(fp, "\tcheck_type=%d\n", temp_host->check_type);
		fprintf(fp, "\tcurrent_state=%d\n", temp_host->current_state);
		fprintf(fp, "\tlast_hard_state=%d\n", temp_host->last_hard_state);
		fprintf(fp, "\tlast_event_id=%lu\n", temp_host->last_event_id);
		fprintf(fp, "\tcurrent_event_id=%lu\n", temp_host->current_event_id);
		fprintf(fp, "\tcurrent_problem_id=%lu\n", temp_host->current_problem_id);
		fprintf(fp, "\tlast_problem_id=%lu\n", temp_host->last_problem_id);
		fprintf(fp, "\tplugin_output=%s\n", (temp_host->plugin_output == NULL) ? "" : temp_host->plugin_output);
		fprintf(fp, "\tlong_plugin_output=%s\n", (temp_host->long_plugin_output == NULL) ? "" : temp_host->long_plugin_output);
		fprintf(fp, "\tperformance_data=%s\n", (temp_host->perf_data == NULL) ? "" : temp_host->perf_data);
		fprintf(fp, "\tlast_check=%lu\n", temp_host->last_check);
		fprintf(fp, "\tnext_check=%lu\n", temp_host->next_check);
		fprintf(fp, "\tcheck_options=%d\n", temp_host->check_options);
		fprintf(fp, "\tcurrent_attempt=%d\n", temp_host->current_attempt);
		fprintf(fp, "\tmax_attempts=%d\n", temp_host->max_attempts);
		fprintf(fp, "\tstate_type=%d\n", temp_host->state_type);
		fprintf(fp, "\tlast_state_change=%lu\n", temp_host->last_state_change);
		fprintf(fp, "\tlast_hard_state_change=%lu\n", temp_host->last_hard_state_change);
		fprintf(fp, "\tlast_time_up=%lu\n", temp_host->last_time_up);
		fprintf(fp, "\tlast_time_down=%lu\n", temp_host->last_time_down);
		fprintf(fp, "\tlast_time_unreachable=%lu\n", temp_host->last_time_unreachable);
		fprintf(fp, "\tlast_notification=%lu\n", temp_host->last_notification);
		fprintf(fp, "\tnext_notification=%lu\n", temp_host->next_notification);
		fprintf(fp, "\tno_more_notifications=%d\n", temp_host->no_more_notifications);
		fprintf(fp, "\tcurrent_notification_number=%d\n", temp_host->current_notification_number);
		fprintf(fp, "\tcurrent_notification_id=%lu\n", temp_host->current_notification_id);
		fprintf(fp, "\tnotifications_enabled=%d\n", temp_host->notifications_enabled);
		fprintf(fp, "\tproblem_has_been_acknowledged=%d\n", temp_host->problem_has_been_acknowledged);
		fprintf(fp, "\tacknowledgement_type=%d\n", temp_host->acknowledgement_type);
		fprintf(fp, "\tactive_checks_enabled=%d\n", temp_host->checks_enabled);
		fprintf(fp, "\tpassive_checks_enabled=%d\n", temp_host->accept_passive_checks);
		fprintf(fp, "\tevent_handler_enabled=%d\n", temp_host->event_handler_enabled);
		fprintf(fp, "\tflap_detection_enabled=%d\n", temp_host->flap_detection_enabled);
		fprintf(fp, "\tprocess_performance_data=%d\n", temp_host->process_performance_data);
		fprintf(fp, "\tobsess=%d\n", temp_host->obsess);
		fprintf(fp, "\tlast_update=%lu\n", current_time);
		fprintf(fp, "\tis_flapping=%d\n", temp_host->is_flapping);
		fprintf(fp, "\tpercent_state_change=%.2f\n", temp_host->percent_state_change);
		fprintf(fp, "\tscheduled_downtime_depth=%d\n", temp_host->scheduled_downtime_depth);
		/* custom variables */
		for (temp_customvariablesmember = temp_host->custom_variables; temp_customvariablesmember != NULL; temp_customvariablesmember = temp_customvariablesmember->next) {
			if (temp_customvariablesmember->variable_name)
				fprintf(fp, "\t_%s=%d;%s\n", temp_customvariablesmember->variable_name, temp_customvariablesmember->has_been_modified, (temp_customvariablesmember->variable_value == NULL) ? "" : temp_customvariablesmember->variable_value);
		}
		fprintf(fp, "\t}\n\n");
	}

	/* save service status data */
	for (temp_service = service_list; temp_service != NULL; temp_service = temp_service->next) {

		fprintf(fp, "servicestatus {\n");
		fprintf(fp, "\thost_name=%s\n", temp_service->host_name);

		fprintf(fp, "\tservice_description=%s\n", temp_service->description);
		fprintf(fp, "\tmodified_attributes=%lu\n", temp_service->modified_attributes);
		fprintf(fp, "\tcheck_command=%s\n", (temp_service->check_command == NULL) ? "" : temp_service->check_command);
		fprintf(fp, "\tcheck_period=%s\n", (temp_service->check_period == NULL) ? "" : temp_service->check_period);
		fprintf(fp, "\tnotification_period=%s\n", (temp_service->notification_period == NULL) ? "" : temp_service->notification_period);
		fprintf(fp, "\tcheck_interval=%f\n", temp_service->check_interval);
		fprintf(fp, "\tretry_interval=%f\n", temp_service->retry_interval);
		fprintf(fp, "\tevent_handler=%s\n", (temp_service->event_handler == NULL) ? "" : temp_service->event_handler);

		fprintf(fp, "\thas_been_checked=%d\n", temp_service->has_been_checked);
		fprintf(fp, "\tcheck_execution_time=%.3f\n", temp_service->execution_time);
		fprintf(fp, "\tcheck_latency=%.3f\n", temp_service->latency);
		fprintf(fp, "\tcheck_type=%d\n", temp_service->check_type);
		fprintf(fp, "\tcurrent_state=%d\n", temp_service->current_state);
		fprintf(fp, "\tlast_hard_state=%d\n", temp_service->last_hard_state);
		fprintf(fp, "\tlast_event_id=%lu\n", temp_service->last_event_id);
		fprintf(fp, "\tcurrent_event_id=%lu\n", temp_service->current_event_id);
		fprintf(fp, "\tcurrent_problem_id=%lu\n", temp_service->current_problem_id);
		fprintf(fp, "\tlast_problem_id=%lu\n", temp_service->last_problem_id);
		fprintf(fp, "\tcurrent_attempt=%d\n", temp_service->current_attempt);
		fprintf(fp, "\tmax_attempts=%d\n", temp_service->max_attempts);
		fprintf(fp, "\tstate_type=%d\n", temp_service->state_type);
		fprintf(fp, "\tlast_state_change=%lu\n", temp_service->last_state_change);
		fprintf(fp, "\tlast_hard_state_change=%lu\n", temp_service->last_hard_state_change);
		fprintf(fp, "\tlast_time_ok=%lu\n", temp_service->last_time_ok);
		fprintf(fp, "\tlast_time_warning=%lu\n", temp_service->last_time_warning);
		fprintf(fp, "\tlast_time_unknown=%lu\n", temp_service->last_time_unknown);
		fprintf(fp, "\tlast_time_critical=%lu\n", temp_service->last_time_critical);
		fprintf(fp, "\tplugin_output=%s\n", (temp_service->plugin_output == NULL) ? "" : temp_service->plugin_output);
		fprintf(fp, "\tlong_plugin_output=%s\n", (temp_service->long_plugin_output == NULL) ? "" : temp_service->long_plugin_output);
		fprintf(fp, "\tperformance_data=%s\n", (temp_service->perf_data == NULL) ? "" : temp_service->perf_data);
		fprintf(fp, "\tlast_check=%lu\n", temp_service->last_check);
		fprintf(fp, "\tnext_check=%lu\n", temp_service->next_check);
		fprintf(fp, "\tcheck_options=%d\n", temp_service->check_options);
		fprintf(fp, "\tcurrent_notification_number=%d\n", temp_service->current_notification_number);
		fprintf(fp, "\tcurrent_notification_id=%lu\n", temp_service->current_notification_id);
		fprintf(fp, "\tlast_notification=%lu\n", temp_service->last_notification);
		fprintf(fp, "\tnext_notification=%lu\n", temp_service->next_notification);
		fprintf(fp, "\tno_more_notifications=%d\n", temp_service->no_more_notifications);
		fprintf(fp, "\tnotifications_enabled=%d\n", temp_service->notifications_enabled);
		fprintf(fp, "\tactive_checks_enabled=%d\n", temp_service->checks_enabled);
		fprintf(fp, "\tpassive_checks_enabled=%d\n", temp_service->accept_passive_checks);
		fprintf(fp, "\tevent_handler_enabled=%d\n", temp_service->event_handler_enabled);
		fprintf(fp, "\tproblem_has_been_acknowledged=%d\n", temp_service->problem_has_been_acknowledged);
		fprintf(fp, "\tacknowledgement_type=%d\n", temp_service->acknowledgement_type);
		fprintf(fp, "\tflap_detection_enabled=%d\n", temp_service->flap_detection_enabled);
		fprintf(fp, "\tprocess_performance_data=%d\n", temp_service->process_performance_data);
		fprintf(fp, "\tobsess=%d\n", temp_service->obsess);
		fprintf(fp, "\tlast_update=%lu\n", current_time);
		fprintf(fp, "\tis_flapping=%d\n", temp_service->is_flapping);
		fprintf(fp, "\tpercent_state_change=%.2f\n", temp_service->percent_state_change);
		fprintf(fp, "\tscheduled_downtime_depth=%d\n", temp_service->scheduled_downtime_depth);
		/* custom variables */
		for (temp_customvariablesmember = temp_service->custom_variables; temp_customvariablesmember != NULL; temp_customvariablesmember = temp_customvariablesmember->next) {
			if (temp_customvariablesmember->variable_name)
				fprintf(fp, "\t_%s=%d;%s\n", temp_customvariablesmember->variable_name, temp_customvariablesmember->has_been_modified, (temp_customvariablesmember->variable_value == NULL) ? "" : temp_customvariablesmember->variable_value);
		}
		fprintf(fp, "\t}\n\n");
	}

	/* save contact status data */
	for (temp_contact = contact_list; temp_contact != NULL; temp_contact = temp_contact->next) {

		fprintf(fp, "contactstatus {\n");
		fprintf(fp, "\tcontact_name=%s\n", temp_contact->name);

		fprintf(fp, "\tmodified_attributes=%lu\n", temp_contact->modified_attributes);
		fprintf(fp, "\tmodified_host_attributes=%lu\n", temp_contact->modified_host_attributes);
		fprintf(fp, "\tmodified_service_attributes=%lu\n", temp_contact->modified_service_attributes);
		fprintf(fp, "\thost_notification_period=%s\n", (temp_contact->host_notification_period == NULL) ? "" : temp_contact->host_notification_period);
		fprintf(fp, "\tservice_notification_period=%s\n", (temp_contact->service_notification_period == NULL) ? "" : temp_contact->service_notification_period);

		fprintf(fp, "\tlast_host_notification=%lu\n", temp_contact->last_host_notification);
		fprintf(fp, "\tlast_service_notification=%lu\n", temp_contact->last_service_notification);
		fprintf(fp, "\thost_notifications_enabled=%d\n", temp_contact->host_notifications_enabled);
		fprintf(fp, "\tservice_notifications_enabled=%d\n", temp_contact->service_notifications_enabled);
		/* custom variables */
		for (temp_customvariablesmember = temp_contact->custom_variables; temp_customvariablesmember != NULL; temp_customvariablesmember = temp_customvariablesmember->next) {
			if (temp_customvariablesmember->variable_name)
				fprintf(fp, "\t_%s=%d;%s\n", temp_customvariablesmember->variable_name, temp_customvariablesmember->has_been_modified, (temp_customvariablesmember->variable_value == NULL) ? "" : temp_customvariablesmember->variable_value);
		}
		fprintf(fp, "\t}\n\n");
	}

	/* save all comments */
	for (temp_comment = comment_list; temp_comment != NULL; temp_comment = temp_comment->next) {

		if (temp_comment->comment_type == HOST_COMMENT)
			fprintf(fp, "hostcomment {\n");
		else
			fprintf(fp, "servicecomment {\n");
		fprintf(fp, "\thost_name=%s\n", temp_comment->host_name);
		if (temp_comment->comment_type == SERVICE_COMMENT)
			fprintf(fp, "\tservice_description=%s\n", temp_comment->service_description);
		fprintf(fp, "\tentry_type=%d\n", temp_comment->entry_type);
		fprintf(fp, "\tcomment_id=%lu\n", temp_comment->comment_id);
		fprintf(fp, "\tsource=%d\n", temp_comment->source);
		fprintf(fp, "\tpersistent=%d\n", temp_comment->persistent);
		fprintf(fp, "\tentry_time=%lu\n", temp_comment->entry_time);
		fprintf(fp, "\texpires=%d\n", temp_comment->expires);
		fprintf(fp, "\texpire_time=%lu\n", temp_comment->expire_time);
		fprintf(fp, "\tauthor=%s\n", temp_comment->author);
		fprintf(fp, "\tcomment_data=%s\n", temp_comment->comment_data);
		fprintf(fp, "\t}\n\n");
	}

	/* save all downtime */
	for (temp_downtime = scheduled_downtime_list; temp_downtime != NULL; temp_downtime = temp_downtime->next) {

		if (temp_downtime->type == HOST_DOWNTIME)
			fprintf(fp, "hostdowntime {\n");
		else
			fprintf(fp, "servicedowntime {\n");
		fprintf(fp, "\thost_name=%s\n", temp_downtime->host_name);
		if (temp_downtime->type == SERVICE_DOWNTIME)
			fprintf(fp, "\tservice_description=%s\n", temp_downtime->service_description);
		fprintf(fp, "\tdowntime_id=%lu\n", temp_downtime->downtime_id);
		fprintf(fp, "\tcomment_id=%lu\n", temp_downtime->comment_id);
		fprintf(fp, "\tentry_time=%lu\n", temp_downtime->entry_time);
		fprintf(fp, "\tstart_time=%lu\n", temp_downtime->start_time);
		fprintf(fp, "\tflex_downtime_start=%lu\n", temp_downtime->flex_downtime_start);
		fprintf(fp, "\tend_time=%lu\n", temp_downtime->end_time);
		fprintf(fp, "\ttriggered_by=%lu\n", temp_downtime->triggered_by);
		fprintf(fp, "\tfixed=%d\n", temp_downtime->fixed);
		fprintf(fp, "\tduration=%lu\n", temp_downtime->duration);
		fprintf(fp, "\tis_in_effect=%d\n", temp_downtime->is_in_effect);
		fprintf(fp, "\tstart_notification_sent=%d\n", temp_downtime->start_notification_sent);
		fprintf(fp, "\tauthor=%s\n", temp_downtime->author);
		fprintf(fp, "\tcomment=%s\n", temp_downtime->comment);
		fprintf(fp, "\t}\n\n");
	}


	/* reset file permissions */
	fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);

	/* flush the file to disk */
	fflush(fp);

	/* fsync the file so that it is completely written out before moving it */
	fsync(fd);

	/* close the temp file */
	result = fclose(fp);

	/* save/close was successful */
	if (result == 0) {

		result = OK;

		/* move the temp file to the status log (overwrite the old status log) */
		if (my_rename(tmp_log, status_file)) {
			unlink(tmp_log);
			nm_log(NSLOG_RUNTIME_ERROR, "Error: Unable to update status data file '%s': %s", status_file, strerror(errno));
			result = ERROR;
		}
	}

	/* a problem occurred saving the file */
	else {

		result = ERROR;

		/* remove temp file and log an error */
		unlink(tmp_log);
		nm_log(NSLOG_RUNTIME_ERROR, "Error: Unable to save status file: %s", strerror(errno));
	}

	nm_free(tmp_log);

	return result;
}