Imported Upstream version 4.4.4

This commit is contained in:
Mario Fetka 2019-08-03 18:28:19 +02:00
parent 797bccfa31
commit 07dcbdceca
28 changed files with 336 additions and 152 deletions

View File

@ -3,6 +3,25 @@ Nagios Core 4 Change Log
########################
4.4.4 - 2019-07-29
------------------
* Fixed log rotation logic to not repeatedly schedule rotation on a DST change (#610, #626) (Jaroslav Jindrak & Sebastian Wolf)
* Fixed $SERVICEPROBLEMID$ to be reset after service recovery (#621) (Sebastian Wolf)
* Fixed defunct worker processes appearing after nagios was reloaded (#441, #620) (Sebastian Wolf)
* Fixed main nagios thread to release nagios.qh on a closed connection (#635) (Sebastian Wolf)
* Fixed semicolon escaping to remove prepended backslash (\) (#643) (Sebastian Wolf)
* Fixed 'Checks of this host have been disabled' message showing on passive-only hosts (#632) (Vojtěch Širůček & Sebastian Wolf)
* Fixed last_hard_state showing the current hard state when service status is brokered (#633) (Sebastian Wolf)
* Fixed long plugin output (>8KB) occasionally getting truncated (#625) (Sebastian Wolf)
* Fixed check scheduling for objects with large check_intervals and small timeperiods (#647) (Sebastian Wolf)
* Fixed SOFT recoveries sending when services had HARD recovery some time after host recovery (#651) (Sebastian Wolf)
* Fixed incorrect permissions on debugging builds of FreeBSD (#420) (Sebastian Wolf)
* Fixed NEB callback lists being partially orphaned when multiple modules subscribe to one callback (#590) (Sebastian Wolf)
* Fixed memory leaks in run_async_service_check(), run_async_host_check() when checks are brokered (#664) (Sebastian Wolf)
* Fixed potential XSS in main.php, map.php (#671, #672) (Jak Gibb)
* Removed NEB brokering for nagios daemonization, since daemonization occurs before NEB initialization (#591) (Sebastian Wolf)
4.4.3 - 2019-01-15
------------------
FIXES

3
THANKS
View File

@ -130,6 +130,7 @@ wrong, please let me know.
* Ingo Lantschner
* Ivan Kuncl
* Jacob Lundqvist
* Jak Gibb
* James "Showkilr" Peterson
* James Maddison
* James Moseley
@ -290,6 +291,7 @@ wrong, please let me know.
* Sam Howard
* Sean Finney
* Sebastian Guarino
* Sebastian Wolf
* Sebastien Barbereau
* Sergio Guzman
* Shad Lords
@ -337,6 +339,7 @@ wrong, please let me know.
* Uwe Knop
* Uwe Knop
* Vadim Okun
* Vojtěch Širůček
* Volkan Yazici
* Volker Aust
* William Leibzon

View File

@ -173,19 +173,13 @@ devclean: distclean
rm -f wpres-phash.h
install:
$(MAKE) install-basic
$(MAKE) strip-post-install
$(INSTALL) -m 775 $(INSTALL_OPTS) -d $(DESTDIR)$(BINDIR)
$(INSTALL) -s -m 774 $(INSTALL_OPTS) @nagios_name@ $(DESTDIR)$(BINDIR)
$(INSTALL) -s -m 774 $(INSTALL_OPTS) @nagiostats_name@ $(DESTDIR)$(BINDIR)
install-unstripped:
$(MAKE) install-basic
install-basic:
$(INSTALL) -m 775 $(INSTALL_OPTS) -d $(DESTDIR)$(BINDIR)
$(INSTALL) -m 774 $(INSTALL_OPTS) @nagios_name@ $(DESTDIR)$(BINDIR)
$(INSTALL) -m 774 $(INSTALL_OPTS) @nagiostats_name@ $(DESTDIR)$(BINDIR)
strip-post-install:
$(STRIP) $(DESTDIR)$(BINDIR)/@nagios_name@
$(STRIP) $(DESTDIR)$(BINDIR)/@nagiostats_name@
$(INSTALL) -m 774 $(INSTALL_OPTS) nagios $(DESTDIR)$(BINDIR)
$(INSTALL) -m 774 $(INSTALL_OPTS) nagiostats $(DESTDIR)$(BINDIR)
.PHONY: libnagios

View File

@ -134,7 +134,7 @@ int run_scheduled_service_check(service *svc, int check_options, double latency)
* don't get all checks subject to that timeperiod
* constraint scheduled at the same time
*/
svc->next_check += ranged_urand(0, check_window(svc));
svc->next_check = reschedule_within_timeperiod(next_valid_time, svc->check_period_ptr, check_window(svc));
}
svc->should_be_scheduled = TRUE;
@ -306,6 +306,7 @@ int run_async_service_check(service *svc, int check_options, double latency, int
clear_volatile_macros_r(&mac);
svc->latency = old_latency;
free_check_result(cr);
my_free(cr);
my_free(processed_command);
return OK;
}
@ -701,11 +702,13 @@ static inline void host_is_active(host *hst)
*****************************************************************************/
static inline void debug_async_service(service *svc, check_result *cr)
{
log_debug_info(DEBUGL_CHECKS, 0, "** Handling %s async check result for service '%s' on host '%s' from '%s'...\n",
log_debug_info(DEBUGL_CHECKS, 0, "** Handling %s async check result for service '%s' on host '%s' from '%s'... current state %d last_hard_state %d \n",
(cr->check_type == CHECK_TYPE_ACTIVE) ? "ACTIVE" : "PASSIVE",
svc->description,
svc->host_name,
check_result_source(cr));
check_result_source(cr),
svc->current_state,
svc->last_hard_state);
log_debug_info(DEBUGL_CHECKS, 1,
" * OPTIONS: %d, SCHEDULED: %d, RESCHEDULE: %d, EXITED OK: %d, RETURN CODE: %d, OUTPUT:\n%s\n",
@ -1215,6 +1218,8 @@ int handle_async_service_check_result(service *svc, check_result *cr)
return ERROR;
}
int new_last_hard_state = svc->last_hard_state;
if (cr->check_type == CHECK_TYPE_PASSIVE) {
if (service_is_passive(svc, cr) == FALSE) {
return ERROR;
@ -1339,13 +1344,14 @@ int handle_async_service_check_result(service *svc, check_result *cr)
/* service hard state change, because if host is down/unreachable
the docs say we have a hard state change (but no notification) */
if (hst->current_state != HOST_UP && svc->last_hard_state != svc->current_state) {
if (hst->current_state != HOST_UP && new_last_hard_state != svc->current_state) {
log_debug_info(DEBUGL_CHECKS, 2, "Host is down or unreachable, forcing service hard state change\n");
hard_state_change = TRUE;
svc->state_type = HARD_STATE;
svc->last_hard_state = svc->current_state;
new_last_hard_state = svc->current_state;
svc->current_attempt = svc->max_attempts;
}
if (check_host == TRUE) {
@ -1484,7 +1490,7 @@ int handle_async_service_check_result(service *svc, check_result *cr)
}
if (svc->current_attempt >= svc->max_attempts &&
(svc->current_state != svc->last_hard_state || svc->state_type == SOFT_STATE)) {
(svc->current_state != new_last_hard_state || svc->state_type == SOFT_STATE)) {
log_debug_info(DEBUGL_CHECKS, 2, "Service had a HARD STATE CHANGE!!\n");
@ -1498,7 +1504,17 @@ int handle_async_service_check_result(service *svc, check_result *cr)
}
/* handle some acknowledgement things and update last_state_change */
/* This is a temporary fix that lets us avoid changing any function boundaries in a bugfix release */
/* @fixme 4.5.0 - refactor so that each specific struct member is only modified in */
/* service_state_or_hard_state_type_change() or handle_async_service_check_result(), not both.*/
int original_last_hard_state = svc->last_hard_state;
service_state_or_hard_state_type_change(svc, state_change, hard_state_change, &log_event, &handle_event);
if (original_last_hard_state != svc->last_hard_state) {
/* svc->last_hard_state now gets written only after the service status is brokered */
new_last_hard_state = svc->last_hard_state;
svc->last_hard_state = original_last_hard_state;
}
/* fix edge cases where log_event wouldn't have been set or won't be */
if (svc->current_state != STATE_OK && svc->state_type == SOFT_STATE) {
@ -1542,7 +1558,7 @@ int handle_async_service_check_result(service *svc, check_result *cr)
constraints. Add a random amount so we don't get all checks
subject to that timeperiod constraint scheduled at the same time */
if (next_valid_time > preferred_time) {
svc->next_check += ranged_urand(0, check_window(svc));
svc->next_check = reschedule_within_timeperiod(next_valid_time, svc->check_period_ptr, check_window(svc));
}
schedule_service_check(svc, svc->next_check, CHECK_OPTION_NONE);
@ -1594,6 +1610,9 @@ int handle_async_service_check_result(service *svc, check_result *cr)
}
if (handle_event == TRUE) {
log_debug_info(DEBUGL_CHECKS, 0, "IS TIME FOR HANDLE THE SERVICE KTHX");
debug_async_service(svc, cr);
handle_service_event(svc);
}
@ -1601,17 +1620,20 @@ int handle_async_service_check_result(service *svc, check_result *cr)
switch into a HARD state and reset the attempts */
if (svc->current_state == STATE_OK && state_change == TRUE) {
/* Reset attempts and problem state */
/* Problem state starts regardless of SOFT/HARD status. */
svc->last_problem_id = svc->current_problem_id;
svc->current_problem_id = 0L;
/* Reset attempts */
if (hard_state_change == TRUE) {
svc->last_problem_id = svc->current_problem_id;
svc->current_problem_id = 0L;
svc->current_notification_number = 0;
svc->host_problem_at_last_check = FALSE;
}
/* Set OK to a hard state */
svc->last_hard_state_change = svc->last_check;
svc->last_hard_state = svc->current_state;
new_last_hard_state = svc->current_state;
/* Set OK to a hard state */
svc->current_attempt = 1;
svc->state_type = HARD_STATE;
}
@ -1632,10 +1654,17 @@ int handle_async_service_check_result(service *svc, check_result *cr)
broker_service_check(NEBTYPE_SERVICECHECK_PROCESSED, NEBFLAG_NONE, NEBATTR_NONE, svc, svc->check_type, cr->start_time, cr->finish_time, NULL, svc->latency, svc->execution_time, service_check_timeout, cr->early_timeout, cr->return_code, NULL, NULL, cr);
#endif
svc->has_been_checked = TRUE;
update_service_status(svc, FALSE);
update_service_performance_data(svc);
/* last_hard_state cleanup
* This occurs after being brokered so that last_hard_state refers to the previous logged hard state,
* rather than the current hard state
*/
svc->last_hard_state = new_last_hard_state;
my_free(old_plugin_output);
return OK;
@ -2224,6 +2253,8 @@ int handle_async_host_check_result(host *hst, check_result *cr)
return ERROR;
}
int new_last_hard_state = hst->last_hard_state;
if (cr->check_type == CHECK_TYPE_PASSIVE) {
if (host_is_passive(hst, cr) == FALSE) {
return ERROR;
@ -2376,7 +2407,7 @@ int handle_async_host_check_result(host *hst, check_result *cr)
}
}
if (hst->current_attempt >= hst->max_attempts && hst->current_state != hst->last_hard_state) {
if (hst->current_attempt >= hst->max_attempts && hst->current_state != new_last_hard_state) {
log_debug_info(DEBUGL_CHECKS, 2, "Host had a HARD STATE CHANGE!!\n");
@ -2387,7 +2418,15 @@ int handle_async_host_check_result(host *hst, check_result *cr)
}
/* handle some acknowledgement things and update last_state_change */
/* @fixme 4.5.0 - See similar comment in handle_async_service_check_result() */
int original_last_hard_state = hst->last_hard_state;
host_state_or_hard_state_type_change(hst, state_change, hard_state_change, &log_event, &handle_event, &send_notification);
if (original_last_hard_state != hst->last_hard_state) {
/* svc->last_hard_state now gets written only after the service status is brokered */
new_last_hard_state = hst->last_hard_state;
hst->last_hard_state = original_last_hard_state;
}
record_last_host_state_ended(hst);
@ -2425,7 +2464,7 @@ int handle_async_host_check_result(host *hst, check_result *cr)
constraints. Add a random amount so we don't get all checks
subject to that timeperiod constraint scheduled at the same time */
if (next_valid_time > preferred_time) {
hst->next_check += ranged_urand(0, check_window(hst));
hst->next_check = reschedule_within_timeperiod(next_valid_time, hst->check_period_ptr, check_window(hst));
}
schedule_host_check(hst, hst->next_check, CHECK_OPTION_NONE);
@ -2495,6 +2534,12 @@ int handle_async_host_check_result(host *hst, check_result *cr)
update_host_status(hst, FALSE);
update_host_performance_data(hst);
/* last_hard_state cleanup
* This occurs after being brokered so that last_hard_state refers to the previous logged hard state,
* rather than the current hard state
*/
hst->last_hard_state = new_last_hard_state;
/* free memory */
my_free(old_plugin_output);
@ -3000,7 +3045,7 @@ int run_scheduled_host_check(host *hst, int check_options, double latency)
if ((time_is_valid == FALSE)
&& (check_time_against_period(next_valid_time, hst->check_period_ptr) == ERROR)) {
hst->next_check = preferred_time + ranged_urand(0, check_window(hst));
hst->next_check = reschedule_within_timeperiod(next_valid_time, hst->check_period_ptr, check_window(hst));
logit(NSLOG_RUNTIME_WARNING, TRUE, "Warning: Check of host '%s' could not be rescheduled properly. Scheduling check for %s...\n", hst->name, ctime(&preferred_time));
@ -3016,7 +3061,7 @@ int run_scheduled_host_check(host *hst, int check_options, double latency)
* don't get all checks subject to that timeperiod
* constraint scheduled at the same time
*/
hst->next_check += ranged_urand(0, check_window(hst));
hst->next_check = reschedule_within_timeperiod(next_valid_time, hst->check_period_ptr, check_window(hst));
}
hst->should_be_scheduled = TRUE;
@ -3188,6 +3233,7 @@ int run_async_host_check(host *hst, int check_options, double latency, int sched
clear_volatile_macros_r(&mac);
hst->latency = old_latency;
free_check_result(cr);
my_free(cr);
my_free(processed_command);
return OK;
}

View File

@ -165,7 +165,7 @@ static int command_input_handler(int sd, int events, void *discard) {
}
if ((cmd_ret = process_external_command1(buf)) != CMD_ERROR_OK) {
logit(NSLOG_EXTERNAL_COMMAND | NSLOG_RUNTIME_WARNING, TRUE, "External command error: %s\n", cmd_error_strerror(cmd_ret));
logit(NSLOG_EXTERNAL_COMMAND | NSLOG_RUNTIME_WARNING, TRUE, "External command %s returned error %s\n", buf, cmd_error_strerror(cmd_ret));
}
}

View File

@ -351,12 +351,13 @@ void init_timing_loop(void) {
*/
check_delay =
mult_factor * scheduling_info.service_inter_check_delay;
if(check_delay > check_window(temp_service)) {
time_t check_window = reschedule_within_timeperiod(next_valid_time, temp_service->check_period_ptr, check_window(temp_service)) - current_time;
if(check_delay > check_window) {
log_debug_info(DEBUGL_EVENTS, 0,
" Fixing check time %lu secs too far away\n",
check_delay - check_window(temp_service));
check_delay - check_window);
fixed_services++;
check_delay = ranged_urand(0, check_window(temp_service));
check_delay = check_window;
log_debug_info(DEBUGL_EVENTS, 0, " New check offset: %d\n",
check_delay);
}
@ -364,14 +365,12 @@ void init_timing_loop(void) {
log_debug_info(DEBUGL_EVENTS, 2, "Preferred Check Time: %lu --> %s\n", (unsigned long)temp_service->next_check, ctime(&temp_service->next_check));
/* make sure the service can actually be scheduled when we want */
is_valid_time = check_time_against_period(temp_service->next_check, temp_service->check_period_ptr);
if(is_valid_time == ERROR) {
log_debug_info(DEBUGL_EVENTS, 2, "Preferred Time is Invalid In Timeperiod '%s': %lu --> %s\n", temp_service->check_period_ptr->name, (unsigned long)temp_service->next_check, ctime(&temp_service->next_check));
get_next_valid_time(temp_service->next_check, &next_valid_time, temp_service->check_period_ptr);
temp_service->next_check =
(time_t)(next_valid_time + check_delay);
temp_service->next_check = reschedule_within_timeperiod(next_valid_time, temp_service->check_period_ptr, check_window(temp_service));
}
log_debug_info(DEBUGL_EVENTS, 2, "Actual Check Time: %lu --> %s\n", (unsigned long)temp_service->next_check, ctime(&temp_service->next_check));
@ -509,7 +508,7 @@ void init_timing_loop(void) {
log_debug_info(DEBUGL_EVENTS, 1, "Fixing check time (off by %lu)\n",
check_delay - check_window(temp_host));
fixed_hosts++;
check_delay = ranged_urand(0, check_window(temp_host));
check_delay = reschedule_within_timeperiod(next_valid_time, temp_host->check_period_ptr, check_window(temp_host));
}
temp_host->next_check = (time_t)(current_time + check_delay);
@ -1559,31 +1558,43 @@ void adjust_check_scheduling(void) {
/* log_debug_info(DEBUGL_SCHEDULING, 2, "Check %d: offset %.3fs, new run time %lu.%06ld.\n", i, new_run_time_offset, (unsigned long)new_run_time.tv_sec, (long)new_run_time.tv_usec);
*/
squeue_change_priority_tv(nagios_squeue, sq_event, &new_run_time);
if (temp_event->run_time != new_run_time.tv_sec)
temp_event->run_time = new_run_time.tv_sec;
/* 06/2019 - moved switch earlier in the for loop because we need to check against the check_period before rescheduling the event */
switch (temp_event->event_type) {
case EVENT_HOST_CHECK:
temp_host = temp_event->event_data;
if (check_time_against_period(new_run_time.tv_sec, temp_host->check_period_ptr) == ERROR) {
continue;
}
if (temp_host->next_check != new_run_time.tv_sec) {
temp_host->next_check = new_run_time.tv_sec;
temp_event->run_time = new_run_time.tv_sec;
update_host_status(temp_host, FALSE);
}
break;
case EVENT_SERVICE_CHECK:
temp_service = temp_event->event_data;
if (check_time_against_period(new_run_time.tv_sec, temp_service->check_period_ptr) == ERROR) {
continue;
}
if (temp_service->next_check != new_run_time.tv_sec) {
temp_service->next_check = new_run_time.tv_sec;
temp_event->run_time = new_run_time.tv_sec;
update_service_status(temp_service, FALSE);
}
break;
default:
break;
}
}
squeue_change_priority_tv(nagios_squeue, sq_event, &new_run_time);
if (temp_event->run_time != new_run_time.tv_sec) {
temp_event->run_time = new_run_time.tv_sec;
}
} /* end for loop */
log_debug_info(DEBUGL_FUNCTIONS, 0, "adjust_check_scheduling() end\n");

View File

@ -902,6 +902,8 @@ int main(int argc, char **argv) {
/* try and collect any zombie processes */
if (sigrestart == TRUE) {
sleep(1);
int status = 0;
pid_t child_pid;
log_debug_info(DEBUGL_PROCESS, 1, "Calling waitpid() on all children...\n");

View File

@ -406,30 +406,28 @@ int neb_register_callback(int callback_type, void *mod_handle, int priority, int
new_callback->priority = priority;
new_callback->module_handle = mod_handle;
new_callback->callback_func = callback_func;
new_callback->next = NULL;
/* add new function to callback list, sorted by priority (first come, first served for same priority) */
new_callback->next = NULL;
if(neb_callback_list[callback_type] == NULL)
neb_callback_list[callback_type] = new_callback;
else {
last_callback = NULL;
for(temp_callback = neb_callback_list[callback_type]; temp_callback != NULL; temp_callback = temp_callback->next) {
if(temp_callback->priority > new_callback->priority)
break;
last_callback = temp_callback;
}
if(last_callback == NULL)
neb_callback_list[callback_type] = new_callback;
else {
if(temp_callback == NULL)
last_callback->next = new_callback;
else {
new_callback->next = temp_callback;
last_callback->next = new_callback;
}
for(last_callback = NULL, temp_callback = neb_callback_list[callback_type];
temp_callback != NULL;
last_callback = temp_callback, temp_callback = temp_callback->next) {
if(new_callback->priority < temp_callback->priority) {
break;
}
}
new_callback->next = temp_callback;
if(last_callback == NULL) {
neb_callback_list[callback_type] = new_callback;
}
else {
last_callback->next = new_callback;
}
return OK;
}

View File

@ -1377,6 +1377,34 @@ void get_next_valid_time(time_t pref_time, time_t *valid_time, timeperiod *tperi
_get_next_valid_time(pref_time, valid_time, tperiod);
}
/* Given the next valid time in a timeperiod, the timeperiod itself, and the normal rescheduling window, */
/* return the next check time */
time_t reschedule_within_timeperiod(time_t starting_valid_time, timeperiod* check_period_ptr, time_t check_window) {
log_debug_info(DEBUGL_FUNCTIONS, 0, "reschedule_within_timeperiod");
/* First, find the next time that is outside the timeperiod */
time_t ending_valid_time;
_get_next_invalid_time(starting_valid_time, &ending_valid_time, check_period_ptr);
/* _get_next_invalid_time returns the first invalid minute. The maximum allowable should be a minute earlier */
ending_valid_time -= 60;
/* Determine whether the next invalid time or the outside of the check_window is closer */
time_t max_nudge = ending_valid_time - starting_valid_time;
/* max_nudge will be less than zero when there's no 'invalid' time */
/* Otherwise, use the closest of the two times to reschedule the check */
if (max_nudge <= 0 || max_nudge > check_window) {
log_debug_info(DEBUGL_CHECKS, 0, "Using raw check_window instead of timeperiod for scheduling \n");
max_nudge = check_window;
}
/* Reschedule within the smaller range */
return starting_valid_time + ranged_urand(0, max_nudge);
}
/* tests if a date range covers just a single day */
int is_daterange_single_day(daterange *dr) {
@ -1561,6 +1589,7 @@ time_t get_next_log_rotation_time(void) {
struct tm *t, tm_s;
int is_dst_now = FALSE;
time_t run_time;
int expected_mday;
time(&current_time);
t = localtime_r(&current_time, &tm_s);
@ -1594,8 +1623,6 @@ time_t get_next_log_rotation_time(void) {
if(is_dst_now == TRUE && t->tm_isdst == 0)
run_time += 3600;
else if(is_dst_now == FALSE && t->tm_isdst > 0)
run_time -= 3600;
return run_time;
}
@ -2025,11 +2052,6 @@ int daemon_init(void)
val |= FD_CLOEXEC;
fcntl(lockfile, F_SETFD, val);
#ifdef USE_EVENT_BROKER
/* send program data to broker */
broker_program_state(NEBTYPE_PROCESS_DAEMONIZE, NEBFLAG_NONE, NEBATTR_NONE, NULL);
#endif
return OK;
}

View File

@ -749,7 +749,7 @@ static int handle_worker_result(int sd, int events, void *arg)
remove_worker(wp);
fanout_destroy(wp->jobs, fo_reassign_wproc_job);
wp->jobs = NULL;
wproc_destroy(wp, 0);
wproc_destroy(wp, WPROC_FORCE);
return 0;
}
while ((buf = worker_ioc2msg(wp->ioc, &size, 0))) {

View File

@ -195,21 +195,17 @@ devclean: distclean
install:
$(MAKE) install-basic
$(MAKE) strip-post-install
install-unstripped:
$(MAKE) install-basic
install-basic:
$(INSTALL) -m 775 $(INSTALL_OPTS) -d $(DESTDIR)$(CGIDIR)
for file in *.cgi; do \
$(INSTALL) -m 775 $(INSTALL_OPTS) $$file $(DESTDIR)$(CGIDIR); \
done
strip-post-install:
install-basic:
$(INSTALL) -m 775 $(INSTALL_OPTS) -d $(DESTDIR)$(CGIDIR)
for file in *.cgi; do \
$(STRIP) $(DESTDIR)$(CGIDIR)/$$file; \
$(INSTALL) -s -m 775 $(INSTALL_OPTS) $$file $(DESTDIR)$(CGIDIR); \
done
.PHONY: libnagios

View File

@ -1834,6 +1834,9 @@ void compute_subject_availability(avail_subject *subject, time_t current_time) {
#ifdef DEBUG
printf("--- BEGINNING/MIDDLE SECTION ---<BR>\n");
#endif
#ifdef DEBUG2
printf("<pre>");
#endif
/**********************************/
/* BEGINNING/MIDDLE SECTION */
@ -1941,6 +1944,9 @@ void compute_subject_availability(avail_subject *subject, time_t current_time) {
}
}
#ifdef DEBUG2
printf("</pre>");
#endif
return;
}
@ -1961,15 +1967,15 @@ void compute_subject_availability_times(int first_state, int last_state, time_t
unsigned long start = 0L;
unsigned long end = 0L;
#ifdef DEBUG
#ifdef DEBUG2
if (subject->type == HOST_SUBJECT) {
printf("HOST '%s'...\n", subject->host_name);
printf("\nHOST '%s'...\n", subject->host_name);
}
else {
printf("SERVICE '%s' ON HOST '%s'...\n", subject->service_description, subject->host_name);
printf("\nSERVICE '%s' ON HOST '%s'...\n", subject->service_description, subject->host_name);
}
printf("COMPUTING %d->%d FROM %lu to %lu (%lu seconds) FOR %s<br>\n", first_state, last_state, start_time, end_time, (end_time - start_time), (subject->type == HOST_SUBJECT) ? "HOST" : "SERVICE");
printf("COMPUTING %d->%d FROM %lu to %lu (%lu seconds) FOR %s\n", first_state, last_state, start_time, end_time, (end_time - start_time), (subject->type == HOST_SUBJECT) ? "HOST" : "SERVICE");
#endif
/* clip times if necessary */
@ -2091,6 +2097,7 @@ void compute_subject_availability_times(int first_state, int last_state, time_t
}
}
else {
as->processed_state = AS_NO_DATA;
return;
}
}
@ -2102,6 +2109,10 @@ void compute_subject_availability_times(int first_state, int last_state, time_t
/* save "processed state" info */
as->processed_state = start_state;
#ifdef DEBUG2
printf("PROCESSED_STATE: %d\n", start_state);
#endif
#ifdef DEBUG
printf("PASSED TIME CHECKS, CLIPPED VALUES: START=%lu, END=%lu\n", start_time, end_time);
#endif
@ -2155,6 +2166,7 @@ void compute_subject_downtime(avail_subject *subject, time_t current_time)
int process_chunk = FALSE;
#ifdef DEBUG2
printf("<pre>");
printf("COMPUTE_SUBJECT_DOWNTIME\n");
#endif
@ -2248,6 +2260,10 @@ void compute_subject_downtime(avail_subject *subject, time_t current_time)
compute_subject_downtime_times(start_time, end_time, subject, temp_sd);
}
}
#ifdef DEBUG2
printf("</pre>");
#endif
}
@ -2264,7 +2280,7 @@ void compute_subject_downtime_times(time_t start_time, time_t end_time, avail_su
archived_state *last = NULL;
#ifdef DEBUG2
printf("<P><b>ENTERING COMPUTE_SUBJECT_DOWNTIME_TIMES: start=%lu, end=%lu, t1=%lu, t2=%lu </b></P>", start_time, end_time, t1, t2);
printf("\n<b>ENTERING COMPUTE_SUBJECT_DOWNTIME_TIMES: start=%lu, end=%lu, t1=%lu, t2=%lu </b>\n\n", start_time, end_time, t1, t2);
#endif
/* times are weird, so bail out... */
@ -2278,25 +2294,25 @@ void compute_subject_downtime_times(time_t start_time, time_t end_time, avail_su
/* find starting point in archived state list */
if (sd == NULL) {
#ifdef DEBUG2
printf("<P>TEMP_AS=SUBJECT->AS_LIST </P>");
printf("TEMP_AS=SUBJECT->AS_LIST\n");
#endif
temp_as = subject->as_list;
}
else if (sd->misc_ptr == NULL) {
#ifdef DEBUG2
printf("<P>TEMP_AS=SUBJECT->AS_LIST</P>");
printf("TEMP_AS=SUBJECT->AS_LIST\n");
#endif
temp_as = subject->as_list;
}
else if (sd->misc_ptr->next == NULL) {
#ifdef DEBUG2
printf("<P>TEMP_AS=SD->MISC_PTR</P>");
printf("TEMP_AS=SD->MISC_PTR\n");
#endif
temp_as = sd->misc_ptr;
}
else {
#ifdef DEBUG2
printf("<P>TEMP_AS=SD->MISC_PTR->NEXT</P>");
printf("TEMP_AS=SD->MISC_PTR->NEXT\n");
#endif
temp_as = sd->misc_ptr->next;
}
@ -2307,20 +2323,21 @@ void compute_subject_downtime_times(time_t start_time, time_t end_time, avail_su
}
else if (temp_as->processed_state == AS_PROGRAM_START || temp_as->processed_state == AS_PROGRAM_END || temp_as->processed_state == AS_NO_DATA) {
#ifdef DEBUG2
printf("<P>ENTRY TYPE #1: %d</P>", temp_as->entry_type);
printf("ENTRY TYPE #1: %d\n", temp_as->entry_type);
#endif
part_subject_state = AS_NO_DATA;
}
else {
#ifdef DEBUG2
printf("<P>ENTRY TYPE #2: %d</P>", temp_as->entry_type);
printf("ENTRY TYPE #2: %d\n", temp_as->entry_type);
printf("STATE: %d\n", temp_as->processed_state);
#endif
part_subject_state = temp_as->processed_state;
}
#ifdef DEBUG2
printf("<P>TEMP_AS=%s</P>", (temp_as == NULL) ? "NULL" : "Not NULL");
printf("<P>SD=%s</P>", (sd == NULL) ? "NULL" : "Not NULL");
printf("TEMP_AS=%s\n", (temp_as == NULL) ? "NULL" : "Not NULL");
printf("SD=%s\n\n", (sd == NULL) ? "NULL" : "Not NULL");
#endif
/* temp_as now points to first event to possibly "break" this chunk */
@ -2353,6 +2370,11 @@ void compute_subject_downtime_times(time_t start_time, time_t end_time, avail_su
/* if status changed, we have to calculate */
if (saved_status != temp_as->entry_type) {
/* accommodate status for program start/end */
if (saved_status == AS_PROGRAM_START || saved_status == AS_PROGRAM_END) {
saved_status = temp_as->processed_state;
}
/* is outside schedule time, use end schdule downtime */
if (temp_as->time_stamp > end_time) {
if (saved_stamp < start_time) {
@ -2386,13 +2408,19 @@ void compute_subject_downtime_times(time_t start_time, time_t end_time, avail_su
compute_subject_downtime_part_times(start_time, end_time, part_subject_state, subject);
}
else {
/* is outside scheduled time, use end schdule downtime */
if (last->time_stamp > end_time) {
/* is outside scheduled time, or at the end of the log, so fake the end of scheduled downtime */
#ifdef DEBUG2
printf("<b>LAST ENTRY TYPE: %d</b>\n", last->entry_type);
#endif
if (last->entry_type == AS_PROGRAM_START || last->entry_type == AS_PROGRAM_END) {
/* if we are NOT assuming initial states, then we do not want to add this data into the downtime */
if (last->entry_type == AS_PROGRAM_START && assume_initial_states == FALSE) {
return;
}
compute_subject_downtime_part_times(saved_stamp, end_time, part_subject_state, subject);
} else {
compute_subject_downtime_part_times(saved_stamp, end_time, saved_status, subject);
}
else {
compute_subject_downtime_part_times(saved_stamp, last->time_stamp, saved_status, subject);
}
}
}
@ -3511,7 +3539,13 @@ void write_log_entries(avail_subject *subject)
if (temp_as->next == NULL) {
get_time_string(&t2, end_date_time, sizeof(end_date_time) - 1, SHORT_DATE_TIME);
get_time_breakdown((time_t)(t2 - temp_as->time_stamp), &days, &hours, &minutes, &seconds);
snprintf(duration, sizeof(duration) - 1, "%dd %dh %dm %ds+", days, hours, minutes, seconds);
/* show blank event duration if the end time is past the start time */
if ((t2 - temp_as->time_stamp) > end_date_time) {
snprintf(duration, sizeof(duration), "");
} else {
snprintf(duration, sizeof(duration) - 1, "%dd %dh %dm %ds+", days, hours, minutes, seconds);
}
}
else {
get_time_string(&(temp_as->next->time_stamp), end_date_time, sizeof(end_date_time) - 1, SHORT_DATE_TIME);
@ -4340,8 +4374,8 @@ void display_host_availability(void)
printf("<td CLASS='hostUP' rowspan=3>UP</td>");
printf("<td CLASS='dataEven'>Unscheduled</td>");
printf("<td CLASS='dataEven'>%s</td>", time_up_unscheduled_string);
printf("<td CLASS='dataEven'>%2.3f%%</td>", percent_time_up);
printf("<td class='dataEven'>%2.3f%%</td></tr>\n", percent_time_up_known);
printf("<td CLASS='dataEven'>%2.3f%%</td>", percent_time_up_unscheduled);
printf("<td class='dataEven'>%2.3f%%</td></tr>\n", percent_time_up_unscheduled_known);
printf("<tr CLASS='dataEven'>");
printf("<td CLASS='dataEven'>Scheduled</td>");
printf("<td CLASS='dataEven'>%s</td>", time_up_scheduled_string);

View File

@ -1619,7 +1619,7 @@ void show_service_detail(void) {
/* get the host status information */
temp_hoststatus = find_hoststatus(temp_service->host_name);
/* see if we should display services for hosts with tis type of status */
/* see if we should display services for hosts with this type of status */
if(!(host_status_types & temp_hoststatus->status))
continue;
@ -1810,8 +1810,11 @@ void show_service_detail(void) {
if(temp_hoststatus->notifications_enabled == FALSE) {
printf("<td ALIGN=center valign=center><a href='%s?type=%d&host=%s'><IMG SRC='%s%s' border=0 WIDTH=%d HEIGHT=%d ALT='Notifications for this host have been disabled' TITLE='Notifications for this host have been disabled'></a></td>", EXTINFO_CGI, DISPLAY_HOST_INFO, url_encode(temp_status->host_name), url_images_path, NOTIFICATIONS_DISABLED_ICON, STATUS_ICON_WIDTH, STATUS_ICON_HEIGHT);
}
if(temp_hoststatus->checks_enabled == FALSE) {
printf("<td ALIGN=center valign=center><a href='%s?type=%d&host=%s'><IMG SRC='%s%s' border=0 WIDTH=%d HEIGHT=%d ALT='Checks of this host have been disabled'd TITLE='Checks of this host have been disabled'></a></td>", EXTINFO_CGI, DISPLAY_HOST_INFO, url_encode(temp_status->host_name), url_images_path, DISABLED_ICON, STATUS_ICON_WIDTH, STATUS_ICON_HEIGHT);
if(temp_hoststatus->checks_enabled == FALSE && temp_hoststatus->accept_passive_checks == FALSE) {
printf("<td ALIGN=center valign=center><a href='%s?type=%d&host=%s'><IMG SRC='%s%s' border=0 WIDTH=%d HEIGHT=%d ALT='Active and passive checks of this host have been disabled' TITLE='Checks of this host have been disabled'></a></td>", EXTINFO_CGI, DISPLAY_HOST_INFO, url_encode(temp_status->host_name), url_images_path, DISABLED_ICON, STATUS_ICON_WIDTH, STATUS_ICON_HEIGHT);
}
else if (temp_hoststatus->checks_enabled == FALSE) {
printf("<td ALIGN=center valign=center><a href='%s?type=%d&host=%s'><IMG SRC='%s%s' border=0 WIDTH=%d HEIGHT=%d ALT='Active checks of this host have been disabled - only passive checks are being accepted' TITLE='Checks of this host have been disabled'></a></td>", EXTINFO_CGI, DISPLAY_HOST_INFO, url_encode(temp_status->host_name), url_images_path, PASSIVE_ONLY_ICON, STATUS_ICON_WIDTH, STATUS_ICON_HEIGHT);
}
if(temp_hoststatus->is_flapping == TRUE) {
printf("<td ALIGN=center valign=center><a href='%s?type=%d&host=%s'><IMG SRC='%s%s' border=0 WIDTH=%d HEIGHT=%d ALT='This host is flapping between states' TITLE='This host is flapping between states'></a></td>", EXTINFO_CGI, DISPLAY_HOST_INFO, url_encode(temp_status->host_name), url_images_path, FLAPPING_ICON, STATUS_ICON_WIDTH, STATUS_ICON_HEIGHT);

4
configure vendored
View File

@ -2444,9 +2444,9 @@ ac_config_headers="$ac_config_headers include/config.h lib/snprintf.h lib/iobrok
PKG_NAME=nagios
PKG_VERSION="4.4.3"
PKG_VERSION="4.4.4"
PKG_HOME_URL="https://www.nagios.org/"
PKG_REL_DATE="2019-01-15"
PKG_REL_DATE="2019-07-29"
ac_aux_dir=
for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do

View File

@ -10,9 +10,9 @@ AC_PREFIX_DEFAULT(/usr/local/nagios)
PKG_NAME=nagios
PKG_VERSION="4.4.3"
PKG_VERSION="4.4.4"
PKG_HOME_URL="https://www.nagios.org/"
PKG_REL_DATE="2019-01-15"
PKG_REL_DATE="2019-07-29"
dnl Figure out how to invoke "install" and what install options to use.
AC_PROG_INSTALL

View File

@ -1,5 +1,5 @@
PROJECT_NAME = Nagios
PROJECT_NUMBER = 4.4.3
PROJECT_NUMBER = 4.4.4
PROJECT_BRIEF = "Dev docs for Nagios core and neb-module hackers"
INPUT = lib/ docs/

View File

@ -1,7 +1,7 @@
<?php
include_once(dirname(__FILE__).'/includes/utils.inc.php');
$this_version = '4.4.3';
$this_version = '4.4.4';
$this_year = '2019';
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
@ -26,7 +26,7 @@ $this_year = '2019';
"Click here to watch the entire Nagios Core 4 Tour!</a>";
<?php } ?>
$(document).ready(function() {
var user = "<?php echo $_SERVER['REMOTE_USER']; ?>";
var user = "<?php echo htmlspecialchars($_SERVER['REMOTE_USER']); ?>";
<?php if ($cfg["enable_page_tour"]) { ?>
vBoxId += ";" + user;
@ -145,7 +145,7 @@ $this_year = '2019';
<div id="currentversioninfo">
<div class="product">Nagios<sup><span style="font-size: small;">&reg;</span></sup> Core<sup><span style="font-size: small;">&trade;</span></sup></div>
<div class="version">Version <?php echo $this_version; ?></div>
<div class="releasedate">January 15, 2019</div>
<div class="releasedate">July 29, 2019</div>
<div class="checkforupdates"><a href="https://www.nagios.org/checkforupdates/?version=<?php echo $this_version; ?>&amp;product=nagioscore" target="_blank">Check for updates</a></div>
</div>

View File

@ -78,7 +78,7 @@
var vboxText = "<a href=https://www.nagios.com/tours target=_blank>" +
"Click here to watch the entire Nagios Core 4 Tour!</a>";
$(document).ready(function() {
var user = "<?php echo $_SERVER['REMOTE_USER']; ?>";
var user = "<?php echo htmlspecialchars($_SERVER['REMOTE_USER']); ?>";
vBoxId += ";" + user;
vbox = new vidbox({pos:'lr',vidurl:'https://www.youtube.com/embed/leaRdb3BElI',

View File

@ -1,7 +1,7 @@
<?php
include_once(dirname(__FILE__).'/includes/utils.inc.php');
$this_version = '4.4.3';
$this_version = '4.4.4';
$link_target = 'main';
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

View File

@ -24,8 +24,8 @@
#include "shared.h"
#define PROGRAM_VERSION "4.4.3"
#define PROGRAM_MODIFICATION_DATE "2019-01-15"
#define PROGRAM_VERSION "4.4.4"
#define PROGRAM_MODIFICATION_DATE "2019-07-29"
NAGIOS_BEGIN_DECL

View File

@ -669,6 +669,7 @@ int is_daterange_single_day(daterange *);
time_t calculate_time_from_weekday_of_month(int, int, int, int); /* calculates midnight time of specific (3rd, last, etc.) weekday of a particular month */
time_t calculate_time_from_day_of_month(int, int, int); /* calculates midnight time of specific (1st, last, etc.) day of a particular month */
void get_next_valid_time(time_t, time_t *, timeperiod *); /* get the next valid time in a time period */
time_t reschedule_within_timeperiod(time_t, timeperiod*, time_t);
time_t get_next_log_rotation_time(void); /* determine the next time to schedule a log rotation */
int dbuf_init(dbuf *, int);
int dbuf_free(dbuf *);

View File

@ -215,7 +215,7 @@ int worker_buf2kvvec_prealloc(struct kvvec *kvv, char *buf, unsigned long len, i
} while (0)
/* forward declaration */
static void gather_output(child_process *cp, iobuf *io, int final);
static int gather_output(child_process *cp, iobuf *io, int final);
static void destroy_job(child_process *cp)
{
@ -258,15 +258,23 @@ static void destroy_job(child_process *cp)
int finish_job(child_process *cp, int reason)
{
static struct kvvec resp = KVVEC_INITIALIZER;
int i, ret;
int i, ret, rd;
/* get rid of still open filedescriptors */
if (cp->outstd.fd != -1) {
gather_output(cp, &cp->outstd, 1);
rd = 1;
while(rd > 0) {
rd = gather_output(cp, &cp->outstd, 0);
}
iobroker_close(iobs, cp->outstd.fd);
}
if (cp->outerr.fd != -1) {
gather_output(cp, &cp->outerr, 1);
rd = 1;
while(rd > 0) {
rd = gather_output(cp, &cp->outerr, 0);
}
iobroker_close(iobs, cp->outerr.fd);
}
@ -442,13 +450,13 @@ static void kill_job(child_process *cp, int reason)
destroy_job(cp);
}
static void gather_output(child_process *cp, iobuf *io, int final)
static int gather_output(child_process *cp, iobuf *io, int final)
{
int retry = 5;
int rd;
for (;;) {
char buf[4096];
int rd;
rd = read(io->fd, buf, sizeof(buf));
if (rd < 0) {
@ -484,13 +492,13 @@ static void gather_output(child_process *cp, iobuf *io, int final)
if (rd <= 0 || final) {
iobroker_close(iobs, io->fd);
io->fd = -1;
if (!final)
check_completion(cp, WNOHANG);
break;
}
break;
}
return rd;
}

View File

@ -29,7 +29,7 @@
Summary: Open Source host, service and network monitoring program
Name: nagios
Version: 4.4.3
Version: 4.4.4
Release: 2%{?dist}
License: GPL
Group: Applications/System
@ -120,6 +120,7 @@ CFLAGS="%{mycflags} %{myXcflags}" LDFLAGS="$CFLAGS" %configure \
--with-checkresult-dir="%{_localstatedir}/nagios/spool/checkresults" \
--sbindir="%{_libdir}/nagios/cgi" \
--sysconfdir="%{_sysconfdir}/nagios" \
--with-cgibindir="%{_libdir}/nagios/cgi" \
--with-cgiurl="/nagios/cgi-bin" \
--with-command-user="apache" \
--with-command-group="apache" \
@ -294,6 +295,9 @@ fi
%changelog
* Wed Jan 16 2019 Jake Omann <jomann@nagios.com> 4.4.3
- Updated configure to use --with-cgibindir since cgis are no longer placed in sbindir
* Wed Jun 20 2018 Bryan Heden <bheden@nagios.com> 4.4.1
- Updated for systemd inclusion - (Karsten Weiss and Fr3dY #535, #537)

View File

@ -1,5 +1,5 @@
[Unit]
Description=Nagios Core 4.4.3
Description=Nagios Core 4.4.4
Documentation=https://www.nagios.org/documentation
After=network.target local-fs.target

View File

@ -1473,6 +1473,7 @@ void run_misc_service_check_tests()
void run_reaper_tests()
{
int result;
/* test null dir */
my_free(check_result_path);
check_result_path = NULL;
@ -1485,35 +1486,44 @@ void run_reaper_tests()
"cant open check result path is an error");
my_free(check_result_path);
/* Allow the check reaper to take awhile */
max_check_reaper_time = 10;
/* existing dir, with nothing in it */
check_result_path = nspath_absolute("./../t-tap/var/reaper/no_files", NULL);
ok(process_check_result_queue(check_result_path) == 0,
"0 files (as there shouldn't be)");
result = process_check_result_queue(check_result_path);
ok(result == 0,
"%d files processed, expected 0 files", result);
my_free(check_result_path);
/* existing dir, with 2 check files in it */
create_check_result_file(1, "hst1", "svc1", "output");
create_check_result_file(2, "hst1", NULL, "output");
check_result_path = nspath_absolute("./../t-tap/var/reaper/some_files", NULL);
ok(process_check_result_queue(check_result_path) == 2,
"2 files (as there should be)");
result = process_check_result_queue(check_result_path);
/* This test is disabled until we have time to figure out debugging on Travis VMs. */
/* ok(result == 2,
"%d files processed, expected 2 files", result); */
my_free(check_result_path);
test_check_debugging=FALSE;
/* do sig_{shutdown,restart} work as intended */
sigshutdown = TRUE;
check_result_path = nspath_absolute("./../t-tap/var/reaper/some_files", NULL);
ok(process_check_result_queue(check_result_path) == 0,
"0 files (as there shouldn't be)");
result = process_check_result_queue(check_result_path);
ok(result == 0,
"%d files processed, expected 0 files", result);
sigshutdown = FALSE;
sigrestart = TRUE;
ok(process_check_result_queue(check_result_path) == 0,
"0 files (as there shouldn't be)");
result = process_check_result_queue(check_result_path);
ok(result == 0,
"%d files processed, expected 0 files", result);
/* force too long of a check */
max_check_reaper_time = -5;
sigrestart = FALSE;
ok(process_check_result_queue(check_result_path) == 0,
result = process_check_result_queue(check_result_path);
ok(result == 0,
"cant process if taking too long");
my_free(check_result_path);
@ -1538,7 +1548,8 @@ int main(int argc, char **argv)
accept_passive_host_checks = TRUE;
accept_passive_service_checks = TRUE;
plan_tests(453);
/* Increment this when the check_reaper test is fixed */
plan_tests(452);
time(&now);

View File

@ -12,10 +12,10 @@ else
fi
# Current version number
CURRENTVERSION=4.4.3
CURRENTVERSION=4.4.4
# Last date
LASTDATE=2019-01-15
LASTDATE=2019-07-29
if [ "x$1" = "x" ]
then

View File

@ -41,15 +41,9 @@ distclean: clean
devclean: distclean
install:
$(MAKE) install-basic
$(MAKE) strip-post-install
install-unstripped:
$(MAKE) install-basic
install-basic:
$(INSTALL) -m 775 $(INSTALL_OPTS) -d $(DESTDIR)$(BINDIR)
$(INSTALL) -m 774 $(INSTALL_OPTS) worker-ping $(DESTDIR)$(BINDIR)
strip-post-install:
$(STRIP) $(DESTDIR)$(BINDIR)/worker-ping
install-unstripped:
$(INSTALL) -s -m 775 $(INSTALL_OPTS) -d $(DESTDIR)$(BINDIR)
$(INSTALL) -s -m 774 $(INSTALL_OPTS) worker-ping $(DESTDIR)$(BINDIR)

View File

@ -513,6 +513,52 @@ int xodtemplate_read_config_data(const char *main_config_file, int options) {
return result;
}
/* Destructively handles semicolons in the nagios configuration language.
* Escaped semicolons "\\;" are turned into semicolons
* The first non-escaped semicolon indicates the start of a comment,
* and the string is truncated at this point.
*/
void xodtemplate_handle_semicolons(char* input) {
/* These two integers only come into play if there are escaped semicolons. */
int dest_end = 0; /* The index to input that we need to copy to */
int src_start = 0; /* The index to input that we need to copy from */
register int x = 0;
/* grab data before comment delimiter - faster than a strtok() and strncpy()... */
for(x = 0; input[x] != '\x0'; x++) {
if(input[x] == ';') {
if(x == 0 || input[x - 1] != '\\') {
break;
}
/* We need to escape semicolons */
if (dest_end == 0) {
/* src_start is also uninitialized */
dest_end = x - 1;
src_start = x;
continue;
}
/* dest_end and src_start are initialized - we need to do a copy. */
/* Copy from src_start (usually a semicolon) up to just before the blackslash */
int copy_size = (x - 1) - src_start;
memmove(input + dest_end, input + src_start, copy_size);
dest_end += copy_size;
src_start = x;
}
}
if (dest_end != 0) {
memmove(input + dest_end, input + src_start, x - src_start);
x += dest_end - src_start;
}
input[x] = '\x0';
}
/* process all files in a specific config directory */
int xodtemplate_process_config_dir(char *dirname, int options) {
@ -638,16 +684,8 @@ int xodtemplate_process_config_file(char *filename, int options) {
current_line = thefile->current_line;
/* grab data before comment delimiter - faster than a strtok() and strncpy()... */
for(x = 0; input[x] != '\x0'; x++) {
if(input[x] == ';') {
if(x == 0)
break;
else if(input[x - 1] != '\\')
break;
}
}
input[x] = '\x0';
/* Remove comments and handle escaped semicolons */
xodtemplate_handle_semicolons(input);
/* strip input */
strip(input);