Logo Search packages:      
Sourcecode: nagios version File versions  Download package

utils.c

/*****************************************************************************
 *
 * UTILS.C - Miscellaneous utility functions for Nagios
 *
 * Copyright (c) 1999-2004 Ethan Galstad (nagios@nagios.org)
 * Last Modified:   01-25-2004
 *
 * License:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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 "../common/config.h"
#include "../common/common.h"
#include "../common/objects.h"
#include "../common/statusdata.h"

#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif

#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
 
#ifdef HAVE_GRP_H
#include <grp.h>
#endif
 
#include "nagios.h"

#ifdef EMBEDDEDPERL
#include <EXTERN.h>
#include <perl.h>
static PerlInterpreter *my_perl;
#include <fcntl.h>
/* In perl.h (or friends) there is a macro that defines sighandler as Perl_sighandler, so we must #undef it so we can use our sighandler() function */
#undef sighandler
/* and we don't need perl's reentrant versions */
#undef localtime
#undef getpwnam
#undef getgrnam
#undef strerror
#endif

char            *my_strtok_buffer=NULL;
char            *original_my_strtok_buffer=NULL;


extern char config_file[MAX_FILENAME_LENGTH];
extern char log_file[MAX_FILENAME_LENGTH];
extern char     command_file[MAX_FILENAME_LENGTH];
extern char     temp_file[MAX_FILENAME_LENGTH];
extern char     lock_file[MAX_FILENAME_LENGTH];
extern char log_archive_path[MAX_FILENAME_LENGTH];

extern char     *nagios_user;
extern char     *nagios_group;

extern char     *macro_contact_name;
extern char     *macro_contact_alias;
extern char *macro_host_name;
extern char *macro_host_alias;
extern char *macro_host_address;
extern char *macro_service_description;
extern char *macro_service_state;
extern char *macro_date_time[7];
extern char *macro_output;
extern char *macro_perfdata;
extern char     *macro_contact_email;
extern char     *macro_contact_pager;
extern char     *macro_admin_email;
extern char     *macro_admin_pager;
extern char     *macro_host_state;
extern char     *macro_state_type;
extern char     *macro_execution_time;
extern char     *macro_latency;
extern char     *macro_current_service_attempt;
extern char     *macro_current_host_attempt;
extern char     *macro_notification_type;
extern char     *macro_notification_number;
extern char     *macro_argv[MAX_COMMAND_ARGUMENTS];
extern char     *macro_user[MAX_USER_MACROS];

extern char     *global_host_event_handler;
extern char     *global_service_event_handler;

extern char     *ocsp_command;

extern char     *illegal_object_chars;
extern char     *illegal_output_chars;

extern int      sigshutdown;
extern int      sigrestart;

extern int      daemon_mode;

extern int  use_syslog;
extern int      log_notifications;
extern int      log_service_retries;
extern int      log_host_retries;
extern int      log_event_handlers;
extern int      log_external_commands;
extern int      log_passive_checks;

extern unsigned long      logging_options;
extern unsigned long      syslog_options;

extern int      service_check_timeout;
extern int      host_check_timeout;
extern int      event_handler_timeout;
extern int      notification_timeout;
extern int      ocsp_timeout;

extern int      log_initial_states;

extern int      sleep_time;
extern int      interval_length;
extern int      inter_check_delay_method;
extern int      interleave_factor_method;

extern int      command_check_interval;
extern int      service_check_reaper_interval;
extern int      freshness_check_interval;

extern int      check_external_commands;
extern int      check_orphaned_services;
extern int      check_service_freshness;

extern int      use_aggressive_host_checking;

extern int      soft_state_dependencies;

extern int      retain_state_information;
extern int      retention_update_interval;
extern int      use_retained_program_state;

extern int      log_rotation_method;

extern time_t   last_command_check;
extern time_t   last_log_rotation;

extern int      verify_config;

extern service_message svc_msg;
extern int      ipc_pipe[2];

extern int      max_parallel_service_checks;
extern int      currently_running_service_checks;

extern int      enable_notifications;
extern int      execute_service_checks;
extern int      accept_passive_service_checks;
extern int      enable_event_handlers;
extern int      obsess_over_services;
extern int      enable_failure_prediction;
extern int      process_performance_data;

extern int      aggregate_status_updates;
extern int      status_update_interval;

extern int      time_change_threshold;

extern int      process_performance_data;

extern int      enable_flap_detection;

extern double   low_service_flap_threshold;
extern double   high_service_flap_threshold;
extern double   low_host_flap_threshold;
extern double   high_host_flap_threshold;

extern int      date_format;

extern contact          *contact_list;
extern contactgroup     *contactgroup_list;
extern host       *host_list;
extern hostgroup  *hostgroup_list;
extern service          *service_list;
extern timed_event      *event_list_high;
extern timed_event      *event_list_low;
extern notification     *notification_list;
extern command          *command_list;
extern timeperiod       *timeperiod_list;

extern int      command_file_fd;
extern FILE     *command_file_fp;
extern int      command_file_created;

char my_system_output[MAX_INPUT_BUFFER];

#ifdef HAVE_TZNAME
#ifdef CYGWIN
extern char     *_tzname[2] __declspec(dllimport);
#else
extern char     *tzname[2];
#endif
#endif

extern service_message svc_msg;

extern int errno;



/******************************************************************/
/************************ MACRO FUNCTIONS *************************/
/******************************************************************/

/* replace macros in notification commands with their values */
int process_macros(char *input_buffer,char *output_buffer,int buffer_length,int options){
      char *temp_buffer;
      int in_macro;
      int arg_index=0;
      int user_index=0;

#ifdef DEBUG0
      printf("process_macros() start\n");
#endif

      strcpy(output_buffer,"");

      in_macro=FALSE;

      for(temp_buffer=my_strtok(input_buffer,"$");temp_buffer!=NULL;temp_buffer=my_strtok(NULL,"$")){

            if(in_macro==FALSE){
                  if(strlen(output_buffer)+strlen(temp_buffer)<buffer_length-1){
                        strncat(output_buffer,temp_buffer,buffer_length-strlen(output_buffer)-1);
                        output_buffer[buffer_length-1]='\x0';
                          }
                  in_macro=TRUE;
                  }
            else{

                  if(strlen(output_buffer)+strlen(temp_buffer)<buffer_length-1){

                        if(!strcmp(temp_buffer,"HOSTNAME"))
                              strncat(output_buffer,(macro_host_name==NULL)?"":macro_host_name,buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"HOSTALIAS"))
                              strncat(output_buffer,(macro_host_alias==NULL)?"":macro_host_alias,buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"HOSTADDRESS"))
                              strncat(output_buffer,(macro_host_address==NULL)?"":macro_host_address,buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"SERVICEDESC"))
                              strncat(output_buffer,(macro_service_description==NULL)?"":macro_service_description,buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"SERVICESTATE"))
                              strncat(output_buffer,(macro_service_state==NULL)?"":macro_service_state,buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"SERVICEATTEMPT"))
                              strncat(output_buffer,(macro_current_service_attempt==NULL)?"":macro_current_service_attempt,buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"DATETIME") || !strcmp(temp_buffer,"LONGDATETIME"))
                              strncat(output_buffer,(macro_date_time[MACRO_DATETIME_LONGDATE]==NULL)?"":macro_date_time[MACRO_DATETIME_LONGDATE],buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"SHORTDATETIME"))
                              strncat(output_buffer,(macro_date_time[MACRO_DATETIME_SHORTDATE]==NULL)?"":macro_date_time[MACRO_DATETIME_SHORTDATE],buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"DATE"))
                              strncat(output_buffer,(macro_date_time[MACRO_DATETIME_DATE]==NULL)?"":macro_date_time[MACRO_DATETIME_DATE],buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"TIME"))
                              strncat(output_buffer,(macro_date_time[MACRO_DATETIME_TIME]==NULL)?"":macro_date_time[MACRO_DATETIME_TIME],buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"TIMET"))
                              strncat(output_buffer,(macro_date_time[MACRO_DATETIME_TIMET]==NULL)?"":macro_date_time[MACRO_DATETIME_TIMET],buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"LASTCHECK"))
                              strncat(output_buffer,(macro_date_time[MACRO_DATETIME_LASTCHECK]==NULL)?"":macro_date_time[MACRO_DATETIME_LASTCHECK],buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"LASTSTATECHANGE"))
                              strncat(output_buffer,(macro_date_time[MACRO_DATETIME_LASTSTATECHANGE]==NULL)?"":macro_date_time[MACRO_DATETIME_LASTSTATECHANGE],buffer_length-strlen(output_buffer)-1);

                        /* $OUTPUT macro is cleaned before insertion */
                        else if(!strcmp(temp_buffer,"OUTPUT"))
                              strncat(output_buffer,(macro_output==NULL)?"":clean_macro_chars(macro_output,options),buffer_length-strlen(output_buffer)-1);

                        /* $PERFDATA macro is cleaned before insertion */
                        else if(!strcmp(temp_buffer,"PERFDATA"))
                              strncat(output_buffer,(macro_perfdata==NULL)?"":clean_macro_chars(macro_perfdata,options),buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"CONTACTNAME"))
                              strncat(output_buffer,(macro_contact_name==NULL)?"":macro_contact_name,buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"CONTACTALIAS"))
                              strncat(output_buffer,(macro_contact_alias==NULL)?"":macro_contact_alias,buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"CONTACTEMAIL"))
                              strncat(output_buffer,(macro_contact_email==NULL)?"":macro_contact_email,buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"CONTACTPAGER"))
                              strncat(output_buffer,(macro_contact_pager==NULL)?"":macro_contact_pager,buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"ADMINEMAIL"))
                              strncat(output_buffer,(macro_admin_email==NULL)?"":macro_admin_email,buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"ADMINPAGER"))
                              strncat(output_buffer,(macro_admin_pager==NULL)?"":macro_admin_pager,buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"HOSTSTATE"))
                              strncat(output_buffer,(macro_host_state==NULL)?"":macro_host_state,buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"HOSTATTEMPT"))
                              strncat(output_buffer,(macro_current_host_attempt==NULL)?"":macro_current_host_attempt,buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"STATETYPE"))
                              strncat(output_buffer,(macro_state_type==NULL)?"":macro_state_type,buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"NOTIFICATIONTYPE"))
                              strncat(output_buffer,(macro_notification_type==NULL)?"":macro_notification_type,buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"NOTIFICATIONNUMBER"))
                              strncat(output_buffer,(macro_notification_number==NULL)?"":macro_notification_number,buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"EXECUTIONTIME"))
                              strncat(output_buffer,(macro_execution_time==NULL)?"":macro_execution_time,buffer_length-strlen(output_buffer)-1);

                        else if(!strcmp(temp_buffer,"LATENCY"))
                              strncat(output_buffer,(macro_latency==NULL)?"":macro_latency,buffer_length-strlen(output_buffer)-1);


                        else if(strstr(temp_buffer,"ARG")==temp_buffer){
                              arg_index=atoi(temp_buffer+3);
                              if(arg_index>=1 && arg_index<=MAX_COMMAND_ARGUMENTS)
                                    strncat(output_buffer,(macro_argv[arg_index-1]==NULL)?"":macro_argv[arg_index-1],buffer_length-strlen(output_buffer)-1);
                                }

                        else if(strstr(temp_buffer,"USER")==temp_buffer){
                              user_index=atoi(temp_buffer+4);
                              if(user_index>=1 && user_index<=MAX_USER_MACROS)
                                    strncat(output_buffer,(macro_user[user_index-1]==NULL)?"":macro_user[user_index-1],buffer_length-strlen(output_buffer)-1);
                                }
                  
                        /* an escaped $ is done by specifying two $$ next to each other */
                        else if(!strcmp(temp_buffer,"")){
                              strncat(output_buffer,"$",buffer_length-strlen(output_buffer)-1);
                              output_buffer[buffer_length-1]='\x0';
                                }
                        
                        /* a non-macro, just some user-defined string between two $s */
                        else{
                              strncat(output_buffer,"$",buffer_length-strlen(output_buffer)-1);
                              output_buffer[buffer_length-1]='\x0';
                              strncat(output_buffer,temp_buffer,buffer_length-strlen(output_buffer)-1);
                              output_buffer[buffer_length-1]='\x0';
                              strncat(output_buffer,"$",buffer_length-strlen(output_buffer)-1);
                                }

                        output_buffer[buffer_length-1]='\x0';
                        }

                  in_macro=FALSE;
                  }
            }

#ifdef DEBUG0
      printf("process_macros() end\n");
#endif

      return OK;
      }


/* grab macros that are specific to a particular service */
int grab_service_macros(service *svc){
      
#ifdef DEBUG0
      printf("grab_service_macros() start\n");
#endif

      /* get the service description */
      if(macro_service_description!=NULL)
            free(macro_service_description);
      macro_service_description=(char *)malloc(strlen(svc->description)+1);
      if(macro_service_description!=NULL)
            strcpy(macro_service_description,svc->description);

      /* get the plugin output */
      if(macro_output!=NULL)
            free(macro_output);
      if(svc->plugin_output==NULL)
            macro_output=NULL;
      else
            macro_output=(char *)malloc(strlen(svc->plugin_output)+1);
      if(macro_output!=NULL)
            strcpy(macro_output,svc->plugin_output);

      /* get the performance data */
      if(macro_perfdata!=NULL)
            free(macro_perfdata);
      if(svc->perf_data==NULL)
            macro_perfdata=NULL;
      else
            macro_perfdata=(char *)malloc(strlen(svc->perf_data)+1);
      if(macro_perfdata!=NULL)
            strcpy(macro_perfdata,svc->perf_data);

      /* grab the service state type macro (this is usually overridden later on) */
      if(macro_state_type!=NULL)
            free(macro_state_type);
      macro_state_type=(char *)malloc(MAX_STATETYPE_LENGTH);
      if(macro_state_type!=NULL)
            strcpy(macro_state_type,(svc->state_type==HARD_STATE)?"HARD":"SOFT");

      /* get the service state */
      if(macro_service_state!=NULL)
            free(macro_service_state);
      macro_service_state=(char *)malloc(MAX_STATE_LENGTH);
      if(macro_service_state!=NULL){
            if(svc->current_state==STATE_OK)
                  strcpy(macro_service_state,"OK");
            else if(svc->current_state==STATE_WARNING)
                  strcpy(macro_service_state,"WARNING");
            else if(svc->current_state==STATE_CRITICAL)
                  strcpy(macro_service_state,"CRITICAL");
            else
                  strcpy(macro_service_state,"UNKNOWN");
              }

      /* get the current service check attempt macro */
      if(macro_current_service_attempt!=NULL)
            free(macro_current_service_attempt);
      macro_current_service_attempt=(char *)malloc(MAX_ATTEMPT_LENGTH);
      if(macro_current_service_attempt!=NULL){
            snprintf(macro_current_service_attempt,MAX_ATTEMPT_LENGTH-1,"%d",svc->current_attempt);
            macro_current_service_attempt[MAX_ATTEMPT_LENGTH-1]='\x0';
              }

      /* get the execution time macro */
      if(macro_execution_time!=NULL)
            free(macro_execution_time);
      macro_execution_time=(char *)malloc(MAX_EXECUTIONTIME_LENGTH);
      if(macro_execution_time!=NULL){
            snprintf(macro_execution_time,MAX_EXECUTIONTIME_LENGTH-1,"%lu",svc->execution_time);
            macro_execution_time[MAX_EXECUTIONTIME_LENGTH-1]='\x0';
              }

      /* get the latency macro */
      if(macro_latency!=NULL)
            free(macro_latency);
      macro_latency=(char *)malloc(MAX_LATENCY_LENGTH);
      if(macro_latency!=NULL){
            snprintf(macro_latency,MAX_LATENCY_LENGTH-1,"%lu",svc->latency);
            macro_latency[MAX_LATENCY_LENGTH-1]='\x0';
              }

      /* get the date/time macros */
      grab_datetime_macros();

      /* get the last check time macro */
      if(macro_date_time[MACRO_DATETIME_LASTCHECK]!=NULL)
            free(macro_date_time[MACRO_DATETIME_LASTCHECK]);
      macro_date_time[MACRO_DATETIME_LASTCHECK]=(char *)malloc(MAX_DATETIME_LENGTH);
      if(macro_date_time[MACRO_DATETIME_LASTCHECK]!=NULL){
            snprintf(macro_date_time[MACRO_DATETIME_LASTCHECK],MAX_DATETIME_LENGTH-1,"%lu",(unsigned long)svc->last_check);
            macro_date_time[MACRO_DATETIME_LASTCHECK][MAX_DATETIME_LENGTH-1]='\x0';
              }

      /* get the last state change time macro */
      if(macro_date_time[MACRO_DATETIME_LASTSTATECHANGE]!=NULL)
            free(macro_date_time[MACRO_DATETIME_LASTSTATECHANGE]);
      macro_date_time[MACRO_DATETIME_LASTSTATECHANGE]=(char *)malloc(MAX_DATETIME_LENGTH);
      if(macro_date_time[MACRO_DATETIME_LASTSTATECHANGE]!=NULL){
            snprintf(macro_date_time[MACRO_DATETIME_LASTSTATECHANGE],MAX_DATETIME_LENGTH-1,"%lu",(unsigned long)svc->last_state_change);
            macro_date_time[MACRO_DATETIME_LASTSTATECHANGE][MAX_DATETIME_LENGTH-1]='\x0';
              }

      strip(macro_service_description);
      strip(macro_output);
      strip(macro_service_state);
      strip(macro_current_service_attempt);

#ifdef DEBUG0
      printf("grab_service_macros() end\n");
#endif

      return OK;
        }


/* grab macros that are specific to a particular host */
int grab_host_macros(host *hst){

#ifdef DEBUG0
      printf("grab_host_macros() start\n");
#endif

      /* get the host name */
      if(macro_host_name!=NULL)
            free(macro_host_name);
      macro_host_name=(char *)malloc(strlen(hst->name)+1);
      if(macro_host_name!=NULL)
            strcpy(macro_host_name,hst->name);
      
      /* get the host alias */
      if(macro_host_alias!=NULL)
            free(macro_host_alias);
      macro_host_alias=(char *)malloc(strlen(hst->alias)+1);
      if(macro_host_alias!=NULL)
            strcpy(macro_host_alias,hst->alias);

      /* get the host address */
      if(macro_host_address!=NULL)
            free(macro_host_address);
      macro_host_address=(char *)malloc(strlen(hst->address)+1);
      if(macro_host_address!=NULL)
            strcpy(macro_host_address,hst->address);

      /* get the host state */
      if(macro_host_state!=NULL)
            free(macro_host_state);
      macro_host_state=(char *)malloc(MAX_STATE_LENGTH);
      if(macro_host_state!=NULL){
            if(hst->status==HOST_DOWN)
                  strcpy(macro_host_state,"DOWN");
            else if(hst->status==HOST_UNREACHABLE)
                  strcpy(macro_host_state,"UNREACHABLE");
            else
                  strcpy(macro_host_state,"UP");
              }

      /* get the plugin output */
      if(macro_output!=NULL)
            free(macro_output);
      if(hst->plugin_output==NULL)
            macro_output=NULL;
      else
            macro_output=(char *)malloc(strlen(hst->plugin_output)+1);
      if(macro_output!=NULL)
            strcpy(macro_output,hst->plugin_output);

      /* get the performance data */
      if(macro_perfdata!=NULL)
            free(macro_perfdata);
      if(hst->perf_data==NULL)
            macro_perfdata=NULL;
      else
            macro_perfdata=(char *)malloc(strlen(hst->perf_data)+1);
      if(macro_perfdata!=NULL)
            strcpy(macro_perfdata,hst->perf_data);

      /* get the host current attempt */
      if(macro_current_host_attempt!=NULL)
            free(macro_current_host_attempt);
      macro_current_host_attempt=(char *)malloc(MAX_ATTEMPT_LENGTH);
      if(macro_current_host_attempt!=NULL){
            snprintf(macro_current_host_attempt,MAX_ATTEMPT_LENGTH-1,"%d",hst->current_attempt);
            macro_current_host_attempt[MAX_ATTEMPT_LENGTH-1]='\x0';
              }

      /* get the execution time macro */
      if(macro_execution_time!=NULL)
            free(macro_execution_time);
      macro_execution_time=(char *)malloc(MAX_EXECUTIONTIME_LENGTH);
      if(macro_execution_time!=NULL){
            snprintf(macro_execution_time,MAX_EXECUTIONTIME_LENGTH-1,"%lu",hst->execution_time);
            macro_execution_time[MAX_EXECUTIONTIME_LENGTH-1]='\x0';
              }

      /* get the date/time macros */
      grab_datetime_macros();

      /* get the last check time macro */
      if(macro_date_time[MACRO_DATETIME_LASTCHECK]!=NULL)
            free(macro_date_time[MACRO_DATETIME_LASTCHECK]);
      macro_date_time[MACRO_DATETIME_LASTCHECK]=(char *)malloc(MAX_DATETIME_LENGTH);
      if(macro_date_time[MACRO_DATETIME_LASTCHECK]!=NULL){
            snprintf(macro_date_time[MACRO_DATETIME_LASTCHECK],MAX_DATETIME_LENGTH-1,"%lu",(unsigned long)hst->last_check);
            macro_date_time[MACRO_DATETIME_LASTCHECK][MAX_DATETIME_LENGTH-1]='\x0';
              }

      /* get the last state change time macro */
      if(macro_date_time[MACRO_DATETIME_LASTSTATECHANGE]!=NULL)
            free(macro_date_time[MACRO_DATETIME_LASTSTATECHANGE]);
      macro_date_time[MACRO_DATETIME_LASTSTATECHANGE]=(char *)malloc(MAX_DATETIME_LENGTH);
      if(macro_date_time[MACRO_DATETIME_LASTSTATECHANGE]!=NULL){
            snprintf(macro_date_time[MACRO_DATETIME_LASTSTATECHANGE],MAX_DATETIME_LENGTH-1,"%lu",(unsigned long)hst->last_state_change);
            macro_date_time[MACRO_DATETIME_LASTSTATECHANGE][MAX_DATETIME_LENGTH-1]='\x0';
              }

      strip(macro_host_name);
      strip(macro_host_alias);
      strip(macro_host_address);
      strip(macro_host_state);
      strip(macro_output);
      strip(macro_current_host_attempt);

#ifdef DEBUG0
      printf("grab_host_macros() end\n");
#endif

      return OK;
        }


/* grab macros that are specific to a particular contact */
int grab_contact_macros(contact *cntct){

#ifdef DEBUG0
      printf("grab_contact_macros() start\n");
#endif

      /* get the name */
      if(macro_contact_name!=NULL)
            free(macro_contact_name);
      macro_contact_name=(char *)malloc(strlen(cntct->name)+1);
      if(macro_contact_name!=NULL)
            strcpy(macro_contact_name,cntct->name);

      /* get the alias */
      if(macro_contact_alias!=NULL)
            free(macro_contact_alias);
      macro_contact_alias=(char *)malloc(strlen(cntct->alias)+1);
      if(macro_contact_alias!=NULL)
            strcpy(macro_contact_alias,cntct->alias);

      /* get the email address */
      if(macro_contact_email!=NULL)
            free(macro_contact_email);
      if(cntct->email==NULL)
            macro_contact_email=NULL;
      else
            macro_contact_email=(char *)malloc(strlen(cntct->email)+1);
      if(macro_contact_email!=NULL)
            strcpy(macro_contact_email,cntct->email);

      /* get the pager number */
      if(macro_contact_pager!=NULL)
            free(macro_contact_pager);
      if(cntct->pager==NULL)
            macro_contact_pager=NULL;
      else
            macro_contact_pager=(char *)malloc(strlen(cntct->pager)+1);
      if(macro_contact_pager!=NULL)
            strcpy(macro_contact_pager,cntct->pager);

      /* get the date/time macros */
      grab_datetime_macros();

      strip(macro_contact_name);
      strip(macro_contact_alias);
      strip(macro_contact_email);
      strip(macro_contact_pager);

#ifdef DEBUG0
      printf("grab_contact_macros() end\n");
#endif

      return OK;
        }


/* updates date/time macros */
int grab_datetime_macros(void){
      time_t t;

#ifdef DEBUG0
      printf("grab_datetime_macros() start\n");
#endif

      /* get the current time */
      time(&t);

      /* get the current date/time (long format macro) */
      if(macro_date_time[MACRO_DATETIME_LONGDATE]!=NULL)
            free(macro_date_time[MACRO_DATETIME_LONGDATE]);
      macro_date_time[MACRO_DATETIME_LONGDATE]=(char *)malloc(MAX_DATETIME_LENGTH);
      if(macro_date_time[MACRO_DATETIME_LONGDATE]!=NULL)
            get_datetime_string(&t,macro_date_time[MACRO_DATETIME_LONGDATE],MAX_DATETIME_LENGTH,LONG_DATE_TIME);

      /* get the current date/time (short format macro) */
      if(macro_date_time[MACRO_DATETIME_SHORTDATE]!=NULL)
            free(macro_date_time[MACRO_DATETIME_SHORTDATE]);
      macro_date_time[MACRO_DATETIME_SHORTDATE]=(char *)malloc(MAX_DATETIME_LENGTH);
      if(macro_date_time[MACRO_DATETIME_SHORTDATE]!=NULL)
            get_datetime_string(&t,macro_date_time[MACRO_DATETIME_SHORTDATE],MAX_DATETIME_LENGTH,SHORT_DATE_TIME);

      /* get the short format date macro */
      if(macro_date_time[MACRO_DATETIME_DATE]!=NULL)
            free(macro_date_time[MACRO_DATETIME_DATE]);
      macro_date_time[MACRO_DATETIME_DATE]=(char *)malloc(MAX_DATETIME_LENGTH);
      if(macro_date_time[MACRO_DATETIME_DATE]!=NULL)
            get_datetime_string(&t,macro_date_time[MACRO_DATETIME_DATE],MAX_DATETIME_LENGTH,SHORT_DATE);

      /* get the short format time macro */
      if(macro_date_time[MACRO_DATETIME_TIME]!=NULL)
            free(macro_date_time[MACRO_DATETIME_TIME]);
      macro_date_time[MACRO_DATETIME_TIME]=(char *)malloc(MAX_DATETIME_LENGTH);
      if(macro_date_time[MACRO_DATETIME_TIME]!=NULL)
            get_datetime_string(&t,macro_date_time[MACRO_DATETIME_TIME],MAX_DATETIME_LENGTH,SHORT_TIME);

      /* get the time_t format time macro */
      if(macro_date_time[MACRO_DATETIME_TIMET]!=NULL)
            free(macro_date_time[MACRO_DATETIME_TIMET]);
      macro_date_time[MACRO_DATETIME_TIMET]=(char *)malloc(MAX_DATETIME_LENGTH);
      if(macro_date_time[MACRO_DATETIME_TIMET]!=NULL){
            snprintf(macro_date_time[MACRO_DATETIME_TIMET],MAX_DATETIME_LENGTH-1,"%lu",(unsigned long)t);
            macro_date_time[MACRO_DATETIME_TIMET][MAX_DATETIME_LENGTH-1]='\x0';
              }

      strip(macro_date_time[MACRO_DATETIME_LONGDATE]);
      strip(macro_date_time[MACRO_DATETIME_SHORTDATE]);
      strip(macro_date_time[MACRO_DATETIME_DATE]);
      strip(macro_date_time[MACRO_DATETIME_TIME]);
      strip(macro_date_time[MACRO_DATETIME_TIMET]);

#ifdef DEBUG0
      printf("grab_datetime_macros() end\n");
#endif

      return OK;
        }



/* clear all macros that are not "constant" (i.e. they change throughout the course of monitoring) */
int clear_volatile_macros(void){
      int x;

#ifdef DEBUG0
      printf("clear_volatile_macros() start\n");
#endif

      /* plugin output macros */
      if(macro_output!=NULL){
            free(macro_output);
            macro_output=NULL;
              }
      if(macro_perfdata!=NULL){
            free(macro_perfdata);
            macro_perfdata=NULL;
              }

      /* contact macros */
      if(macro_contact_name!=NULL){
            free(macro_contact_name);
            macro_contact_name=NULL;
              }
      if(macro_contact_alias!=NULL){
            free(macro_contact_alias);
            macro_contact_alias=NULL;
              }
      if(macro_contact_email!=NULL){
            free(macro_contact_email);
            macro_contact_email=NULL;
              }
      if(macro_contact_pager!=NULL){
            free(macro_contact_pager);
            macro_contact_pager=NULL;
              }

      /* host macros */
      if(macro_host_name!=NULL){
            free(macro_host_name);
            macro_host_name=NULL;
              }
      if(macro_host_alias!=NULL){
            free(macro_host_alias);
            macro_host_alias=NULL;
              }
      if(macro_host_address!=NULL){
            free(macro_host_address);
            macro_host_address=NULL;
              }
      if(macro_host_state!=NULL){
            free(macro_host_state);
            macro_host_state=NULL;
              }
      if(macro_current_host_attempt!=NULL){
            free(macro_current_host_attempt);
            macro_current_host_attempt=NULL;
              }

      /* service macros */
      if(macro_service_description!=NULL){
            free(macro_service_description);
            macro_service_description=NULL;
              }
      if(macro_service_state!=NULL){
            free(macro_service_state);
            macro_service_state=NULL;
              }
      if(macro_current_service_attempt!=NULL){
            free(macro_current_service_attempt);
            macro_current_service_attempt=NULL;
                }

      /* miscellaneous macros */
      if(macro_state_type!=NULL){
            free(macro_state_type);
            macro_state_type=NULL;
              }
      if(macro_date_time[MACRO_DATETIME_LONGDATE]!=NULL){
            free(macro_date_time[MACRO_DATETIME_LONGDATE]);
            macro_date_time[MACRO_DATETIME_LONGDATE]=NULL;
              }
      if(macro_date_time[MACRO_DATETIME_SHORTDATE]!=NULL){
            free(macro_date_time[MACRO_DATETIME_SHORTDATE]);
            macro_date_time[MACRO_DATETIME_SHORTDATE]=NULL;
              }
      if(macro_date_time[MACRO_DATETIME_DATE]!=NULL){
            free(macro_date_time[MACRO_DATETIME_DATE]);
            macro_date_time[MACRO_DATETIME_DATE]=NULL;
              }
      if(macro_date_time[MACRO_DATETIME_TIME]!=NULL){
            free(macro_date_time[MACRO_DATETIME_TIME]);
            macro_date_time[MACRO_DATETIME_TIME]=NULL;
              }
      if(macro_date_time[MACRO_DATETIME_TIMET]!=NULL){
            free(macro_date_time[MACRO_DATETIME_TIMET]);
            macro_date_time[MACRO_DATETIME_TIMET]=NULL;
              }
      if(macro_date_time[MACRO_DATETIME_LASTCHECK]!=NULL){
            free(macro_date_time[MACRO_DATETIME_LASTCHECK]);
            macro_date_time[MACRO_DATETIME_LASTCHECK]=NULL;
              }
      if(macro_date_time[MACRO_DATETIME_LASTSTATECHANGE]!=NULL){
            free(macro_date_time[MACRO_DATETIME_LASTSTATECHANGE]);
            macro_date_time[MACRO_DATETIME_LASTSTATECHANGE]=NULL;
              }
      if(macro_notification_type!=NULL){
            free(macro_notification_type);
            macro_notification_type=NULL;
              }
      if(macro_notification_number!=NULL){
            free(macro_notification_number);
            macro_notification_number=NULL;
              }
      if(macro_execution_time!=NULL){
            free(macro_execution_time);
            macro_execution_time=NULL;
              }
      if(macro_latency!=NULL){
            free(macro_latency);
            macro_latency=NULL;
              }

      /* command argument macros */
      for(x=0;x<MAX_COMMAND_ARGUMENTS;x++){
            if(macro_argv[x]!=NULL){
                  free(macro_argv[x]);
                  macro_argv[x]=NULL;
                    }
              }

#ifdef DEBUG0
      printf("clear_volatile_macros() end\n");
#endif

      return OK;
        }


/* clear macros that are constant (i.e. they do NOT change during monitoring) */
int clear_nonvolatile_macros(void){
      int x=0;

#ifdef DEBUG0
      printf("clear_nonvolatile_macros() start\n");
#endif

      /* admin email and pager */
      if(macro_admin_email!=NULL){
            free(macro_admin_email);
            macro_admin_email=NULL;
              }
      if(macro_admin_pager!=NULL){
            free(macro_admin_pager);
            macro_admin_pager=NULL;
              }

      /* user macros */
      for(x=0;x<MAX_USER_MACROS;x++){
            if(macro_user[x]!=NULL){
                  free(macro_user[x]);
                  macro_user[x]=NULL;
                    }
              }

#ifdef DEBUG0
      printf("clear_nonvolatile_macros() end\n");
#endif

      return OK;
        }




/******************************************************************/
/******************** SYSTEM COMMAND FUNCTIONS ********************/
/******************************************************************/


/* executes a system command - used for service checks and notifications */
int my_system(char *cmd,int timeout,int *early_timeout,char *output,int output_length){
        pid_t pid;
      int status;
      int result;
      char buffer[MAX_INPUT_BUFFER];
      int fd[2];
      FILE *fp=NULL;
      int bytes_read=0;
      time_t start_time,end_time;

#ifdef EMBEDDEDPERL
      char fname[1024];
      char tmpfname[32];
      char *args[5] = {"",DO_CLEAN, "", "", NULL };
      int isperl;
      int tmpfd;
#ifdef THREADEDPERL
      dTHX;
#endif
      dSP;
#endif


#ifdef DEBUG0
      printf("my_system() start\n");
#endif

      /* initialize return variables */
      if(output!=NULL)
            strcpy(output,"");
      *early_timeout=FALSE;

      /* if no command was passed, return with no error */
      if(cmd==NULL)
              return STATE_OK;

#ifdef EMBEDDEDPERL

      strncpy(fname,cmd,strcspn(cmd," "));
      fname[strcspn(cmd," ")] = '\x0';

      /* have "filename" component of command. Check for PERL */
      fp=fopen(fname,"r");
      if(fp==NULL)
            strcpy(buffer,"");
      else{
            fgets(buffer,80,fp);
            fclose(fp);
              }

      isperl=0;

      if(strstr(buffer,"/bin/perl")!=NULL){

            isperl = 1;
            args[0] = fname;
            args[2] = tmpfname;

            if(strchr(cmd,' ')==NULL)
                  args[3]="";
            else
                  args[3]=cmd+strlen(fname)+1;

            /* call our perl interpreter to compile and optionally cache the compiled script. */
            perl_call_argv("Embed::Persistent::eval_file", G_DISCARD | G_EVAL, args);
              }
#endif 

      /* create a pipe */
      pipe(fd);

      /* make the pipe non-blocking */
      fcntl(fd[0],F_SETFL,O_NONBLOCK);
      fcntl(fd[1],F_SETFL,O_NONBLOCK);

      /* get the command start time */
      time(&start_time);

      /* fork */
      pid=fork();

      /* return an error if we couldn't fork */
      if(pid==-1){

            snprintf(buffer,sizeof(buffer)-1,"Warning: fork() in my_system() failed for command \"%s\"\n",cmd);
            buffer[sizeof(buffer)-1]='\x0';

            if(output!=NULL){
                  strncpy(output,buffer,output_length-1);
                  output[output_length-1]='\x0';
                    }

            write_to_logs_and_console(buffer,NSLOG_RUNTIME_WARNING,TRUE);

            /* close both ends of the pipe */
            close(fd[0]);
            close(fd[1]);
            
              return STATE_UNKNOWN;  
              }

      /* execute the command in the child process */
        if (pid==0){

            /* become process group leader */
            setpgid(0,0);

#ifndef USE_MEMORY_PERFORMANCE_TWEAKS
            /* free allocated memory */
            free_memory();
#endif

            /* reset signal handling */
            reset_sighandler();

            /* close pipe for reading */
            close(fd[0]);

            /* trap commands that timeout */
            signal(SIGALRM,my_system_sighandler);
            alarm(timeout);


            /******** BEGIN EMBEDDED PERL CODE EXECUTION ********/

#ifdef EMBEDDEDPERL
            if(isperl){

                  /* generate a temporary filename to which stdout can be redirected. */
                  snprintf(tmpfname,sizeof(tmpfname)-1,"/tmp/embeddedXXXXXX");
                  if((tmpfd=mkstemp(tmpfname))==-1)
                        _exit(STATE_UNKNOWN);

                  /* execute our previously compiled script  */
                  ENTER;
                  SAVETMPS;
                  PUSHMARK(SP);
                  XPUSHs(sv_2mortal(newSVpv(args[0],0)));
                  XPUSHs(sv_2mortal(newSVpv(args[1],0)));
                  XPUSHs(sv_2mortal(newSVpv(args[2],0)));
                  XPUSHs(sv_2mortal(newSVpv(args[3],0)));
                  PUTBACK;
                  perl_call_pv("Embed::Persistent::run_package", G_EVAL);
                  SPAGAIN;
                  status = POPi;
                  PUTBACK;
                  FREETMPS;
                  LEAVE;                                    

                  /* check return status  */
                  if(SvTRUE(ERRSV)){
#ifdef DEBUG0
                        printf("embedded perl ran command %s with error\n",fname);
#endif
                        status=-2;
                          }

                  /* read back stdout from script */
                  fp=fopen(tmpfname,"r");

                  /* default return string in case nothing was returned */
                  strcpy(buffer,"(No output!)");

                  /* grab output from plugin (which was redirected to the temp file) */
                  fgets(buffer,sizeof(buffer)-1,fp);
                  buffer[sizeof(buffer)-1]='\x0';
                  strip(buffer);

                  /* close and delete temp file */
                  fclose(fp);
                  close(tmpfd);
                  unlink(tmpfname);

                  /* report the command status */
                  if(status==-2)
                        result=STATE_CRITICAL;
                  else
                        result=status;

                  /* write the output back to the parent process */
                  write(fd[1],buffer,strlen(buffer)+1);

                  /* close pipe for writing */
                  close(fd[1]);

                  /* reset the alarm */
                  alarm(0);

                  _exit(result);
                    }

            /* Not a perl command. Use popen... */
#endif  

            /******** END EMBEDDED PERL CODE EXECUTION ********/


            /* run the command */
            fp=popen(cmd,"r");
            
            /* report an error if we couldn't run the command */
            if(fp==NULL){

                  strncpy(buffer,"(Error: Could not execute command)\n",sizeof(buffer)-1);
                  buffer[sizeof(buffer)-1]='\x0';

                  /* write the error back to the parent process */
                  write(fd[1],buffer,strlen(buffer)+1);

                  result=STATE_CRITICAL;
                    }
            else{

                  /* default return string in case nothing was returned */
                  strcpy(buffer,"(No output!)");

                  /* read in the first line of output from the command */
                  fgets(buffer,sizeof(buffer)-1,fp);

                  /* close the command and get termination status */
                  status=pclose(fp);
                  
                  /* report an error if we couldn't close the command */
                  if(status==-1)
                        result=STATE_CRITICAL;
                  else
                        result=WEXITSTATUS(status);

                  /* write the output back to the parent process */
                  write(fd[1],buffer,strlen(buffer)+1);
                    }

            /* close pipe for writing */
            close(fd[1]);

            /* reset the alarm */
            alarm(0);
            
            _exit(result);
              }

      /* parent waits for child to finish executing command */
      else{
            
            /* close pipe for writing */
            close(fd[1]);

            /* wait for child to exit */
            waitpid(pid,&status,0);

            /* get the end time for running the command */
            time(&end_time);

            /* get the exit code returned from the program */
            result=WEXITSTATUS(status);

            /* check for possibly missing scripts/binaries/etc */
            if(result==126 || result==127){
                  snprintf(buffer,sizeof(buffer)-1,"Warning: Attempting to execute the command \"%s\" resulted in a return code of %d.  Make sure the script or binary you are trying to execute actually exists...\n",cmd,result);
                  buffer[sizeof(buffer)-1]='\x0';
                  write_to_logs_and_console(buffer,NSLOG_RUNTIME_WARNING,TRUE);
                    }

            /* because of my idiotic idea of having UNKNOWN states be equivalent to -1, I must hack things a bit... */
            if(result==255 || result==-1)
                  result=STATE_UNKNOWN;

            /* check bounds on the return value */
            if(result<-1 || result>3)
                  result=STATE_UNKNOWN;

            /* try and read the results from the command output (retry if we encountered a signal) */
            if(output!=NULL){
                  do{
                        bytes_read=read(fd[0],output,output_length-1);
                            }while(bytes_read==-1 && errno==EINTR);
                    }

            if(bytes_read==-1 && output!=NULL)
                  strcpy(output,"");

            /* if there was a critical return code and no output AND the command time exceeded the timeout thresholds, assume a timeout */
            if(result==STATE_CRITICAL && bytes_read==-1 && (end_time-start_time)>=timeout){

                  /* set the early timeout flag */
                  *early_timeout=TRUE;

                  /* try to kill the command that timed out by sending termination signal to child process group */
                  kill((pid_t)(-pid),SIGTERM);
                  sleep(1);
                  kill((pid_t)(-pid),SIGKILL);
                    }

            /* close the pipe for reading */
            close(fd[0]);
              }

#ifdef DEBUG1
      printf("my_system() end\n");
#endif

      return result;
        }



/* given a "raw" command, return the "expanded" or "whole" command line */
void get_raw_command_line(char *cmd,char *raw_command,int buffer_length){
      char temp_buffer[MAX_INPUT_BUFFER];
      char *buffer;
      command *temp_command;
      int x;

#ifdef DEBUG0
      printf("get_raw_command_line() start\n");
#endif
#ifdef DEBUG1
      printf("\tInput: %s\n",cmd);
#endif

      /* initialize the command */
      strcpy(raw_command,"");

      /* if we were handed a NULL string, throw it right back */
      if(cmd==NULL){
            
#ifdef DEBUG1
            printf("\tRaw command is NULL!\n");
#endif

            return;
              }

      /* clear the old command arguments */
      for(x=0;x<MAX_COMMAND_ARGUMENTS;x++){
            if(macro_argv[x]!=NULL)
                  free(macro_argv[x]);
            macro_argv[x]=NULL;
              }

      /* if the command is enclosed in quotes, this *is* the command we should run, don't do a lookup */
      if(cmd[0]=='\"'){
            strncpy(raw_command,cmd+1,buffer_length);
            raw_command[buffer_length-1]='\x0';
            strip(raw_command);

            /* strip the trailing quote if its there... */
            if(raw_command[strlen(raw_command)-1]=='\"')
                  raw_command[strlen(raw_command)-1]='\x0';
              }

      /* else lookup the command */
      else{

            strcpy(temp_buffer,cmd);

            /* get the command name */
            buffer=my_strtok(temp_buffer,"!");

            /* the buffer should never be NULL, but just in case... */
            if(buffer==NULL){
                  strcpy(raw_command,"");
                  return;
                    }
            else{
                  strncpy(raw_command,buffer,buffer_length);
                  raw_command[buffer_length-1]='\x0';
                    }

            /* get the arguments */
            for(x=0;x<MAX_COMMAND_ARGUMENTS;x++){
                  buffer=my_strtok(NULL,"!");
                  if(buffer==NULL)
                        break;
                  strip(buffer);
                  macro_argv[x]=(char *)malloc(strlen(buffer)+1);
                  if(macro_argv[x]!=NULL)
                        strcpy(macro_argv[x],buffer);
                    }

            /* find the command used to check this service */
            temp_command=find_command(raw_command,NULL);

            /* error if we couldn't find the command */
            if(temp_command==NULL)
                  return;

            strncpy(raw_command,temp_command->command_line,buffer_length);
            raw_command[buffer_length-1]='\x0';
            strip(raw_command);
              }

#ifdef DEBUG1
      printf("\tOutput: %s\n",raw_command);
#endif
#ifdef DEBUG0
      printf("get_raw_command_line() end\n");
#endif

      return;
        }





/******************************************************************/
/************************* TIME FUNCTIONS *************************/
/******************************************************************/


/* see if the specified time falls into a valid time range in the given time period */
int check_time_against_period(time_t check_time,char *period_name){
      timeperiod *temp_period;
      timerange *temp_range;
      unsigned long midnight_today;
      struct tm *t;

#ifdef DEBUG0
      printf("check_time_against_period() start\n");
#endif
      
      /* if no period name was specified, assume the time is good */
      if(period_name==NULL)
            return OK;

      /* if no period name was specified, assume the time is good */
      if(!strcmp(period_name,""))
            return OK;

      /* if period could not be found, assume the time is good */
      temp_period=find_timeperiod(period_name,NULL);
      if(temp_period==NULL)
            return OK;

      t=localtime((time_t *)&check_time);

      /* calculate the start of the day (midnight, 00:00 hours) */
      t->tm_sec=0;
      t->tm_min=0;
      t->tm_hour=0;
      midnight_today=(unsigned long)mktime(t);

      for(temp_range=temp_period->days[t->tm_wday];temp_range!=NULL;temp_range=temp_range->next){

            /* if the user-specified time falls in this range, return with a positive result */
            if(check_time>=(time_t)(midnight_today+temp_range->range_start) && check_time<=(time_t)(midnight_today+temp_range->range_end))
                  return OK;
              }

#ifdef DEBUG0
      printf("check_time_against_period() end\n");
#endif

      return ERROR;
        }



/* given a preferred time, get the next valid time within a time period */ 
void get_next_valid_time(time_t preferred_time,time_t *valid_time, char *period_name){
      timeperiod *temp_period;
      timerange *temp_timerange;
      unsigned long midnight_today;
      struct tm *t;
      int today;
      int weekday;
      unsigned long earliest_next_valid_time=0L;
      time_t this_time_range_start;
      int has_looped=FALSE;
      int days_into_the_future;

#ifdef DEBUG0
      printf("get_next_valid_time() start\n");
#endif

#ifdef DEBUG1
      printf("\tPreferred Time: %lu --> %s",(unsigned long)preferred_time,ctime(&preferred_time));
#endif

      /* if the preferred time is valid today, go with it */
      if(check_time_against_period(preferred_time,period_name)==OK)
            *valid_time=preferred_time;

      /* else find the next available time */
      else{

            /* find the time period - if we can't find it, go with the preferred time */
            temp_period=find_timeperiod(period_name,NULL);
            if(temp_period==NULL){
                  *valid_time=preferred_time;
                  return;
                    }

 
            t=localtime((time_t *)&preferred_time);

            /* calculate the start of the day (midnight, 00:00 hours) */
            t->tm_sec=0;
            t->tm_min=0;
            t->tm_hour=0;
            midnight_today=(unsigned long)mktime(t);

            today=t->tm_wday;

            has_looped=FALSE;

            /* check a one week rotation of time */
            for(weekday=today,days_into_the_future=0;;weekday++,days_into_the_future++){

                  if(weekday>=7){
                        weekday-=7;
                        has_looped=TRUE;
                          }

                  /* check all time ranges for this day of the week */
                  for(temp_timerange=temp_period->days[weekday];temp_timerange!=NULL;temp_timerange=temp_timerange->next){

                        /* calculate the time for the start of this time range */
                        this_time_range_start=(time_t)(midnight_today+(days_into_the_future*3600*24)+temp_timerange->range_start);

                        /* we're looking for the earliest possible start time for this day */
                        if((earliest_next_valid_time==(time_t)0 || (this_time_range_start < earliest_next_valid_time)) && (this_time_range_start >= (time_t)preferred_time))
                              earliest_next_valid_time=this_time_range_start;
                          }

                  /* break out of the loop if we have checked an entire week already */
                  if(has_looped==TRUE && weekday >= today)
                        break;
                    }

            /* if we couldn't find a time period (there must be none defined) */
            if(earliest_next_valid_time==(time_t)0)
                  *valid_time=(time_t)preferred_time;

            /* else use the calculated time */
            else
                  *valid_time=earliest_next_valid_time;
              }

#ifdef DEBUG1
      printf("\tNext Valid Time: %lu --> %s",(unsigned long)*valid_time,ctime(valid_time));
#endif

#ifdef DEBUG0
      printf("get_next_valid_time() end\n");
#endif

      return;
        }

      
       

/* given a date/time in time_t format, produce a corresponding date/time string, including timezone */
void get_datetime_string(time_t *raw_time,char *buffer,int buffer_length, int type){
      time_t t;
      struct tm *tm_ptr;
      int hour;
      int minute;
      int second;
      int month;
      int day;
      int year;
      char *weekdays[7]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
      char *months[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sept","Oct","Nov","Dec"};
      char *tzone="";

      if(raw_time==NULL)
            time(&t);
      else 
            t=*raw_time;

      tm_ptr=localtime(&t);

      hour=tm_ptr->tm_hour;
      minute=tm_ptr->tm_min;
      second=tm_ptr->tm_sec;
      month=tm_ptr->tm_mon+1;
      day=tm_ptr->tm_mday;
      year=tm_ptr->tm_year+1900;

#ifdef HAVE_TM_ZONE
      tzone=(char *)tm_ptr->tm_zone;
#else
      tzone=(tm_ptr->tm_isdst)?tzname[1]:tzname[0];
#endif

      /* ctime() style date/time */
      if(type==LONG_DATE_TIME)
            snprintf(buffer,buffer_length,"%s %s %d %02d:%02d:%02d %s %d",weekdays[tm_ptr->tm_wday],months[tm_ptr->tm_mon],day,hour,minute,second,tzone,year);

      /* short date/time */
      else if(type==SHORT_DATE_TIME){
            if(date_format==DATE_FORMAT_EURO)
                  snprintf(buffer,buffer_length,"%02d-%02d-%04d %02d:%02d:%02d",day,month,year,hour,minute,second);
            else if(date_format==DATE_FORMAT_ISO8601 || date_format==DATE_FORMAT_STRICT_ISO8601)
                  snprintf(buffer,buffer_length,"%04d-%02d-%02d%c%02d:%02d:%02d",year,month,day,(date_format==DATE_FORMAT_STRICT_ISO8601)?'T':' ',hour,minute,second);
            else
                  snprintf(buffer,buffer_length,"%02d-%02d-%04d %02d:%02d:%02d",month,day,year,hour,minute,second);
              }

      /* short date */
      else if(type==SHORT_DATE){
            if(date_format==DATE_FORMAT_EURO)
                  snprintf(buffer,buffer_length,"%02d-%02d-%04d",day,month,year);
            else if(date_format==DATE_FORMAT_ISO8601 || date_format==DATE_FORMAT_STRICT_ISO8601)
                  snprintf(buffer,buffer_length,"%04d-%02d-%02d",year,month,day);
            else
                  snprintf(buffer,buffer_length,"%02d-%02d-%04d",month,day,year);
              }

      /* short time */
      else
            snprintf(buffer,buffer_length,"%02d:%02d:%02d",hour,minute,second);

      buffer[buffer_length-1]='\x0';

      return;
        }



/* get the next time to schedule a log rotation */
void get_next_log_rotation_time(time_t *run_time){
      time_t current_time;
      struct tm *t;
      int is_dst_now=FALSE;

#ifdef DEBUG0
      printf("get_next_log_rotation_time() start\n");
#endif
      
      time(&current_time);
      t=localtime(&current_time);
      t->tm_min=0;
      t->tm_sec=0;
      is_dst_now=(t->tm_isdst>0)?TRUE:FALSE;

      switch(log_rotation_method){
      case LOG_ROTATION_HOURLY:
            t->tm_hour++;
            *run_time=mktime(t);
            break;
      case LOG_ROTATION_DAILY:
            t->tm_mday++;
            t->tm_hour=0;
            *run_time=mktime(t);
            break;
      case LOG_ROTATION_WEEKLY:
            t->tm_mday+=(7-t->tm_wday);
            t->tm_hour=0;
            *run_time=mktime(t);
            break;
      case LOG_ROTATION_MONTHLY:
            t->tm_mon++;
            t->tm_mday=1;
            t->tm_hour=0;
            *run_time=mktime(t);
            break;
      default:
            break;
              }

      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;


#ifdef DEBUG1
      printf("\tNext Log Rotation Time: %s",ctime(run_time));
#endif

#ifdef DEBUG0
      printf("get_next_log_rotation_time() end\n");
#endif

      return;
        }



/******************************************************************/
/******************** SIGNAL HANDLER FUNCTIONS ********************/
/******************************************************************/


/* trap signals so we can exit gracefully */
void setup_sighandler(void){

#ifdef DEBUG0
      printf("setup_sighandler() start\n");
#endif

      /* reset the shutdown flag */
      sigshutdown=FALSE;

      /* remove buffering from stderr, stdin, and stdout */
      setbuf(stdin,(char *)NULL);
      setbuf(stdout,(char *)NULL);
      setbuf(stderr,(char *)NULL);

      /* initialize signal handling */
      signal(SIGQUIT,sighandler);
      signal(SIGTERM,sighandler);
      signal(SIGHUP,sighandler);
      signal(SIGSEGV,sighandler);

#ifdef DEBUG0
      printf("setup_sighandler() end\n");
#endif

      return;
        }


/* reset signal handling... */
void reset_sighandler(void){

#ifdef DEBUG0
      printf("reset_sighandler() start\n");
#endif

      /* set signal handling to default actions */
      signal(SIGQUIT,SIG_DFL);
      signal(SIGTERM,SIG_DFL);
      signal(SIGHUP,SIG_DFL);
      signal(SIGSEGV,SIG_DFL);

#ifdef DEBUG0
      printf("reset_sighandler() end\n");
#endif

      return;
        }


/* handle signals */
void sighandler(int sig){
      static char *sigs[]={"EXIT","HUP","INT","QUIT","ILL","TRAP","ABRT","BUS","FPE","KILL","USR1","SEGV","USR2","PIPE","ALRM","TERM","STKFLT","CHLD","CONT","STOP","TSTP","TTIN","TTOU","URG","XCPU","XFSZ","VTALRM","PROF","WINCH","IO","PWR","UNUSED","ZERR","DEBUG",(char *)NULL};
      int i;
      char temp_buffer[MAX_INPUT_BUFFER];


      /* if shutdown is already true, we're in a signal trap loop! */
      if(sigshutdown==TRUE)
            exit(ERROR);

      if(sig<0)
            sig=-sig;

      for(i=0;sigs[i]!=(char *)NULL;i++);

      sig%=i;

      /* we received a SIGHUP, so restart... */
      if(sig==SIGHUP){

            sigrestart=TRUE;

            sprintf(temp_buffer,"Caught SIGHUP, restarting...\n");
            write_to_logs_and_console(temp_buffer,NSLOG_PROCESS_INFO,FALSE);
#ifdef DEBUG2
            printf("%s\n",temp_buffer);
#endif
              }

      /* else begin shutting down... */
      else if(sig<16){

            sigshutdown=TRUE;

            sprintf(temp_buffer,"Caught SIG%s, shutting down...\n",sigs[sig]);
            write_to_logs_and_console(temp_buffer,NSLOG_PROCESS_INFO,FALSE);

#ifdef DEBUG2
            printf("%s\n",temp_buffer);
#endif

            /* remove the lock file if we're in daemon mode */
            if(daemon_mode==TRUE)
                  unlink(lock_file);

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

      return;
        }


/* handle timeouts when executing service checks */
void service_check_sighandler(int sig){

      /* write plugin check results to message queue */
      strncpy(svc_msg.output,"(Service Check Timed Out)",sizeof(svc_msg.output)-1);
      svc_msg.output[sizeof(svc_msg.output)-1]='\x0';
      svc_msg.return_code=STATE_CRITICAL;
      svc_msg.exited_ok=TRUE;
      svc_msg.check_type=SERVICE_CHECK_ACTIVE;
      svc_msg.finish_time=time(NULL);
      write_svc_message(&svc_msg);

      /* close write end of IPC pipe */
      close(ipc_pipe[1]);

      /* try to kill the command that timed out by sending termination signal to our process group */
      /* we also kill ourselves while doing this... */
      kill((pid_t)0,SIGKILL);
      
      /* force the child process (service check) to exit... */
      exit(STATE_CRITICAL);
        }


/* handle timeouts when executing commands via my_system() */
void my_system_sighandler(int sig){

      /* force the child process to exit... */
      exit(STATE_CRITICAL);
        }




/******************************************************************/
/************************ DAEMON FUNCTIONS ************************/
/******************************************************************/

int daemon_init(void){
      pid_t pid=-1;
      int pidno;
      int lockfile;
      int val=0;
      char buf[256];
      struct flock lock;
      char temp_buffer[MAX_INPUT_BUFFER];

#ifdef RLIMIT_CORE
      struct rlimit limit;
#endif

      chdir("/");       /* change working directory */

      umask(S_IWGRP|S_IWOTH);

      lockfile=open(lock_file,O_RDWR | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);

      if(lockfile<0){
            strcpy(temp_buffer,"");
            if(errno==EISDIR)
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"%s is a directory\n",lock_file);
            else if(errno==EACCES)
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"You do not have permission to write to %s\n",lock_file);
            else if(errno==ENAMETOOLONG)
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"The filename is too long: %s\n",lock_file);
            else if(errno==ENOENT)
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"%s does not exist (ENOENT)\n",lock_file);
            else if(errno==ENOTDIR)
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"%s does not exist (ENOTDIR)\n",lock_file);
            else if(errno==ENXIO)
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"Cannot write to special file\n");
            else if(errno==ENODEV)
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"Cannot write to device\n");
            else if(errno==EROFS)
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"%s is on a read-only file system\n",lock_file);
            else if(errno==ETXTBSY)
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"%s is a currently running program\n",lock_file);
            else if(errno==EFAULT)
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"%s is outside address space\n",lock_file);
            else if(errno==ELOOP)
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"Too many symbolic links\n");
            else if(errno==ENOSPC)
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"No space on device\n");
            else if(errno==ENOMEM)
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"Insufficient kernel memory\n");
            else if(errno==EMFILE)
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"Too many files open in process\n");
            else if(errno==ENFILE)
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"Too many files open on system\n");

            temp_buffer[sizeof(temp_buffer)-1]='\x0';
            write_to_logs_and_console(temp_buffer,NSLOG_RUNTIME_ERROR,TRUE);

            snprintf(temp_buffer,sizeof(temp_buffer),"Bailing out due to errors encountered while attempting to daemonize... (PID=%d)",(int)getpid());
            temp_buffer[sizeof(temp_buffer)-1]='\x0';
            write_to_logs_and_console(temp_buffer,NSLOG_PROCESS_INFO | NSLOG_RUNTIME_ERROR,TRUE);

            cleanup();
            exit(ERROR);
              }

      /* see if we can read the contents of the lockfile */
      if((val=read(lockfile,buf,(size_t)10))<0){
            write_to_logs_and_console("Lockfile exists but cannot be read",NSLOG_RUNTIME_ERROR,TRUE);
            cleanup();
            exit(ERROR);
              }

      /* we read something - check the PID */
      if(val>0){
            if((val=sscanf(buf,"%d",&pidno))<1){
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"Lockfile '%s' does not contain a valid PID (%s)",lock_file,buf);
                  write_to_logs_and_console(temp_buffer,NSLOG_RUNTIME_ERROR,TRUE);
                  cleanup();
                  exit(ERROR);
                    }
              }

      /* check for SIGHUP */
      if(val==1 && (pid=(pid_t)pidno)==getpid()){
            close(lockfile);
            return OK;
              }

      /* exit on errors... */
      if((pid=fork())<0)
            return(ERROR);

      /* parent process goes away.. */
      else if((int)pid != 0)
            exit(OK);

      /* child continues... */

      /* child becomes session leader... */
      setsid();

      /* place a file lock on the lock file */
      lock.l_type=F_WRLCK;
      lock.l_start=0;
      lock.l_whence=SEEK_SET;
      lock.l_len=0;
      if(fcntl(lockfile,F_SETLK,&lock)<0){
            if(errno==EACCES || errno==EAGAIN)
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"Lockfile '%s' is held by PID %d.  Bailing out...",lock_file,(int)lock.l_pid);
            else
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"Cannot lock lockfile '%s': %s. Bailing out...",lock_file,strerror(errno));
            write_to_logs_and_console(temp_buffer,NSLOG_RUNTIME_ERROR,TRUE);
            cleanup();
            exit(ERROR);
              }

      /* prevent daemon from dumping a core file... */
#ifdef RLIMIT_CORE
      getrlimit(RLIMIT_CORE,&limit);
      limit.rlim_cur=0;
      setrlimit(RLIMIT_CORE,&limit);
#endif

      /* write PID to lockfile... */
      lseek(lockfile,0,SEEK_SET);
      ftruncate(lockfile,0);
      sprintf(buf,"%d\n",(int)getpid());
      write(lockfile,buf,strlen(buf));

      /* make sure lock file stays open while program is executing... */
      val=fcntl(lockfile,F_GETFD,0);
      val|=FD_CLOEXEC;
      fcntl(lockfile,F_SETFD,val);

        /* close existing stdin, stdout, stderr */
      close(0);
      close(1);
      close(2);

      /* THIS HAS TO BE DONE TO AVOID PROBLEMS WITH STDERR BEING REDIRECTED TO SERVICE MESSAGE PIPE! */
      /* re-open stdin, stdout, stderr with known values */
      open("/dev/null",O_RDONLY);
      open("/dev/null",O_WRONLY);
      open("/dev/null",O_WRONLY);

      return OK;
      }




/******************************************************************/
/*********************** SECURITY FUNCTIONS ***********************/
/******************************************************************/

/* drops privileges */
int drop_privileges(char *user, char *group){
      char temp_buffer[MAX_INPUT_BUFFER];
      uid_t uid=-1;
      gid_t gid=-1;
      struct group *grp;
      struct passwd *pw;

#ifdef DEBUG0
      printf("drop_privileges() start\n");
#endif

#ifdef DEBUG1
      printf("Original UID/GID: %d/%d\n",(int)getuid(),(int)getgid());
#endif

      /* set effective group ID */
      if(group!=NULL){
            
            /* see if this is a group name */
            if(strspn(group,"0123456789")<strlen(group)){
                  grp=(struct group *)getgrnam(group);
                  if(grp!=NULL)
                        gid=(gid_t)(grp->gr_gid);
                  else{
                        snprintf(temp_buffer,sizeof(temp_buffer)-1,"Warning: Could not get group entry for '%s'",group);
                        temp_buffer[sizeof(temp_buffer)-1]='\x0';
                        write_to_logs_and_console(temp_buffer,NSLOG_RUNTIME_WARNING,TRUE);
                            }
                    }

            /* else we were passed the GID */
            else
                  gid=(gid_t)atoi(group);

            /* set effective group ID if other than current EGID */
            if(gid!=getegid()){

                  if(setgid(gid)==-1){
                        snprintf(temp_buffer,sizeof(temp_buffer)-1,"Warning: Could not set effective GID=%d",(int)gid);
                        temp_buffer[sizeof(temp_buffer)-1]='\x0';
                        write_to_logs_and_console(temp_buffer,NSLOG_RUNTIME_WARNING,TRUE);
                          }
                    }
              }


      /* set effective user ID */
      if(user!=NULL){
            
            /* see if this is a user name */
            if(strspn(user,"0123456789")<strlen(user)){
                  pw=(struct passwd *)getpwnam(user);
                  if(pw!=NULL)
                        uid=(uid_t)(pw->pw_uid);
                  else{
                        snprintf(temp_buffer,sizeof(temp_buffer)-1,"Warning: Could not get passwd entry for '%s'",user);
                        temp_buffer[sizeof(temp_buffer)-1]='\x0';
                        write_to_logs_and_console(temp_buffer,NSLOG_RUNTIME_WARNING,TRUE);
                          }
                    }

            /* else we were passed the UID */
            else
                  uid=(uid_t)atoi(user);
                  
#ifdef HAVE_INITGROUPS

            if(uid!=geteuid()){

                  /* initialize supplementary groups */
                  if(initgroups(user,gid)==-1){
                        if(errno==EPERM){
                              snprintf(temp_buffer,sizeof(temp_buffer)-1,"Warning: Unable to change supplementary groups using initgroups() -- I hope you know what you're doing");
                              temp_buffer[sizeof(temp_buffer)-1]='\x0';
                              write_to_logs_and_console(temp_buffer,NSLOG_RUNTIME_WARNING,TRUE);
                                    }
                        else{
                              snprintf(temp_buffer,sizeof(temp_buffer)-1,"Warning: Possibly root user failed dropping privileges with initgroups()");
                              temp_buffer[sizeof(temp_buffer)-1]='\x0';
                              write_to_logs_and_console(temp_buffer,NSLOG_RUNTIME_WARNING,TRUE);
                              return ERROR;
                                  }
                              }
                    }
#endif
            if(setuid(uid)==-1){
                  snprintf(temp_buffer,sizeof(temp_buffer)-1,"Warning: Could not set effective UID=%d",(int)uid);
                  temp_buffer[sizeof(temp_buffer)-1]='\x0';
                  write_to_logs_and_console(temp_buffer,NSLOG_RUNTIME_WARNING,TRUE);
                    }
              }

#ifdef DEBUG1
      printf("New UID/GID: %d/%d\n",(int)getuid(),(int)getgid());
#endif

#ifdef DEBUG0
      printf("drop_privileges() end\n");
#endif

      return OK;
        }




/******************************************************************/
/************************* IPC FUNCTIONS **************************/
/******************************************************************/



/* reads a service message from the message pipe */
int read_svc_message(service_message *message){
      int read_result;
      int bytes_to_read;
      int write_offset;

#ifdef DEBUG0
      printf("read_svc_message() start\n");
#endif

      /* clear the message buffer */
      bzero((void *)message,sizeof(service_message));

      /* initialize the number of bytes to read */
      bytes_to_read=sizeof(service_message);

        /* read a single message from the pipe, taking into consideration that we may have had an interrupt */
      while(1){

            write_offset=sizeof(service_message)-bytes_to_read;

            /* try and read a (full or partial) message */
            read_result=read(ipc_pipe[0],message+write_offset,bytes_to_read);

            /* we had a failure in reading from the pipe... */
            if(read_result==-1){

                  /* if the problem wasn't due to an interrupt, return with an error */
                  if(errno!=EINTR)
                        break;

                  /* otherwise we'll try reading from the pipe again... */
                    }

            /* are we at the end of pipe? this should not happen... */
            else if(read_result==0){

                  read_result=-1;
                  break;
                    }

            /* did we read fewer bytes than we were supposed to?  if so, try this read and try again (so we get the rest of the message)... */
            else if(read_result<bytes_to_read){
                  bytes_to_read-=read_result;
                  continue;
                    }

            else
                  break;
              }

#ifdef DEBUG0
      printf("read_svc_message() end\n");
#endif

      return read_result;
      }



/* writes a service message to the message pipe */
int write_svc_message(service_message *message){
      int write_result;

#ifdef DEBUG0
      printf("write_svc_message() start\n");
#endif

      while(1){

            write_result=write(ipc_pipe[1],message,sizeof(service_message));

            if(write_result==-1){

                  if(errno!=EINTR && errno!=EAGAIN)
                        break;
                     }
            else 
                  break;
              }


#ifdef DEBUG0
      printf("write_svc_message() end\n");
#endif

      return write_result;
        }


/* creates external command file as a named pipe (FIFO) and opens it for reading (non-blocked mode) */
int open_command_file(void){
      char buffer[MAX_INPUT_BUFFER];
      int result;

#ifdef DEBUG0
      printf("open_command_file() start\n");
#endif

      /* if we're not checking external commands, don't do anything */
      if(check_external_commands==FALSE)
            return OK;

      /* the command file was already created */
      if(command_file_created==TRUE)
            return OK;

      /* reset umask (group needs write permissions) */
      umask(S_IWOTH);

      /* create the external command file as a named pipe (FIFO) */
      if((result=mkfifo(command_file,S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP))!=0){

            snprintf(buffer,sizeof(buffer)-1,"Error: Could not create external command file '%s' as named pipe: (%d) -> %s.  If this file already exists and you are sure that another copy of Nagios is not running, you should delete this file.\n",command_file,errno,strerror(errno));
            buffer[sizeof(buffer)-1]='\x0';
            write_to_logs_and_console(buffer,NSLOG_RUNTIME_ERROR,TRUE);

            return ERROR;
              }

      /* open the command file for reading (non-blocked) - O_TRUNC flag cannot be used due to errors on some systems */
      if((command_file_fd=open(command_file,O_RDONLY | O_NONBLOCK))<0){

            snprintf(buffer,sizeof(buffer)-1,"Error: Could not open external command file for reading via open(): (%d) -> %s\n",errno,strerror(errno));
            buffer[sizeof(buffer)-1]='\x0';
            write_to_logs_and_console(buffer,NSLOG_RUNTIME_ERROR,TRUE);

            return ERROR;
              }

      /* re-open the FIFO for use with fgets() */
      if((command_file_fp=fdopen(command_file_fd,"r"))==NULL){

            snprintf(buffer,sizeof(buffer)-1,"Error: Could not open external command file for reading via fdopen(): (%d) -> %s\n",errno,strerror(errno));
            buffer[sizeof(buffer)-1]='\x0';
            write_to_logs_and_console(buffer,NSLOG_RUNTIME_ERROR,TRUE);

            return ERROR;
              }

      /* set a flag to remember we already created the file */
      command_file_created=TRUE;

#ifdef DEBUG0
      printf("open_command_file() end\n");
#endif

      return OK;
        }


/* closes the external command file FIFO and deletes it */
int close_command_file(void){
      int result;

#ifdef DEBUG0
      printf("close_command_file() start\n");
#endif

      /* if we're not checking external commands, don't do anything */
      if(check_external_commands==FALSE)
            return OK;

      /* delete the named pipe prior to closing */
      /* since there is a race condition of processes */
      /* opening the pipe after we close and before it is */
      /* removed */
      result=unlink(command_file);

      /* close the command file */
      fclose(command_file_fp);
      close(command_file_fd);

      /* an error occurred while trying to delete the command file */
      if(result!=0)
            return ERROR;

#ifdef DEBUG0
      printf("close_command_file() end\n");
#endif

      return OK;
        }




/******************************************************************/
/************************ STRING FUNCTIONS ************************/
/******************************************************************/

/* strip newline, carriage return, and tab characters from end of a string */
void strip(char *buffer){
      register int x;

      if(buffer==NULL)
            return;

      x=(int)strlen(buffer)-1;

      for(;x>=0;x--){
            if(buffer[x]==' ' || buffer[x]=='\n' || buffer[x]=='\r' || buffer[x]=='\t' || buffer[x]==13)
                  buffer[x]='\x0';
            else
                  break;
              }

      return;
      }



/* determines whether or not an object name (host, service, etc) contains illegal characters */
int contains_illegal_object_chars(char *name){
      register int x;
      register int y;
      register int ch;

      if(name==NULL)
            return FALSE;

      x=(int)strlen(name)-1;

      for(;x>=0;x--){

            ch=(int)name[x];

            /* illegal ASCII characters */
            if(ch<32 || ch==127)
                  return TRUE;

            /* illegal extended ASCII characters */
            if(ch>=166)
                  return TRUE;

            /* illegal user-specified characters */
            if(illegal_object_chars!=NULL)
                  for(y=0;illegal_object_chars[y];y++)
                        if(name[x]==illegal_object_chars[y])
                              return TRUE;
              }

      return FALSE;
        }



/* cleans illegal characters in macros before output */
char *clean_macro_chars(char *macro,int options){
      register int x,y,z;
      register int ch;
      register int len;
      register int illegal_char;

      if(macro==NULL)
            return "";

      len=(int)strlen(macro);

      /* strip illegal characters out of macro */
      if(options & STRIP_ILLEGAL_MACRO_CHARS){

            for(y=0,x=0;x<len;x++){
                  
                  ch=(int)macro[x];

                  /* illegal ASCII characters */
                  if(ch<32 || ch==127)
                        continue;

                  /* illegal extended ASCII characters */
                  if(ch>=166)
                        continue;

                  /* illegal user-specified characters */
                  illegal_char=FALSE;
                  if(illegal_output_chars!=NULL){
                        for(z=0;illegal_output_chars[z]!='\x0';z++){
                              if(ch==(int)illegal_output_chars[z]){
                                    illegal_char=TRUE;
                                    break;
                                      }
                                }
                          }
                        
                    if(illegal_char==FALSE)
                        macro[y++]=macro[x];
                    }

            macro[y++]='\x0';
              }

#ifdef ON_HOLD_FOR_NOW
      /* escape nasty character in macro */
      if(options & ESCAPE_MACRO_CHARS){
              }
#endif

      return macro;
        }



/* fix the problem with strtok() skipping empty options between tokens */     
char *my_strtok(char *buffer,char *tokens){
      char *token_position;
      char *sequence_head;

      if(buffer!=NULL){
            if(original_my_strtok_buffer!=NULL)
                  free(original_my_strtok_buffer);
            my_strtok_buffer=(char *)malloc(strlen(buffer)+1);
            if(my_strtok_buffer==NULL)
                  return NULL;
            original_my_strtok_buffer=my_strtok_buffer;
            strcpy(my_strtok_buffer,buffer);
              }
      
      sequence_head=my_strtok_buffer;

      if(sequence_head[0]=='\x0')
            return NULL;
      
      token_position=index(my_strtok_buffer,tokens[0]);

      if(token_position==NULL){
            my_strtok_buffer=index(my_strtok_buffer,'\x0');
            return sequence_head;
              }

      token_position[0]='\x0';
      my_strtok_buffer=token_position+1;

      return sequence_head;
        }



/* fixes compiler problems under Solaris, since strsep() isn't included */
/* this code is taken from the glibc source */
char *my_strsep (char **stringp, const char *delim){
      char *begin, *end;

      begin = *stringp;
      if (begin == NULL)
            return NULL;

      /* A frequent case is when the delimiter string contains only one
         character.  Here we don't need to call the expensive `strpbrk'
         function and instead work using `strchr'.  */
      if(delim[0]=='\0' || delim[1]=='\0'){
            char ch = delim[0];

            if(ch=='\0')
                  end=NULL;
            else{
                  if(*begin==ch)
                        end=begin;
                  else
                        end=strchr(begin+1,ch);
                  }
            }

      else
            /* Find the end of the token.  */
            end = strpbrk (begin, delim);

      if(end){

            /* Terminate the token and set *STRINGP past NUL character.  */
            *end++='\0';
            *stringp=end;
            }
      else
            /* No more delimiters; this is the last token.  */
            *stringp=NULL;

      return begin;
      }




/******************************************************************/
/************************* FILE FUNCTIONS *************************/
/******************************************************************/

/* renames a file - works across filesystems (Mike Wiacek) */
int my_rename(char *source, char *dest){
      char buffer[MAX_INPUT_BUFFER]={0};
      int rename_result;
      int source_fd;
      int dest_fd;
      int bytes_read;


      /* make sure we have something */
      if(source==NULL || dest==NULL)
            return -1;

      /* first see if we can rename file with standard function */
      rename_result=rename(source,dest);

      /* an error occurred because the source and dest files are on different filesystems */
      if(rename_result==-1 && errno==EXDEV){

#ifdef DEBUG2
            printf("\tMoving file across file systems.\n");
#endif

            /* open destination file for writing */
            if((dest_fd=open(dest,O_WRONLY|O_TRUNC|O_CREAT|O_APPEND,0644))>0){

                  /* open source file for reading */
                  if((source_fd=open(source,O_RDONLY,0644))>0){

                        while((bytes_read=read(source_fd,buffer,sizeof(buffer)))>0)
                              write(dest_fd,buffer,bytes_read);

                        close(source_fd);
                        close(dest_fd);
                        
                        /* delete the original file */
                        unlink(source);

                        /* reset result since we sucessfully copied file */
                        rename_result=0;
                          }

                  else{
                        close(dest_fd);
                        return rename_result;
                          }
                    }

            else
                  return rename_result;
              }

      return rename_result;
        }



/******************************************************************/
/*********************** CLEANUP FUNCTIONS ************************/
/******************************************************************/

/* do some cleanup before we exit */
void cleanup(void){

#ifdef DEBUG0
      printf("cleanup() start\n");
#endif

      /* free all allocated memory */
      free_memory();

      /* reset global variables to default values */
      reset_variables();

      /* clear all macros */
      clear_volatile_macros();
      clear_nonvolatile_macros();

#ifdef DEBUG0
      printf("cleanup() end\n");
#endif

      return;
      }


/* free the memory allocated to the linked lists */
void free_memory(void){
      timed_event *this_event=NULL;
      timed_event *next_event=NULL;

#ifdef DEBUG0
      printf("free_memory() start\n");
#endif

      /* free all allocated memory for the object definitions */
      free_object_data();

      /* free memory for the high priority event list */
      this_event=event_list_high;
      while(this_event!=NULL){
            next_event=this_event->next;
            free(this_event);
            this_event=next_event;
              }

      /* reset the event pointer */
      event_list_high=NULL;

      /* free memory for the low priority event list */
      this_event=event_list_low;
      while(this_event!=NULL){
            next_event=this_event->next;
            free(this_event);
            this_event=next_event;
              }

      /* reset the event pointer */
      event_list_low=NULL;

#ifdef DEBUG1
      printf("\tevent lists freed\n");
#endif

      /* free memory used by my_strtok() function */
      if(original_my_strtok_buffer!=NULL)
            free(original_my_strtok_buffer);

      /* reset the my_strtok() buffers */
      original_my_strtok_buffer=NULL;
      my_strtok_buffer=NULL;

#ifdef DEBUG1
      printf("\tmy_strtok() buffers freed\n");
#endif

      /* free memory for global event handlers */
      if(global_host_event_handler!=NULL){
            free(global_host_event_handler);
            global_host_event_handler=NULL;
              }
      if(global_service_event_handler!=NULL){
            free(global_service_event_handler);
            global_service_event_handler=NULL;
              }

#ifdef DEBUG1
      printf("\tglobal event handlers freed\n");
#endif

      /* free any notification list that may have been overlooked */
      free_notification_list();

#ifdef DEBUG1
      printf("\tnotification_list freed\n");
#endif

      /* free obsessive compulsive service command */
      if(ocsp_command!=NULL){
            free(ocsp_command);
            ocsp_command=NULL;
              }

      /* free illegal char strings */
      if(illegal_object_chars!=NULL){
            free(illegal_object_chars);
            illegal_object_chars=NULL;
              }
      if(illegal_output_chars!=NULL){
            free(illegal_output_chars);
            illegal_output_chars=NULL;
              }

      /* free nagios user and group */
      if(nagios_user!=NULL){
            free(nagios_user);
            nagios_user=NULL;
              }
      if(nagios_group!=NULL){
            free(nagios_group);
            nagios_group=NULL;
              }

#ifdef DEBUG0
      printf("free_memory() end\n");
#endif

      return;
      }


/* free a notification list that was created */
void free_notification_list(void){
      notification *temp_notification;
      notification *next_notification;

#ifdef DEBUG0
      printf("free_notification_list() start\n");
#endif

      temp_notification=notification_list;
      while(temp_notification!=NULL){
            next_notification=temp_notification->next;
            free((void *)temp_notification);
            temp_notification=next_notification;
              }

      /* reset notification list pointer */
      notification_list=NULL;

#ifdef DEBUG0
      printf("free_notification_list() end\n");
#endif

      return;
        }


/* reset all system-wide variables, so when we've receive a SIGHUP we can restart cleanly */
int reset_variables(void){
      int x;

#ifdef DEBUG0
      printf("reset_variables() start\n");
#endif

      strncpy(log_file,DEFAULT_LOG_FILE,sizeof(log_file));
      log_file[sizeof(log_file)-1]='\x0';
      strncpy(temp_file,DEFAULT_TEMP_FILE,sizeof(temp_file));
      temp_file[sizeof(temp_file)-1]='\x0';
      strncpy(command_file,DEFAULT_COMMAND_FILE,sizeof(command_file));
      command_file[sizeof(command_file)-1]='\x0';
      if(sigrestart==FALSE){
            strncpy(lock_file,DEFAULT_LOCK_FILE,sizeof(lock_file));
            lock_file[sizeof(lock_file)-1]='\x0';
              }
      strncpy(log_archive_path,DEFAULT_LOG_ARCHIVE_PATH,sizeof(log_archive_path));
      log_archive_path[sizeof(log_archive_path)-1]='\x0';

      nagios_user=(char *)malloc(strlen(DEFAULT_NAGIOS_USER)+1);
      if(nagios_user!=NULL)
            strcpy(nagios_user,DEFAULT_NAGIOS_USER);
      nagios_group=(char *)malloc(strlen(DEFAULT_NAGIOS_GROUP)+1);
      if(nagios_group!=NULL)
            strcpy(nagios_group,DEFAULT_NAGIOS_GROUP);

      use_syslog=DEFAULT_USE_SYSLOG;
      log_service_retries=DEFAULT_LOG_SERVICE_RETRIES;
      log_host_retries=DEFAULT_LOG_HOST_RETRIES;
      log_initial_states=DEFAULT_LOG_INITIAL_STATES;

      log_notifications=DEFAULT_NOTIFICATION_LOGGING;
      log_event_handlers=DEFAULT_LOG_EVENT_HANDLERS;
      log_external_commands=DEFAULT_LOG_EXTERNAL_COMMANDS;
      log_passive_checks=DEFAULT_LOG_PASSIVE_CHECKS;

      logging_options=NSLOG_RUNTIME_ERROR | NSLOG_RUNTIME_WARNING | NSLOG_VERIFICATION_ERROR | NSLOG_VERIFICATION_WARNING | NSLOG_CONFIG_ERROR | NSLOG_CONFIG_WARNING | NSLOG_PROCESS_INFO | NSLOG_HOST_NOTIFICATION | NSLOG_SERVICE_NOTIFICATION | NSLOG_EVENT_HANDLER | NSLOG_EXTERNAL_COMMAND | NSLOG_PASSIVE_CHECK | NSLOG_HOST_UP | NSLOG_HOST_DOWN | NSLOG_HOST_UNREACHABLE | NSLOG_SERVICE_OK | NSLOG_SERVICE_WARNING | NSLOG_SERVICE_UNKNOWN | NSLOG_SERVICE_CRITICAL | NSLOG_INFO_MESSAGE;

      syslog_options=NSLOG_RUNTIME_ERROR | NSLOG_RUNTIME_WARNING | NSLOG_VERIFICATION_ERROR | NSLOG_VERIFICATION_WARNING | NSLOG_CONFIG_ERROR | NSLOG_CONFIG_WARNING | NSLOG_PROCESS_INFO | NSLOG_HOST_NOTIFICATION | NSLOG_SERVICE_NOTIFICATION | NSLOG_EVENT_HANDLER | NSLOG_EXTERNAL_COMMAND | NSLOG_PASSIVE_CHECK | NSLOG_HOST_UP | NSLOG_HOST_DOWN | NSLOG_HOST_UNREACHABLE | NSLOG_SERVICE_OK | NSLOG_SERVICE_WARNING | NSLOG_SERVICE_UNKNOWN | NSLOG_SERVICE_CRITICAL | NSLOG_INFO_MESSAGE;

      service_check_timeout=DEFAULT_SERVICE_CHECK_TIMEOUT;
      host_check_timeout=DEFAULT_HOST_CHECK_TIMEOUT;
      event_handler_timeout=DEFAULT_EVENT_HANDLER_TIMEOUT;
      notification_timeout=DEFAULT_NOTIFICATION_TIMEOUT;
      ocsp_timeout=DEFAULT_OCSP_TIMEOUT;

      sleep_time=DEFAULT_SLEEP_TIME;
      interval_length=DEFAULT_INTERVAL_LENGTH;
      inter_check_delay_method=ICD_SMART;
      interleave_factor_method=ILF_SMART;

      use_aggressive_host_checking=DEFAULT_AGGRESSIVE_HOST_CHECKING;

      soft_state_dependencies=FALSE;

      retain_state_information=FALSE;
      retention_update_interval=DEFAULT_RETENTION_UPDATE_INTERVAL;
      use_retained_program_state=TRUE;

      command_check_interval=DEFAULT_COMMAND_CHECK_INTERVAL;
      service_check_reaper_interval=DEFAULT_SERVICE_REAPER_INTERVAL;
      freshness_check_interval=DEFAULT_FRESHNESS_CHECK_INTERVAL;

      check_external_commands=DEFAULT_CHECK_EXTERNAL_COMMANDS;
      check_orphaned_services=DEFAULT_CHECK_ORPHANED_SERVICES;
      check_service_freshness=DEFAULT_CHECK_SERVICE_FRESHNESS;

      log_rotation_method=LOG_ROTATION_NONE;

      last_command_check=0L;
      last_log_rotation=0L;

        max_parallel_service_checks=DEFAULT_MAX_PARALLEL_SERVICE_CHECKS;
        currently_running_service_checks=0;

      enable_notifications=TRUE;
      execute_service_checks=TRUE;
      accept_passive_service_checks=TRUE;
      enable_event_handlers=TRUE;
      obsess_over_services=FALSE;
      enable_failure_prediction=TRUE;

      aggregate_status_updates=TRUE;
      status_update_interval=DEFAULT_STATUS_UPDATE_INTERVAL;

      time_change_threshold=DEFAULT_TIME_CHANGE_THRESHOLD;

      enable_flap_detection=DEFAULT_ENABLE_FLAP_DETECTION;
      low_service_flap_threshold=DEFAULT_LOW_SERVICE_FLAP_THRESHOLD;
      high_service_flap_threshold=DEFAULT_HIGH_SERVICE_FLAP_THRESHOLD;
      low_host_flap_threshold=DEFAULT_LOW_HOST_FLAP_THRESHOLD;
      high_host_flap_threshold=DEFAULT_HIGH_HOST_FLAP_THRESHOLD;

      process_performance_data=DEFAULT_PROCESS_PERFORMANCE_DATA;

      date_format=DATE_FORMAT_US;

      macro_contact_name=NULL;
      macro_contact_alias=NULL;
      macro_host_name=NULL;
      macro_host_alias=NULL;
      macro_host_address=NULL;
      macro_service_description=NULL;
      macro_service_state=NULL;
      macro_output=NULL;
      macro_perfdata=NULL;
      macro_contact_email=NULL;
      macro_contact_pager=NULL;
      macro_admin_email=NULL;
      macro_admin_pager=NULL;
      macro_host_state=NULL;
      macro_state_type=NULL;
      macro_current_service_attempt=NULL;
      macro_current_host_attempt=NULL;
      macro_notification_type=NULL;
      macro_execution_time=NULL;
      macro_latency=NULL;

      macro_date_time[MACRO_DATETIME_LONGDATE]=NULL;
      macro_date_time[MACRO_DATETIME_SHORTDATE]=NULL;
      macro_date_time[MACRO_DATETIME_DATE]=NULL;
      macro_date_time[MACRO_DATETIME_TIME]=NULL;
      macro_date_time[MACRO_DATETIME_TIMET]=NULL;
      macro_date_time[MACRO_DATETIME_LASTCHECK]=NULL;
      macro_date_time[MACRO_DATETIME_LASTSTATECHANGE]=NULL;

      for(x=0;x<MAX_COMMAND_ARGUMENTS;x++)
            macro_argv[x]=NULL;

      for(x=0;x<MAX_USER_MACROS;x++)
            macro_user[x]=NULL;

      global_host_event_handler=NULL;
      global_service_event_handler=NULL;

      ocsp_command=NULL;

      /* reset umask */
      umask(S_IWGRP|S_IWOTH);

#ifdef DEBUG0
      printf("reset_variables() end\n");
#endif

      return OK;
        }

Generated by  Doxygen 1.6.0   Back to index