/***************************************************************************** * * UTILS.C - Miscellaneous utility functions for NetSaint * * Copyright (c) 1999-2002 Ethan Galstad (netsaint@netsaint.org) * Last Modified: 02-20-2002 * * 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 #endif #ifdef HAVE_PWD_H #include #endif #ifdef HAVE_GRP_H #include #endif #include "netsaint.h" #ifdef EMBEDDEDPERL #include #include #include /* 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 #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 *netsaint_user; extern char *netsaint_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 *host_perfdata_command; extern char *service_perfdata_command; 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 perfdata_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 check_external_commands; extern int check_orphaned_services; 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 int program_mode; extern time_t last_mode_change; 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 execute_service_checks; extern int accept_passive_service_checks; extern int enable_event_handlers; extern int obsess_over_services; 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 euro_style_dates; 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 extern char *tzname[2]; #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){ 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)=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==NULL)?"":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;x3) 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;xcommand_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(euro_style_dates==TRUE) snprintf(buffer,buffer_length,"%02d-%02d-%04d %02d:%02d:%02d",day,month,year,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(euro_style_dates==TRUE) snprintf(buffer,buffer_length,"%02d-%02d-%04d",day,month,year); 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(¤t_time); t=localtime(¤t_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: %lu\n",(unsigned long)*run_time); #endif #ifdef DEBUG0 printf("get_next_log_rotation_time() end\n"); #endif return; } /******************************************************************/ /********************* PROGRAM MODE FUNCTIONS *********************/ /******************************************************************/ /* switch to standby or active mode */ void set_program_mode(int mode){ char temp_buffer[MAX_INPUT_BUFFER]; #ifdef DEBUG0 printf("set_program_mode() start\n"); #endif /* set the program mode variable */ if(mode==STANDBY_MODE) program_mode=STANDBY_MODE; else program_mode=ACTIVE_MODE; /* update the last mode change time */ last_mode_change=time(NULL); /* update the status log */ update_program_status(FALSE); snprintf(temp_buffer,sizeof(temp_buffer),"Entering %s mode...\n",(mode==ACTIVE_MODE)?"active":"standby"); temp_buffer[sizeof(temp_buffer)-1]='\x0'; write_to_logs_and_console(temp_buffer,NSLOG_PROCESS_INFO,FALSE); #ifdef DEBUG0 printf("set_program_mode() 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){ snprintf(temp_buffer,sizeof(temp_buffer)-1,"Lockfile '%s' is held by PID %d. Bailing out...",lock_file,(int)pid); 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")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")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(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 %s\n",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; } /* make a note that we already created the command 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){ #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; /* close the command file */ fclose(command_file_fp); close(command_file_fd); /* delete the named pipe */ if(unlink(command_file)!=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){ int x; if(buffer==NULL) return; x=(int)strlen(buffer); for(;x>=1;x--){ if(buffer[x-1]==' ' || buffer[x-1]=='\n' || buffer[x-1]=='\r' || buffer[x-1]=='\t' || buffer[x-1]==13) buffer[x-1]='\x0'; else break; } return; } /* 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 performance data commands */ if(host_perfdata_command!=NULL){ free(host_perfdata_command); host_perfdata_command=NULL; } if(service_perfdata_command!=NULL){ free(service_perfdata_command); service_perfdata_command=NULL; } /* free netsaint user and group */ if(netsaint_user!=NULL){ free(netsaint_user); netsaint_user=NULL; } if(netsaint_group!=NULL){ free(netsaint_group); netsaint_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'; netsaint_user=(char *)malloc(strlen(DEFAULT_NETSAINT_USER)+1); if(netsaint_user!=NULL) strcpy(netsaint_user,DEFAULT_NETSAINT_USER); netsaint_group=(char *)malloc(strlen(DEFAULT_NETSAINT_GROUP)+1); if(netsaint_group!=NULL) strcpy(netsaint_group,DEFAULT_NETSAINT_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; perfdata_timeout=DEFAULT_PERFDATA_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; check_external_commands=DEFAULT_CHECK_EXTERNAL_COMMANDS; check_orphaned_services=DEFAULT_CHECK_ORPHANED_SERVICES; 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; execute_service_checks=TRUE; accept_passive_service_checks=TRUE; enable_event_handlers=TRUE; obsess_over_services=FALSE; 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; euro_style_dates=FALSE; program_mode=ACTIVE_MODE; last_mode_change=time(NULL); 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