nagios4/base/nagios.c
2019-04-18 17:09:18 +02:00

938 lines
28 KiB
C

/*****************************************************************************
*
* NAGIOS.C - Core Program Code For Nagios
*
* Program: Nagios Core
* License: GPL
*
* First Written: 01-28-1999 (start of development)
*
* Description:
*
* 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 Nagios.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, 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/nagios.h"
#include "../include/sretention.h"
#include "../include/perfdata.h"
#include "../include/broker.h"
#include "../include/nebmods.h"
#include "../include/nebmodules.h"
#include "../include/workers.h"
/*#define DEBUG_MEMORY 1*/
#ifdef DEBUG_MEMORY
#include <mcheck.h>
#endif
static int is_worker;
static void set_loadctl_defaults(void)
{
struct rlimit rlim;
/* Workers need to up 'em, master needs to know 'em */
getrlimit(RLIMIT_NOFILE, &rlim);
rlim.rlim_cur = rlim.rlim_max;
setrlimit(RLIMIT_NOFILE, &rlim);
loadctl.nofile_limit = rlim.rlim_max;
#ifdef RLIMIT_NPROC
getrlimit(RLIMIT_NPROC, &rlim);
rlim.rlim_cur = rlim.rlim_max;
setrlimit(RLIMIT_NPROC, &rlim);
loadctl.nproc_limit = rlim.rlim_max;
#else
loadctl.nproc_limit = loadctl.nofile_limit / 2;
#endif
/*
* things may have been configured already. Otherwise we
* set some sort of sane defaults here
*/
if (!loadctl.jobs_max) {
loadctl.jobs_max = loadctl.nproc_limit - 100;
if (!is_worker && loadctl.jobs_max > (loadctl.nofile_limit - 50) * wproc_num_workers_online) {
loadctl.jobs_max = (loadctl.nofile_limit - 50) * wproc_num_workers_online;
}
}
if (!loadctl.jobs_limit)
loadctl.jobs_limit = loadctl.jobs_max;
if (!loadctl.backoff_limit)
loadctl.backoff_limit = online_cpus() * 2.5;
if (!loadctl.rampup_limit)
loadctl.rampup_limit = online_cpus() * 0.8;
if (!loadctl.backoff_change)
loadctl.backoff_change = loadctl.jobs_limit * 0.3;
if (!loadctl.rampup_change)
loadctl.rampup_change = loadctl.backoff_change * 0.25;
if (!loadctl.check_interval)
loadctl.check_interval = 60;
if (!loadctl.jobs_min)
loadctl.jobs_min = online_cpus() * 20; /* pessimistic */
}
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;
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;
}
static int nagios_core_worker(const char *path)
{
int sd, ret;
char response[128];
is_worker = 1;
set_loadctl_defaults();
sd = nsock_unix(path, NSOCK_TCP | NSOCK_CONNECT);
if (sd < 0) {
printf("Failed to connect to query socket '%s': %s: %s\n",
path, nsock_strerror(sd), strerror(errno));
return 1;
}
ret = nsock_printf_nul(sd, "@wproc register name=Core Worker %ld;pid=%ld", (long)getpid(), (long)getpid());
if (ret < 0) {
printf("Failed to register as worker.\n");
return 1;
}
ret = read(sd, response, 3);
if (ret != 3) {
printf("Failed to read response from wproc manager\n");
return 1;
}
if (memcmp(response, "OK", 3)) {
read(sd, response + 3, sizeof(response) - 4);
response[sizeof(response) - 2] = 0;
printf("Failed to register with wproc manager: %s\n", response);
return 1;
}
enter_worker(sd, start_cmd);
free_worker_memory(WPROC_FORCE);
free_memory(get_global_macros());
return 0;
}
/*
* only handles logfile for now, which we stash in macros to
* make sure we can log *somewhere* in case the new path is
* completely inaccessible.
*/
static int test_configured_paths(void)
{
FILE *fp;
nagios_macros *mac;
mac = get_global_macros();
fp = fopen(log_file, "a+");
if (!fp) {
/*
* we do some variable trashing here so logit() can
* open the old logfile (if any), in case we got a
* restart command or a SIGHUP
*/
char *value_absolute = log_file;
log_file = mac->x[MACRO_LOGFILE];
logit(NSLOG_CONFIG_ERROR, TRUE, "Error: Failed to open logfile '%s' for writing: %s\n", value_absolute, strerror(errno));
return ERROR;
}
fclose(fp);
/* save the macro */
mac->x[MACRO_LOGFILE] = log_file;
return OK;
}
int main(int argc, char **argv) {
int result;
int error = FALSE;
int display_license = FALSE;
int display_help = FALSE;
int c = 0;
struct tm *tm, tm_s;
time_t now;
char datestring[256];
nagios_macros *mac;
const char *worker_socket = NULL;
int i;
#ifdef HAVE_SIGACTION
struct sigaction sig_action;
#endif
#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'},
{"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'},
{0, 0, 0, 0}
};
#define getopt(argc, argv, o) getopt_long(argc, argv, o, long_options, &option_index)
#endif
memset(&loadctl, 0, sizeof(loadctl));
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) {
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 */
test_scheduling = TRUE;
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 'x':
printf("Warning: -x is deprecated and will be removed\n");
break;
default:
break;
}
}
#ifdef DEBUG_MEMORY
mtrace();
#endif
/* if we're a worker we can skip everything below */
if(worker_socket) {
exit(nagios_core_worker(worker_socket));
}
/* Initialize configuration variables */
init_main_cfg_vars(1);
init_shared_cfg_vars(1);
if(daemon_mode == FALSE) {
printf("\nNagios Core %s\n", PROGRAM_VERSION);
printf("Copyright (c) 2009-present 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");
printf("Website: https://www.nagios.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");
cleanup();
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(" -s, --test-scheduling Shows projected/recommended check scheduling and other\n");
printf(" diagnostic info based on the current configuration files.\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 Nagios 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("\n");
printf("Visit the Nagios website at https://www.nagios.org/ for bug fixes, new\n");
printf("releases, online documentation, FAQs, information on subscribing to\n");
printf("the mailing lists, and commercial support options for Nagios.\n");
printf("\n");
cleanup();
exit(ERROR);
}
/*
* 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");
cleanup();
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.
*/
#ifdef HAVE_SIGACTION
sig_action.sa_sigaction = NULL;
sig_action.sa_handler = handle_sigxfsz;
sigfillset(&sig_action.sa_mask);
sig_action.sa_flags = SA_NODEFER|SA_RESTART;
sigaction(SIGXFSZ, &sig_action, NULL);
#else
signal(SIGXFSZ, handle_sigxfsz);
#endif
/*
* let's go to town. We'll be noisy if we're verifying config
* or running scheduling tests.
*/
if(verify_config || test_scheduling || precache_objects) {
reset_variables();
/*
* if we don't beef up our resource limits as much as
* we can, it's quite possible we'll run headlong into
* EAGAIN due to too many processes when we try to
* drop privileges later.
*/
set_loadctl_defaults();
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");
cleanup();
exit(EXIT_FAILURE);
}
if(verify_config)
printf(" Read main config file okay...\n");
/* drop privileges */
if((result = drop_privileges(nagios_user, nagios_group)) == ERROR) {
printf(" Failed to drop privileges. Aborting.");
cleanup();
exit(EXIT_FAILURE);
}
/*
* this must come after dropping privileges, so we make
* sure to test access permissions as the right user.
*/
if (!verify_config && test_configured_paths() == ERROR) {
printf(" One or more path problems detected. Aborting.\n");
cleanup();
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, "nagios.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", 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 Nagios, 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");
cleanup();
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 Nagios, 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");
cleanup();
exit(EXIT_FAILURE);
}
if(verify_config) {
printf("\nThings look okay - No serious problems were detected during the pre-flight check\n");
}
/* scheduling tests need a bit more than config verifications */
if(test_scheduling == TRUE) {
/* we'll need the event queue here so we can time insertions */
init_event_queue();
timing_point("Done initializing event queue\n");
/* read initial service and host state information */
initialize_retention_data(config_file);
read_initial_state_information();
timing_point("Retention data and initial state parsed\n");
/* initialize the event timing loop */
init_timing_loop();
timing_point("Timing loop initialized\n");
/* display scheduling information */
display_scheduling_info();
}
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();
cleanup();
my_free(config_file);
my_free(config_file_dir);
exit(result);
}
/* else start to monitor things... */
else {
/*
* 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], '/'))
nagios_binary_path = nspath_absolute(argv[0], NULL);
else
nagios_binary_path = strdup(argv[0]);
if (!nagios_binary_path) {
logit(NSLOG_RUNTIME_ERROR, TRUE, "Error: Unable to allocate memory for nagios_binary_path\n");
cleanup();
exit(EXIT_FAILURE);
}
if (!(nagios_iobs = iobroker_create())) {
logit(NSLOG_RUNTIME_ERROR, TRUE, "Error: Failed to create IO broker set: %s\n",
strerror(errno));
cleanup();
exit(EXIT_FAILURE);
}
/* keep monitoring things until we get a shutdown command */
do {
/* reset internal book-keeping (in case we're restarting) */
wproc_num_workers_spawned = wproc_num_workers_online = 0;
caught_signal = sigshutdown = FALSE;
sig_id = 0;
/* reset program variables */
reset_variables();
timing_point("Variables reset\n");
/* get PID */
nagios_pid = (int)getpid();
/* read in the configuration files (main and resource config files) */
result = read_main_config_file(config_file);
if (result != OK) {
logit(NSLOG_CONFIG_ERROR, TRUE, "Error: Failed to process config file '%s'. Aborting\n", config_file);
cleanup();
exit(EXIT_FAILURE);
}
timing_point("Main config file read\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);
my_free(mac->x[MACRO_PROCESSSTARTTIME]);
asprintf(&mac->x[MACRO_PROCESSSTARTTIME], "%llu", (unsigned long long)program_start);
/* 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());
cleanup();
exit(EXIT_FAILURE);
}
/* get new PID */
nagios_pid = (int)getpid();
}
/* 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);
}
if (test_path_access(nagios_binary_path, X_OK)) {
logit(NSLOG_RUNTIME_ERROR, TRUE, "Error: failed to access() %s: %s\n", nagios_binary_path, strerror(errno));
logit(NSLOG_RUNTIME_ERROR, TRUE, "Error: Spawning workers will be impossible. Aborting.\n");
cleanup();
exit(EXIT_FAILURE);
}
if (test_configured_paths() == ERROR) {
/* error has already been logged */
cleanup();
exit(EXIT_FAILURE);
}
/* this must be logged after we read config data, as user may have changed location of main log file */
logit(NSLOG_PROCESS_INFO, TRUE, "Nagios %s starting... (PID=%d)\n", 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);
/* open debug log now that we're the right user */
open_debug_log();
#ifdef USE_EVENT_BROKER
/* initialize modules */
neb_init_modules();
neb_init_callback_list();
#endif
timing_point("NEB module API initialized\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
*/
if (qh_init(qh_socket_path ? qh_socket_path : DEFAULT_QUERY_SOCKET) != OK) {
logit(NSLOG_RUNTIME_ERROR, TRUE, "Error: Failed to initialize query handler. Aborting\n");
exit(EXIT_FAILURE);
}
timing_point("Query handler initialized\n");
#ifdef ENABLE_NERD
nerd_init();
timing_point("NERD initialized\n");
#endif
/* initialize check workers */
if(init_workers(num_check_workers) < 0) {
logit(NSLOG_RUNTIME_ERROR, TRUE, "Failed to spawn workers. Aborting\n");
exit(EXIT_FAILURE);
}
timing_point("%u workers spawned\n", wproc_num_workers_spawned);
i = 0;
while (i < 50 && wproc_num_workers_online < wproc_num_workers_spawned) {
iobroker_poll(nagios_iobs, 50);
i++;
}
timing_point("%u workers connected\n", wproc_num_workers_online);
/* now that workers have arrived we can set the defaults */
set_loadctl_defaults();
#ifdef USE_EVENT_BROKER
/* load modules */
if (neb_load_all_modules() != OK) {
logit(NSLOG_CONFIG_ERROR, ERROR, "Error: Module loading failed. Aborting.\n");
/* if we're dumping core, we must remove all dl-files */
if (daemon_dumps_core)
neb_unload_all_modules(NEBMODULE_FORCE_UNLOAD, NEBMODULE_NEB_SHUTDOWN);
cleanup();
exit(EXIT_FAILURE);
}
timing_point("Modules loaded\n");
/* send program data to broker */
broker_program_state(NEBTYPE_PROCESS_PRELAUNCH, NEBFLAG_NONE, NEBATTR_NONE, NULL);
timing_point("First callback made\n");
#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 Nagios 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*/
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 Nagios from the command line with the -v option to verify your config before restarting. (PID=%d)\n", (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(TRUE);
}
#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);
}
timing_point("Object configuration parsed and understood\n");
#ifdef DETECT_RLIMIT_PROBLEM
/* lets do a quick system limit detection
to determine if we're likely to run into any
problems. */
rlimit_problem_detection(num_check_workers);
timing_point("Limit detection");
#endif
/* write the objects.cache file */
fcache_objects(object_cache_file);
timing_point("Objects cached\n");
init_event_queue();
timing_point("Event queue initialized\n");
#ifdef USE_EVENT_BROKER
/* send program data to broker */
broker_program_state(NEBTYPE_PROCESS_START, NEBFLAG_NONE, NEBATTR_NONE, NULL);
#endif
/* initialize status data only if we're starting (no restarts) */
if(sigrestart == FALSE) {
initialize_status_data(config_file);
timing_point("Status data initialized\n");
}
/* initialize scheduled downtime data */
initialize_downtime_data();
timing_point("Downtime data initialized\n");
/* read initial service and host state information */
initialize_retention_data(config_file);
timing_point("Retention data initialized\n");
read_initial_state_information();
timing_point("Initial state information read\n");
/* initialize comment data */
initialize_comment_data();
timing_point("Comment data initialized\n");
/* initialize performance data */
initialize_performance_data(config_file);
timing_point("Performance data initialized\n");
/* initialize the event timing loop */
init_timing_loop();
timing_point("Event timing loop initialized\n");
/* initialize check statistics */
init_check_stats();
timing_point("check stats initialized\n");
/* check for updates */
check_for_nagios_updates(FALSE, TRUE);
timing_point("Update check concluded\n");
/* update all status data (with retained information) */
update_all_status_data();
timing_point("Status data updated\n");
/* log initial host and service state */
log_host_states(INITIAL_STATES, NULL);
log_service_states(INITIAL_STATES, NULL);
timing_point("Initial states logged\n");
/* reset the restart flag */
sigrestart = FALSE;
/* fire up command file worker */
launch_command_file_worker();
timing_point("Command file worker launched\n");
#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], "%llu", (unsigned long long)event_start);
timing_point("Entering event execution loop\n");
/***** start monitoring all services *****/
/* (doesn't return until a restart or shutdown signal is encountered) */
event_execution_loop();
/*
* immediately deinitialize the query handler so it
* can remove modules that have stashed data with it
*/
qh_deinit(qh_socket_path ? qh_socket_path : DEFAULT_QUERY_SOCKET);
/* 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 lose them */
/* did we catch a signal? */
if(caught_signal == TRUE) {
if(sig_id == SIGHUP)
logit(NSLOG_PROCESS_INFO, TRUE, "Caught SIGHUP, restarting...\n");
}
#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();
/* clean up performance data */
cleanup_performance_data();
/* clean up the scheduled downtime data */
cleanup_downtime_data();
/* clean up comment data */
free_comment_data();
/* clean up the status data if we are not restarting */
if(sigrestart == FALSE) {
cleanup_status_data(TRUE);
}
free_worker_memory(WPROC_FORCE);
/* shutdown stuff... */
if(sigshutdown == TRUE) {
shutdown_command_file_worker();
iobroker_destroy(nagios_iobs, IOBROKER_CLOSE_SOCKETS);
nagios_iobs = NULL;
/* log a shutdown message */
logit(NSLOG_PROCESS_INFO, TRUE, "Successfully shutdown... (PID=%d)\n", (int)getpid());
}
/* try and collect any zombie processes */
if (sigrestart == TRUE) {
int status = 0;
pid_t child_pid;
log_debug_info(DEBUGL_PROCESS, 1, "Calling waitpid() on all children...\n");
while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) {
log_debug_info(DEBUGL_PROCESS, 2, " * child PID: (%d), status: (%d)\n", child_pid, status);
}
log_debug_info(DEBUGL_PROCESS, 1, "All children have been wait()ed on\n");
cleanup();
}
/* close debug log */
close_debug_log();
}
while(sigrestart == TRUE && sigshutdown == FALSE);
if(daemon_mode == TRUE)
unlink(lock_file);
/* free misc memory */
cleanup();
my_free(lock_file);
my_free(config_file);
my_free(config_file_dir);
my_free(nagios_binary_path);
}
return OK;
}