/***************************************************************************** * * UTILS.C - Miscellaneous utility functions for Nagios * * Copyright (c) 1999-2007 Ethan Galstad (nagios@nagios.org) * Last Modified: 04-30-2007 * * License: * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *****************************************************************************/ #include "../include/config.h" #include "../include/common.h" #include "../include/objects.h" #include "../include/statusdata.h" #include "../include/comments.h" #include "../include/nagios.h" #include "../include/broker.h" #include "../include/nebmods.h" #include "../include/nebmodules.h" #ifdef EMBEDDEDPERL #include "../include/epn_nagios.h" static PerlInterpreter *my_perl = NULL; int use_embedded_perl=TRUE; #endif char *my_strtok_buffer=NULL; char *original_my_strtok_buffer=NULL; extern char *config_file; extern char *log_file; extern char *command_file; extern char *temp_file; extern char *lock_file; extern char *log_archive_path; extern char *auth_file; extern char *p1_file; extern char *nagios_user; extern char *nagios_group; extern char *macro_x[MACRO_X_COUNT]; extern char *macro_x_names[MACRO_X_COUNT]; extern char *macro_argv[MAX_COMMAND_ARGUMENTS]; extern char *macro_user[MAX_USER_MACROS]; extern char *macro_contactaddress[MAX_CONTACT_ADDRESSES]; extern char *macro_ondemand; extern char *global_host_event_handler; extern char *global_service_event_handler; extern char *ocsp_command; extern char *ochp_command; extern char *illegal_object_chars; extern char *illegal_output_chars; extern int use_regexp_matches; extern int use_true_regexp_matching; extern int sigshutdown; extern int sigrestart; extern char *sigs[35]; extern int caught_signal; extern int sig_id; extern int daemon_mode; extern int daemon_dumps_core; 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 ochp_timeout; extern int log_initial_states; extern double sleep_time; extern int interval_length; extern int service_inter_check_delay_method; extern int host_inter_check_delay_method; extern int service_interleave_factor_method; extern int max_host_check_spread; extern int max_service_check_spread; extern int command_check_interval; extern int service_check_reaper_interval; extern int service_freshness_check_interval; extern int host_freshness_check_interval; extern int auto_rescheduling_interval; extern int auto_rescheduling_window; extern int check_external_commands; extern int check_orphaned_services; extern int check_service_freshness; extern int check_host_freshness; extern int auto_reschedule_checks; 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 use_retained_scheduling_info; extern int retention_scheduling_horizon; extern unsigned long modified_host_process_attributes; extern unsigned long modified_service_process_attributes; extern int log_rotation_method; extern time_t last_command_check; extern time_t last_command_status_update; extern time_t last_log_rotation; extern int verify_config; extern int test_scheduling; 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 execute_host_checks; extern int accept_passive_host_checks; extern int enable_event_handlers; extern int obsess_over_services; extern int obsess_over_hosts; 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 unsigned long event_broker_options; 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 servicegroup *servicegroup_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 pthread_t worker_threads[TOTAL_WORKER_THREADS]; extern circular_buffer external_command_buffer; extern circular_buffer service_result_buffer; extern circular_buffer event_broker_buffer; extern int external_command_buffer_slots; extern int check_result_buffer_slots; /* from GNU defines errno as a macro, since it's a per-thread variable */ #ifndef errno extern int errno; #endif /******************************************************************/ /************************ 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 x; int arg_index=0; int user_index=0; int address_index=0; char *selected_macro=NULL; int clean_macro=FALSE; int found_macro_x=FALSE; #ifdef DEBUG0 printf("process_macros() start\n"); #endif if(output_buffer==NULL || buffer_length<=0) return ERROR; strcpy(output_buffer,""); if(input_buffer==NULL) return ERROR; in_macro=FALSE; /*#define TEST_MACROS 1*/ #ifdef TEST_MACROS printf("**** BEGIN MACRO PROCESSING ***********\n"); printf("Processing: '%s'\n",input_buffer); printf("Buffer length: %d\n",buffer_length); #endif for(temp_buffer=my_strtok(input_buffer,"$");temp_buffer!=NULL;temp_buffer=my_strtok(NULL,"$")){ #ifdef TEST_MACROS printf(" Processing part: '%s'\n",temp_buffer); #endif selected_macro=NULL; found_macro_x=FALSE; clean_macro=FALSE; if(in_macro==FALSE){ if(strlen(output_buffer)+strlen(temp_buffer)=16 && x<=19){ clean_macro=TRUE; options&=STRIP_ILLEGAL_MACRO_CHARS|ESCAPE_MACRO_CHARS; } break; } } /* we already have a macro... */ if(found_macro_x==TRUE) x=0; /* on-demand host macros */ else if(strstr(temp_buffer,"HOST") && strstr(temp_buffer,":")){ grab_on_demand_macro(temp_buffer); selected_macro=macro_ondemand; /* output/perfdata macros get cleaned */ if(strstr(temp_buffer,"HOSTOUTPUT:")==temp_buffer || strstr(temp_buffer,"HOSTPERFDATA:")){ clean_macro=TRUE; options&=STRIP_ILLEGAL_MACRO_CHARS|ESCAPE_MACRO_CHARS; } } /* on-demand service macros */ else if(strstr(temp_buffer,"SERVICE") && strstr(temp_buffer,":")){ grab_on_demand_macro(temp_buffer); selected_macro=macro_ondemand; /* output/perfdata macros get cleaned */ if(strstr(temp_buffer,"SERVICEOUTPUT:")==temp_buffer || strstr(temp_buffer,"SERVICEPERFDATA:")){ clean_macro=TRUE; options&=STRIP_ILLEGAL_MACRO_CHARS|ESCAPE_MACRO_CHARS; } } /* argv macros */ else if(strstr(temp_buffer,"ARG")==temp_buffer){ arg_index=atoi(temp_buffer+3); if(arg_index>=1 && arg_index<=MAX_COMMAND_ARGUMENTS) selected_macro=macro_argv[arg_index-1]; else selected_macro=NULL; } /* user macros */ else if(strstr(temp_buffer,"USER")==temp_buffer){ user_index=atoi(temp_buffer+4); if(user_index>=1 && user_index<=MAX_USER_MACROS) selected_macro=macro_user[user_index-1]; else selected_macro=NULL; } /* contact address macros */ else if(strstr(temp_buffer,"CONTACTADDRESS")==temp_buffer){ address_index=atoi(temp_buffer+14); if(address_index>=1 && address_index<=MAX_CONTACT_ADDRESSES) selected_macro=macro_contactaddress[address_index-1]; else selected_macro=NULL; } /* an escaped $ is done by specifying two $$ next to each other */ else if(!strcmp(temp_buffer,"")){ #ifdef TEST_MACROS printf(" Escaped $. Running output (%d): '%s'\n",strlen(output_buffer),output_buffer); #endif strncat(output_buffer,"$",buffer_length-strlen(output_buffer)-1); } /* a non-macro, just some user-defined string between two $s */ else{ #ifdef TEST_MACROS printf(" Non-macro. Running output (%d): '%s'\n",strlen(output_buffer),output_buffer); #endif 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); } /* insert macro */ if(selected_macro!=NULL){ /* URL encode the macro */ if(options & URL_ENCODE_MACRO_CHARS) selected_macro=get_url_encoded_string(selected_macro); /* some macros are cleaned... */ if(clean_macro==TRUE || ((options & STRIP_ILLEGAL_MACRO_CHARS) || (options & ESCAPE_MACRO_CHARS))) strncat(output_buffer,(selected_macro==NULL)?"":clean_macro_chars(selected_macro,options),buffer_length-strlen(output_buffer)-1); /* others are not cleaned */ else strncat(output_buffer,(selected_macro==NULL)?"":selected_macro,buffer_length-strlen(output_buffer)-1); /* free memory if necessary */ if(options & URL_ENCODE_MACRO_CHARS) free(selected_macro); #ifdef TEST_MACROS printf(" Just finished macro. Running output (%d): '%s'\n",strlen(output_buffer),output_buffer); #endif } output_buffer[buffer_length-1]='\x0'; } in_macro=FALSE; } } #ifdef TEST_MACROS printf("Done. Final output: '%s'\n",output_buffer); printf("**** END MACRO PROCESSING *************\n"); #endif #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){ servicegroup *temp_servicegroup; serviceextinfo *temp_serviceextinfo; time_t current_time; unsigned long duration; int days; int hours; int minutes; int seconds; char temp_buffer[MAX_INPUT_BUFFER]; #ifdef DEBUG0 printf("grab_service_macros() start\n"); #endif /* get the service description */ if(macro_x[MACRO_SERVICEDESC]!=NULL) free(macro_x[MACRO_SERVICEDESC]); macro_x[MACRO_SERVICEDESC]=strdup(svc->description); /* get the plugin output */ if(macro_x[MACRO_SERVICEOUTPUT]!=NULL) free(macro_x[MACRO_SERVICEOUTPUT]); if(svc->plugin_output==NULL) macro_x[MACRO_SERVICEOUTPUT]=NULL; else macro_x[MACRO_SERVICEOUTPUT]=strdup(svc->plugin_output); /* get the performance data */ if(macro_x[MACRO_SERVICEPERFDATA]!=NULL) free(macro_x[MACRO_SERVICEPERFDATA]); if(svc->perf_data==NULL) macro_x[MACRO_SERVICEPERFDATA]=NULL; else macro_x[MACRO_SERVICEPERFDATA]=strdup(svc->perf_data); /* get the service check command */ if(macro_x[MACRO_SERVICECHECKCOMMAND]!=NULL) free(macro_x[MACRO_SERVICECHECKCOMMAND]); if(svc->service_check_command==NULL) macro_x[MACRO_SERVICECHECKCOMMAND]=NULL; else macro_x[MACRO_SERVICECHECKCOMMAND]=strdup(svc->service_check_command); /* grab the service check type */ if(macro_x[MACRO_SERVICECHECKTYPE]!=NULL) free(macro_x[MACRO_SERVICECHECKTYPE]); macro_x[MACRO_SERVICECHECKTYPE]=(char *)malloc(MAX_CHECKTYPE_LENGTH); if(macro_x[MACRO_SERVICECHECKTYPE]!=NULL) strcpy(macro_x[MACRO_SERVICECHECKTYPE],(svc->check_type==SERVICE_CHECK_PASSIVE)?"PASSIVE":"ACTIVE"); /* grab the service state type macro (this is usually overridden later on) */ if(macro_x[MACRO_SERVICESTATETYPE]!=NULL) free(macro_x[MACRO_SERVICESTATETYPE]); macro_x[MACRO_SERVICESTATETYPE]=(char *)malloc(MAX_STATETYPE_LENGTH); if(macro_x[MACRO_SERVICESTATETYPE]!=NULL) strcpy(macro_x[MACRO_SERVICESTATETYPE],(svc->state_type==HARD_STATE)?"HARD":"SOFT"); /* get the service state */ if(macro_x[MACRO_SERVICESTATE]!=NULL) free(macro_x[MACRO_SERVICESTATE]); macro_x[MACRO_SERVICESTATE]=(char *)malloc(MAX_STATE_LENGTH); if(macro_x[MACRO_SERVICESTATE]!=NULL){ if(svc->current_state==STATE_OK) strcpy(macro_x[MACRO_SERVICESTATE],"OK"); else if(svc->current_state==STATE_WARNING) strcpy(macro_x[MACRO_SERVICESTATE],"WARNING"); else if(svc->current_state==STATE_CRITICAL) strcpy(macro_x[MACRO_SERVICESTATE],"CRITICAL"); else strcpy(macro_x[MACRO_SERVICESTATE],"UNKNOWN"); } /* get the service state id */ if(macro_x[MACRO_SERVICESTATEID]!=NULL) free(macro_x[MACRO_SERVICESTATEID]); macro_x[MACRO_SERVICESTATEID]=(char *)malloc(MAX_STATEID_LENGTH); if(macro_x[MACRO_SERVICESTATEID]!=NULL){ snprintf(macro_x[MACRO_SERVICESTATEID],MAX_STATEID_LENGTH,"%d",svc->current_state); macro_x[MACRO_SERVICESTATEID][MAX_STATEID_LENGTH-1]='\x0'; } /* get the current service check attempt macro */ if(macro_x[MACRO_SERVICEATTEMPT]!=NULL) free(macro_x[MACRO_SERVICEATTEMPT]); macro_x[MACRO_SERVICEATTEMPT]=(char *)malloc(MAX_ATTEMPT_LENGTH); if(macro_x[MACRO_SERVICEATTEMPT]!=NULL){ snprintf(macro_x[MACRO_SERVICEATTEMPT],MAX_ATTEMPT_LENGTH,"%d",svc->current_attempt); macro_x[MACRO_SERVICEATTEMPT][MAX_ATTEMPT_LENGTH-1]='\x0'; } /* get the execution time macro */ if(macro_x[MACRO_SERVICEEXECUTIONTIME]!=NULL) free(macro_x[MACRO_SERVICEEXECUTIONTIME]); macro_x[MACRO_SERVICEEXECUTIONTIME]=(char *)malloc(MAX_EXECUTIONTIME_LENGTH); if(macro_x[MACRO_SERVICEEXECUTIONTIME]!=NULL){ snprintf(macro_x[MACRO_SERVICEEXECUTIONTIME],MAX_EXECUTIONTIME_LENGTH,"%.3f",svc->execution_time); macro_x[MACRO_SERVICEEXECUTIONTIME][MAX_EXECUTIONTIME_LENGTH-1]='\x0'; } /* get the latency macro */ if(macro_x[MACRO_SERVICELATENCY]!=NULL) free(macro_x[MACRO_SERVICELATENCY]); macro_x[MACRO_SERVICELATENCY]=(char *)malloc(MAX_LATENCY_LENGTH); if(macro_x[MACRO_SERVICELATENCY]!=NULL){ snprintf(macro_x[MACRO_SERVICELATENCY],MAX_LATENCY_LENGTH,"%.3f",svc->latency); macro_x[MACRO_SERVICELATENCY][MAX_LATENCY_LENGTH-1]='\x0'; } /* get the last check time macro */ if(macro_x[MACRO_LASTSERVICECHECK]!=NULL) free(macro_x[MACRO_LASTSERVICECHECK]); macro_x[MACRO_LASTSERVICECHECK]=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_x[MACRO_LASTSERVICECHECK]!=NULL){ snprintf(macro_x[MACRO_LASTSERVICECHECK],MAX_DATETIME_LENGTH,"%lu",(unsigned long)svc->last_check); macro_x[MACRO_LASTSERVICECHECK][MAX_DATETIME_LENGTH-1]='\x0'; } /* get the last state change time macro */ if(macro_x[MACRO_LASTSERVICESTATECHANGE]!=NULL) free(macro_x[MACRO_LASTSERVICESTATECHANGE]); macro_x[MACRO_LASTSERVICESTATECHANGE]=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_x[MACRO_LASTSERVICESTATECHANGE]!=NULL){ snprintf(macro_x[MACRO_LASTSERVICESTATECHANGE],MAX_DATETIME_LENGTH,"%lu",(unsigned long)svc->last_state_change); macro_x[MACRO_LASTSERVICESTATECHANGE][MAX_DATETIME_LENGTH-1]='\x0'; } /* get the last time ok macro */ if(macro_x[MACRO_LASTSERVICEOK]!=NULL) free(macro_x[MACRO_LASTSERVICEOK]); macro_x[MACRO_LASTSERVICEOK]=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_x[MACRO_LASTSERVICEOK]!=NULL){ snprintf(macro_x[MACRO_LASTSERVICEOK],MAX_DATETIME_LENGTH,"%lu",(unsigned long)svc->last_time_ok); macro_x[MACRO_LASTSERVICEOK][MAX_DATETIME_LENGTH-1]='\x0'; } /* get the last time warning macro */ if(macro_x[MACRO_LASTSERVICEWARNING]!=NULL) free(macro_x[MACRO_LASTSERVICEWARNING]); macro_x[MACRO_LASTSERVICEWARNING]=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_x[MACRO_LASTSERVICEWARNING]!=NULL){ snprintf(macro_x[MACRO_LASTSERVICEWARNING],MAX_DATETIME_LENGTH,"%lu",(unsigned long)svc->last_time_warning); macro_x[MACRO_LASTSERVICEWARNING][MAX_DATETIME_LENGTH-1]='\x0'; } /* get the last time unknown macro */ if(macro_x[MACRO_LASTSERVICEUNKNOWN]!=NULL) free(macro_x[MACRO_LASTSERVICEUNKNOWN]); macro_x[MACRO_LASTSERVICEUNKNOWN]=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_x[MACRO_LASTSERVICEUNKNOWN]!=NULL){ snprintf(macro_x[MACRO_LASTSERVICEUNKNOWN],MAX_DATETIME_LENGTH,"%lu",(unsigned long)svc->last_time_unknown); macro_x[MACRO_LASTSERVICEUNKNOWN][MAX_DATETIME_LENGTH-1]='\x0'; } /* get the last time critical macro */ if(macro_x[MACRO_LASTSERVICECRITICAL]!=NULL) free(macro_x[MACRO_LASTSERVICECRITICAL]); macro_x[MACRO_LASTSERVICECRITICAL]=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_x[MACRO_LASTSERVICECRITICAL]!=NULL){ snprintf(macro_x[MACRO_LASTSERVICECRITICAL],MAX_DATETIME_LENGTH,"%lu",(unsigned long)svc->last_time_critical); macro_x[MACRO_LASTSERVICECRITICAL][MAX_DATETIME_LENGTH-1]='\x0'; } /* get the service downtime depth */ if(macro_x[MACRO_SERVICEDOWNTIME]!=NULL) free(macro_x[MACRO_SERVICEDOWNTIME]); macro_x[MACRO_SERVICEDOWNTIME]=(char *)malloc(MAX_DOWNTIME_LENGTH); if(macro_x[MACRO_SERVICEDOWNTIME]!=NULL){ snprintf(macro_x[MACRO_SERVICEDOWNTIME],MAX_DOWNTIME_LENGTH,"%d",svc->scheduled_downtime_depth); macro_x[MACRO_SERVICEDOWNTIME][MAX_DOWNTIME_LENGTH-1]='\x0'; } /* get the percent state change */ if(macro_x[MACRO_SERVICEPERCENTCHANGE]!=NULL) free(macro_x[MACRO_SERVICEPERCENTCHANGE]); macro_x[MACRO_SERVICEPERCENTCHANGE]=(char *)malloc(MAX_PERCENTCHANGE_LENGTH); if(macro_x[MACRO_SERVICEPERCENTCHANGE]!=NULL){ snprintf(macro_x[MACRO_SERVICEPERCENTCHANGE],MAX_PERCENTCHANGE_LENGTH,"%.2f",svc->percent_state_change); macro_x[MACRO_SERVICEPERCENTCHANGE][MAX_PERCENTCHANGE_LENGTH-1]='\x0'; } time(¤t_time); duration=(unsigned long)(current_time-svc->last_state_change); /* get the state duration in seconds */ if(macro_x[MACRO_SERVICEDURATIONSEC]!=NULL) free(macro_x[MACRO_SERVICEDURATIONSEC]); macro_x[MACRO_SERVICEDURATIONSEC]=(char *)malloc(MAX_DURATION_LENGTH); if(macro_x[MACRO_SERVICEDURATIONSEC]!=NULL){ snprintf(macro_x[MACRO_SERVICEDURATIONSEC],MAX_DURATION_LENGTH,"%lu",duration); macro_x[MACRO_SERVICEDURATIONSEC][MAX_DURATION_LENGTH-1]='\x0'; } /* get the state duration */ if(macro_x[MACRO_SERVICEDURATION]!=NULL) free(macro_x[MACRO_SERVICEDURATION]); macro_x[MACRO_SERVICEDURATION]=(char *)malloc(MAX_DURATION_LENGTH); if(macro_x[MACRO_SERVICEDURATION]!=NULL){ days=duration/86400; duration-=(days*86400); hours=duration/3600; duration-=(hours*3600); minutes=duration/60; duration-=(minutes*60); seconds=duration; snprintf(macro_x[MACRO_SERVICEDURATION],MAX_DURATION_LENGTH,"%dd %dh %dm %ds",days,hours,minutes,seconds); macro_x[MACRO_SERVICEDURATION][MAX_DURATION_LENGTH-1]='\x0'; } /* find one servicegroup (there may be none or several) this service is associated with */ for(temp_servicegroup=servicegroup_list;temp_servicegroup!=NULL;temp_servicegroup=temp_servicegroup->next){ if(is_service_member_of_servicegroup(temp_servicegroup,svc)==TRUE) break; } /* get the servicegroup name */ if(macro_x[MACRO_SERVICEGROUPNAME]!=NULL) free(macro_x[MACRO_SERVICEGROUPNAME]); macro_x[MACRO_SERVICEGROUPNAME]=NULL; if(temp_servicegroup!=NULL) macro_x[MACRO_SERVICEGROUPNAME]=strdup(temp_servicegroup->group_name); /* get the servicegroup alias */ if(macro_x[MACRO_SERVICEGROUPALIAS]!=NULL) free(macro_x[MACRO_SERVICEGROUPALIAS]); macro_x[MACRO_SERVICEGROUPALIAS]=NULL; if(temp_servicegroup!=NULL) macro_x[MACRO_SERVICEGROUPALIAS]=strdup(temp_servicegroup->alias); if((temp_serviceextinfo=find_serviceextinfo(svc->host_name,svc->description))){ /* get the action url */ if(macro_x[MACRO_SERVICEACTIONURL]!=NULL) free(macro_x[MACRO_SERVICEACTIONURL]); if(temp_serviceextinfo->action_url==NULL) macro_x[MACRO_SERVICEACTIONURL]=NULL; else macro_x[MACRO_SERVICEACTIONURL]=strdup(temp_serviceextinfo->action_url); /* get the notes url */ if(macro_x[MACRO_SERVICENOTESURL]!=NULL) free(macro_x[MACRO_SERVICENOTESURL]); if(temp_serviceextinfo->notes_url==NULL) macro_x[MACRO_SERVICENOTESURL]=NULL; else macro_x[MACRO_SERVICENOTESURL]=strdup(temp_serviceextinfo->notes_url); /* get the notes */ if(macro_x[MACRO_SERVICENOTES]!=NULL) free(macro_x[MACRO_SERVICENOTES]); if(temp_serviceextinfo->notes==NULL) macro_x[MACRO_SERVICENOTES]=NULL; else macro_x[MACRO_SERVICENOTES]=strdup(temp_serviceextinfo->notes); } /* get the date/time macros */ grab_datetime_macros(); strip(macro_x[MACRO_SERVICEOUTPUT]); strip(macro_x[MACRO_SERVICEPERFDATA]); strip(macro_x[MACRO_SERVICECHECKCOMMAND]); strip(macro_x[MACRO_SERVICENOTES]); /* notes and action URL macros may themselves contain macros, so process them... */ if(macro_x[MACRO_SERVICEACTIONURL]!=NULL){ process_macros(macro_x[MACRO_SERVICEACTIONURL],temp_buffer,sizeof(temp_buffer),URL_ENCODE_MACRO_CHARS); free(macro_x[MACRO_SERVICEACTIONURL]); macro_x[MACRO_SERVICEACTIONURL]=strdup(temp_buffer); } if(macro_x[MACRO_SERVICENOTESURL]!=NULL){ process_macros(macro_x[MACRO_SERVICENOTESURL],temp_buffer,sizeof(temp_buffer),URL_ENCODE_MACRO_CHARS); free(macro_x[MACRO_SERVICENOTESURL]); macro_x[MACRO_SERVICENOTESURL]=strdup(temp_buffer); } #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){ hostgroup *temp_hostgroup; hostextinfo *temp_hostextinfo; time_t current_time; unsigned long duration; int days; int hours; int minutes; int seconds; char temp_buffer[MAX_INPUT_BUFFER]; #ifdef DEBUG0 printf("grab_host_macros() start\n"); #endif /* get the host name */ if(macro_x[MACRO_HOSTNAME]!=NULL) free(macro_x[MACRO_HOSTNAME]); macro_x[MACRO_HOSTNAME]=strdup(hst->name); /* get the host alias */ if(macro_x[MACRO_HOSTALIAS]!=NULL) free(macro_x[MACRO_HOSTALIAS]); macro_x[MACRO_HOSTALIAS]=strdup(hst->alias); /* get the host address */ if(macro_x[MACRO_HOSTADDRESS]!=NULL) free(macro_x[MACRO_HOSTADDRESS]); macro_x[MACRO_HOSTADDRESS]=strdup(hst->address); /* get the host state */ if(macro_x[MACRO_HOSTSTATE]!=NULL) free(macro_x[MACRO_HOSTSTATE]); macro_x[MACRO_HOSTSTATE]=(char *)malloc(MAX_STATE_LENGTH); if(macro_x[MACRO_HOSTSTATE]!=NULL){ if(hst->current_state==HOST_DOWN) strcpy(macro_x[MACRO_HOSTSTATE],"DOWN"); else if(hst->current_state==HOST_UNREACHABLE) strcpy(macro_x[MACRO_HOSTSTATE],"UNREACHABLE"); else strcpy(macro_x[MACRO_HOSTSTATE],"UP"); } /* get the host state id */ if(macro_x[MACRO_HOSTSTATEID]!=NULL) free(macro_x[MACRO_HOSTSTATEID]); macro_x[MACRO_HOSTSTATEID]=(char *)malloc(MAX_STATEID_LENGTH); if(macro_x[MACRO_HOSTSTATEID]!=NULL){ snprintf(macro_x[MACRO_HOSTSTATEID],MAX_STATEID_LENGTH,"%d",hst->current_state); macro_x[MACRO_HOSTSTATEID][MAX_STATEID_LENGTH-1]='\x0'; } /* grab the host check type */ if(macro_x[MACRO_HOSTCHECKTYPE]!=NULL) free(macro_x[MACRO_HOSTCHECKTYPE]); macro_x[MACRO_HOSTCHECKTYPE]=(char *)malloc(MAX_CHECKTYPE_LENGTH); if(macro_x[MACRO_HOSTCHECKTYPE]!=NULL) strcpy(macro_x[MACRO_HOSTCHECKTYPE],(hst->check_type==HOST_CHECK_PASSIVE)?"PASSIVE":"ACTIVE"); /* get the host state type macro */ if(macro_x[MACRO_HOSTSTATETYPE]!=NULL) free(macro_x[MACRO_HOSTSTATETYPE]); macro_x[MACRO_HOSTSTATETYPE]=(char *)malloc(MAX_STATETYPE_LENGTH); if(macro_x[MACRO_HOSTSTATETYPE]!=NULL) strcpy(macro_x[MACRO_HOSTSTATETYPE],(hst->state_type==HARD_STATE)?"HARD":"SOFT"); /* get the plugin output */ if(macro_x[MACRO_HOSTOUTPUT]!=NULL) free(macro_x[MACRO_HOSTOUTPUT]); if(hst->plugin_output==NULL) macro_x[MACRO_HOSTOUTPUT]=NULL; else macro_x[MACRO_HOSTOUTPUT]=strdup(hst->plugin_output); /* get the performance data */ if(macro_x[MACRO_HOSTPERFDATA]!=NULL) free(macro_x[MACRO_HOSTPERFDATA]); if(hst->perf_data==NULL) macro_x[MACRO_HOSTPERFDATA]=NULL; else macro_x[MACRO_HOSTPERFDATA]=strdup(hst->perf_data); /* get the host check command */ if(macro_x[MACRO_HOSTCHECKCOMMAND]!=NULL) free(macro_x[MACRO_HOSTCHECKCOMMAND]); if(hst->host_check_command==NULL) macro_x[MACRO_HOSTCHECKCOMMAND]=NULL; else macro_x[MACRO_HOSTCHECKCOMMAND]=strdup(hst->host_check_command); /* get the host current attempt */ if(macro_x[MACRO_HOSTATTEMPT]!=NULL) free(macro_x[MACRO_HOSTATTEMPT]); macro_x[MACRO_HOSTATTEMPT]=(char *)malloc(MAX_ATTEMPT_LENGTH); if(macro_x[MACRO_HOSTATTEMPT]!=NULL){ snprintf(macro_x[MACRO_HOSTATTEMPT],MAX_ATTEMPT_LENGTH,"%d",hst->current_attempt); macro_x[MACRO_HOSTATTEMPT][MAX_ATTEMPT_LENGTH-1]='\x0'; } /* get the host downtime depth */ if(macro_x[MACRO_HOSTDOWNTIME]!=NULL) free(macro_x[MACRO_HOSTDOWNTIME]); macro_x[MACRO_HOSTDOWNTIME]=(char *)malloc(MAX_DOWNTIME_LENGTH); if(macro_x[MACRO_HOSTDOWNTIME]!=NULL){ snprintf(macro_x[MACRO_HOSTDOWNTIME],MAX_DOWNTIME_LENGTH,"%d",hst->scheduled_downtime_depth); macro_x[MACRO_HOSTDOWNTIME][MAX_DOWNTIME_LENGTH-1]='\x0'; } /* get the percent state change */ if(macro_x[MACRO_HOSTPERCENTCHANGE]!=NULL) free(macro_x[MACRO_HOSTPERCENTCHANGE]); macro_x[MACRO_HOSTPERCENTCHANGE]=(char *)malloc(MAX_PERCENTCHANGE_LENGTH); if(macro_x[MACRO_HOSTPERCENTCHANGE]!=NULL){ snprintf(macro_x[MACRO_HOSTPERCENTCHANGE],MAX_PERCENTCHANGE_LENGTH,"%.2f",hst->percent_state_change); macro_x[MACRO_HOSTPERCENTCHANGE][MAX_PERCENTCHANGE_LENGTH-1]='\x0'; } time(¤t_time); duration=(unsigned long)(current_time-hst->last_state_change); /* get the state duration in seconds */ if(macro_x[MACRO_HOSTDURATIONSEC]!=NULL) free(macro_x[MACRO_HOSTDURATIONSEC]); macro_x[MACRO_HOSTDURATIONSEC]=(char *)malloc(MAX_DURATION_LENGTH); if(macro_x[MACRO_HOSTDURATIONSEC]!=NULL){ snprintf(macro_x[MACRO_HOSTDURATIONSEC],MAX_DURATION_LENGTH,"%lu",duration); macro_x[MACRO_HOSTDURATIONSEC][MAX_DURATION_LENGTH-1]='\x0'; } /* get the state duration */ if(macro_x[MACRO_HOSTDURATION]!=NULL) free(macro_x[MACRO_HOSTDURATION]); macro_x[MACRO_HOSTDURATION]=(char *)malloc(MAX_DURATION_LENGTH); if(macro_x[MACRO_HOSTDURATION]!=NULL){ days=duration/86400; duration-=(days*86400); hours=duration/3600; duration-=(hours*3600); minutes=duration/60; duration-=(minutes*60); seconds=duration; snprintf(macro_x[MACRO_HOSTDURATION],MAX_DURATION_LENGTH,"%dd %dh %dm %ds",days,hours,minutes,seconds); macro_x[MACRO_HOSTDURATION][MAX_DURATION_LENGTH-1]='\x0'; } /* get the execution time macro */ if(macro_x[MACRO_HOSTEXECUTIONTIME]!=NULL) free(macro_x[MACRO_HOSTEXECUTIONTIME]); macro_x[MACRO_HOSTEXECUTIONTIME]=(char *)malloc(MAX_EXECUTIONTIME_LENGTH); if(macro_x[MACRO_HOSTEXECUTIONTIME]!=NULL){ snprintf(macro_x[MACRO_HOSTEXECUTIONTIME],MAX_EXECUTIONTIME_LENGTH,"%.3f",hst->execution_time); macro_x[MACRO_HOSTEXECUTIONTIME][MAX_EXECUTIONTIME_LENGTH-1]='\x0'; } /* get the latency macro */ if(macro_x[MACRO_HOSTLATENCY]!=NULL) free(macro_x[MACRO_HOSTLATENCY]); macro_x[MACRO_HOSTLATENCY]=(char *)malloc(MAX_LATENCY_LENGTH); if(macro_x[MACRO_HOSTLATENCY]!=NULL){ snprintf(macro_x[MACRO_HOSTLATENCY],MAX_LATENCY_LENGTH,"%.3f",hst->latency); macro_x[MACRO_HOSTLATENCY][MAX_LATENCY_LENGTH-1]='\x0'; } /* get the last check time macro */ if(macro_x[MACRO_LASTHOSTCHECK]!=NULL) free(macro_x[MACRO_LASTHOSTCHECK]); macro_x[MACRO_LASTHOSTCHECK]=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_x[MACRO_LASTHOSTCHECK]!=NULL){ snprintf(macro_x[MACRO_LASTHOSTCHECK],MAX_DATETIME_LENGTH,"%lu",(unsigned long)hst->last_check); macro_x[MACRO_LASTHOSTCHECK][MAX_DATETIME_LENGTH-1]='\x0'; } /* get the last state change time macro */ if(macro_x[MACRO_LASTHOSTSTATECHANGE]!=NULL) free(macro_x[MACRO_LASTHOSTSTATECHANGE]); macro_x[MACRO_LASTHOSTSTATECHANGE]=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_x[MACRO_LASTHOSTSTATECHANGE]!=NULL){ snprintf(macro_x[MACRO_LASTHOSTSTATECHANGE],MAX_DATETIME_LENGTH,"%lu",(unsigned long)hst->last_state_change); macro_x[MACRO_LASTHOSTSTATECHANGE][MAX_DATETIME_LENGTH-1]='\x0'; } /* get the last time up macro */ if(macro_x[MACRO_LASTHOSTUP]!=NULL) free(macro_x[MACRO_LASTHOSTUP]); macro_x[MACRO_LASTHOSTUP]=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_x[MACRO_LASTHOSTUP]!=NULL){ snprintf(macro_x[MACRO_LASTHOSTUP],MAX_DATETIME_LENGTH,"%lu",(unsigned long)hst->last_time_up); macro_x[MACRO_LASTHOSTUP][MAX_DATETIME_LENGTH-1]='\x0'; } /* get the last time down macro */ if(macro_x[MACRO_LASTHOSTDOWN]!=NULL) free(macro_x[MACRO_LASTHOSTDOWN]); macro_x[MACRO_LASTHOSTDOWN]=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_x[MACRO_LASTHOSTDOWN]!=NULL){ snprintf(macro_x[MACRO_LASTHOSTDOWN],MAX_DATETIME_LENGTH,"%lu",(unsigned long)hst->last_time_down); macro_x[MACRO_LASTHOSTDOWN][MAX_DATETIME_LENGTH-1]='\x0'; } /* get the last time unreachable macro */ if(macro_x[MACRO_LASTHOSTUNREACHABLE]!=NULL) free(macro_x[MACRO_LASTHOSTUNREACHABLE]); macro_x[MACRO_LASTHOSTUNREACHABLE]=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_x[MACRO_LASTHOSTUNREACHABLE]!=NULL){ snprintf(macro_x[MACRO_LASTHOSTUNREACHABLE],MAX_DATETIME_LENGTH,"%lu",(unsigned long)hst->last_time_unreachable); macro_x[MACRO_LASTHOSTUNREACHABLE][MAX_DATETIME_LENGTH-1]='\x0'; } /* find one hostgroup (there may be none or several) this host is associated with */ for(temp_hostgroup=hostgroup_list;temp_hostgroup!=NULL;temp_hostgroup=temp_hostgroup->next){ if(is_host_member_of_hostgroup(temp_hostgroup,hst)==TRUE) break; } /* get the hostgroup name */ if(macro_x[MACRO_HOSTGROUPNAME]!=NULL) free(macro_x[MACRO_HOSTGROUPNAME]); macro_x[MACRO_HOSTGROUPNAME]=NULL; if(temp_hostgroup!=NULL) macro_x[MACRO_HOSTGROUPNAME]=strdup(temp_hostgroup->group_name); /* get the hostgroup alias */ if(macro_x[MACRO_HOSTGROUPALIAS]!=NULL) free(macro_x[MACRO_HOSTGROUPALIAS]); macro_x[MACRO_HOSTGROUPALIAS]=NULL; if(temp_hostgroup!=NULL) macro_x[MACRO_HOSTGROUPALIAS]=strdup(temp_hostgroup->alias); if((temp_hostextinfo=find_hostextinfo(hst->name))){ /* get the action url */ if(macro_x[MACRO_HOSTACTIONURL]!=NULL) free(macro_x[MACRO_HOSTACTIONURL]); if(temp_hostextinfo->action_url==NULL) macro_x[MACRO_HOSTACTIONURL]=NULL; else macro_x[MACRO_HOSTACTIONURL]=strdup(temp_hostextinfo->action_url); /* get the notes url */ if(macro_x[MACRO_HOSTNOTESURL]!=NULL) free(macro_x[MACRO_HOSTNOTESURL]); if(temp_hostextinfo->notes_url==NULL) macro_x[MACRO_HOSTNOTESURL]=NULL; else macro_x[MACRO_HOSTNOTESURL]=strdup(temp_hostextinfo->notes_url); /* get the notes */ if(macro_x[MACRO_HOSTNOTES]!=NULL) free(macro_x[MACRO_HOSTNOTES]); if(temp_hostextinfo->notes==NULL) macro_x[MACRO_HOSTNOTES]=NULL; else macro_x[MACRO_HOSTNOTES]=strdup(temp_hostextinfo->notes); } /* get the date/time macros */ grab_datetime_macros(); strip(macro_x[MACRO_HOSTOUTPUT]); strip(macro_x[MACRO_HOSTPERFDATA]); strip(macro_x[MACRO_HOSTCHECKCOMMAND]); strip(macro_x[MACRO_HOSTNOTES]); /* notes and action URL macros may themselves contain macros, so process them... */ if(macro_x[MACRO_HOSTACTIONURL]!=NULL){ process_macros(macro_x[MACRO_HOSTACTIONURL],temp_buffer,sizeof(temp_buffer),URL_ENCODE_MACRO_CHARS); free(macro_x[MACRO_HOSTACTIONURL]); macro_x[MACRO_HOSTACTIONURL]=strdup(temp_buffer); } if(macro_x[MACRO_HOSTNOTESURL]!=NULL){ process_macros(macro_x[MACRO_HOSTNOTESURL],temp_buffer,sizeof(temp_buffer),URL_ENCODE_MACRO_CHARS); free(macro_x[MACRO_HOSTNOTESURL]); macro_x[MACRO_HOSTNOTESURL]=strdup(temp_buffer); } #ifdef DEBUG0 printf("grab_host_macros() end\n"); #endif return OK; } /* grab an on-demand host or service macro */ int grab_on_demand_macro(char *str){ char *macro=NULL; char *first_arg=NULL; char *second_arg=NULL; char result_buffer[MAX_INPUT_BUFFER]; int result_buffer_len, delimiter_len; host *temp_host; hostgroup *temp_hostgroup; hostgroupmember *temp_hostgroupmember; service *temp_service; servicegroup *temp_servicegroup; servicegroupmember *temp_servicegroupmember; char *ptr; int return_val=ERROR; #ifdef DEBUG0 printf("grab_on_demand_macro() start\n"); #endif /* clear the on-demand macro */ if(macro_ondemand!=NULL){ free(macro_ondemand); macro_ondemand=NULL; } /* get the first argument */ macro=strdup(str); if(macro==NULL) return ERROR; /* get the host name */ ptr=strchr(macro,':'); if(ptr==NULL){ free(macro); return ERROR; } /* terminate the macro name at the first arg's delimiter */ ptr[0]='\x0'; first_arg=ptr+1; /* get the second argument (if present) */ ptr=strchr(first_arg,':'); if(ptr!=NULL){ /* terminate the first arg at the second arg's delimiter */ ptr[0]='\x0'; second_arg=ptr+1; } /* process the macro */ if(strstr(macro,"HOST")){ /* process a host macro */ if(second_arg==NULL){ temp_host=find_host(first_arg); return_val=grab_on_demand_host_macro(temp_host,macro); } /* process a host macro containing a hostgroup */ else{ temp_hostgroup=find_hostgroup(first_arg); if(temp_hostgroup==NULL){ free(macro); return ERROR; } return_val=OK; /* start off assuming there's no error */ result_buffer[0]='\0'; result_buffer[sizeof(result_buffer)-1]='\0'; result_buffer_len=0; delimiter_len=strlen(second_arg); /* process each host in the hostgroup */ temp_hostgroupmember=temp_hostgroup->members; if(temp_hostgroupmember==NULL){ macro_ondemand=strdup(""); free(macro); return OK; } while(1){ temp_host=find_host(temp_hostgroupmember->host_name); if(grab_on_demand_host_macro(temp_host,macro)==OK){ strncat(result_buffer,macro_ondemand,sizeof(result_buffer)-result_buffer_len-1); result_buffer_len+=strlen(macro_ondemand); if(result_buffer_len>sizeof(result_buffer)-1){ return_val=ERROR; break; } temp_hostgroupmember=temp_hostgroupmember->next; if(temp_hostgroupmember==NULL) break; strncat(result_buffer,second_arg,sizeof(result_buffer)-result_buffer_len-1); result_buffer_len+=delimiter_len; if(result_buffer_len>sizeof(result_buffer)-1){ return_val=ERROR; break; } } else{ return_val=ERROR; temp_hostgroupmember=temp_hostgroupmember->next; if(temp_hostgroupmember==NULL) break; } free(macro_ondemand); macro_ondemand=NULL; } free(macro_ondemand); macro_ondemand=strdup(result_buffer); } } else if(strstr(macro,"SERVICE")){ /* second args will either be service description or delimiter */ if(second_arg==NULL){ free(macro); return ERROR; } /* process a service macro */ temp_service=find_service(first_arg, second_arg); if(temp_service!=NULL) return_val=grab_on_demand_service_macro(temp_service,macro); /* process a service macro containing a servicegroup */ else{ temp_servicegroup=find_servicegroup(first_arg); if(temp_servicegroup==NULL){ free(macro); return ERROR; } return_val=OK; /* start off assuming there's no error */ result_buffer[0]='\0'; result_buffer[sizeof(result_buffer)-1]='\0'; result_buffer_len=0; delimiter_len=strlen(second_arg); /* process each service in the servicegroup */ temp_servicegroupmember=temp_servicegroup->members; if(temp_servicegroupmember==NULL){ macro_ondemand=strdup(""); free(macro); return OK; } while(1){ temp_service=find_service(temp_servicegroupmember->host_name,temp_servicegroupmember->service_description); if(grab_on_demand_service_macro(temp_service,macro)==OK){ strncat(result_buffer,macro_ondemand,sizeof(result_buffer)-result_buffer_len-1); result_buffer_len+=strlen(macro_ondemand); if(result_buffer_len>sizeof(result_buffer)-1){ return_val=ERROR; break; } temp_servicegroupmember=temp_servicegroupmember->next; if(temp_servicegroupmember==NULL) break; strncat(result_buffer,second_arg,sizeof(result_buffer)-result_buffer_len-1); result_buffer_len+=delimiter_len; if(result_buffer_len>sizeof(result_buffer)-1){ return_val=ERROR; break; } } else{ return_val=ERROR; temp_servicegroupmember=temp_servicegroupmember->next; if(temp_servicegroupmember==NULL) break; } free(macro_ondemand); macro_ondemand=NULL; } free(macro_ondemand); macro_ondemand=strdup(result_buffer); } } else return_val=ERROR; free(macro); #ifdef DEBUG0 printf("grab_on_demand_macro() end\n"); #endif return return_val; } /* grab an on-demand host macro */ int grab_on_demand_host_macro(host *hst, char *macro){ hostgroup *temp_hostgroup; hostextinfo *temp_hostextinfo; char temp_buffer[MAX_INPUT_BUFFER]; time_t current_time; unsigned long duration; int days; int hours; int minutes; int seconds; #ifdef DEBUG0 printf("grab_on_demand_host_macro() start\n"); #endif if(hst==NULL || macro==NULL) return ERROR; /* initialize the macro */ macro_ondemand=NULL; time(¤t_time); duration=(unsigned long)(current_time-hst->last_state_change); /* find one hostgroup (there may be none or several) this host is associated with */ for(temp_hostgroup=hostgroup_list;temp_hostgroup!=NULL;temp_hostgroup=temp_hostgroup->next){ if(is_host_member_of_hostgroup(temp_hostgroup,hst)==TRUE) break; } /* get the host alias */ if(!strcmp(macro,"HOSTALIAS")) macro_ondemand=strdup(hst->alias); /* get the host address */ else if(!strcmp(macro,"HOSTADDRESS")) macro_ondemand=strdup(hst->address); /* get the host state */ else if(!strcmp(macro,"HOSTSTATE")){ macro_ondemand=(char *)malloc(MAX_STATE_LENGTH); if(macro_ondemand!=NULL){ if(hst->current_state==HOST_DOWN) strcpy(macro_ondemand,"DOWN"); else if(hst->current_state==HOST_UNREACHABLE) strcpy(macro_ondemand,"UNREACHABLE"); else strcpy(macro_ondemand,"UP"); } } /* get the host state id */ else if(!strcmp(macro,"HOSTSTATEID")){ macro_ondemand=(char *)malloc(MAX_STATEID_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_STATEID_LENGTH,"%d",hst->current_state); macro_ondemand[MAX_STATEID_LENGTH-1]='\x0'; } } /* grab the host check type */ else if(!strcmp(macro,"HOSTCHECKTYPE")){ macro_ondemand=(char *)malloc(MAX_CHECKTYPE_LENGTH); if(macro_ondemand!=NULL) strcpy(macro_ondemand,(hst->check_type==HOST_CHECK_PASSIVE)?"PASSIVE":"ACTIVE"); } /* get the host state type macro */ else if(!strcmp(macro,"HOSTSTATETYPE")){ macro_ondemand=(char *)malloc(MAX_STATETYPE_LENGTH); if(macro_ondemand!=NULL) strcpy(macro_ondemand,(hst->state_type==HARD_STATE)?"HARD":"SOFT"); } /* get the plugin output */ else if(!strcmp(macro,"HOSTOUTPUT")){ if(hst->plugin_output==NULL) macro_ondemand=NULL; else{ macro_ondemand=strdup(hst->plugin_output); strip(macro_ondemand); } } /* get the performance data */ else if(!strcmp(macro,"HOSTPERFDATA")){ if(hst->perf_data==NULL) macro_ondemand=NULL; else{ macro_ondemand=strdup(hst->perf_data); strip(macro_ondemand); } } /* get the host current attempt */ else if(!strcmp(macro,"HOSTATTEMPT")){ macro_ondemand=(char *)malloc(MAX_ATTEMPT_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_ATTEMPT_LENGTH,"%d",hst->current_attempt); macro_ondemand[MAX_ATTEMPT_LENGTH-1]='\x0'; } } /* get the host downtime depth */ else if(!strcmp(macro,"HOSTDOWNTIME")){ macro_ondemand=(char *)malloc(MAX_DOWNTIME_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_DOWNTIME_LENGTH,"%d",hst->scheduled_downtime_depth); macro_ondemand[MAX_ATTEMPT_LENGTH-1]='\x0'; } } /* get the percent state change */ else if(!strcmp(macro,"HOSTPERCENTCHANGE")){ macro_ondemand=(char *)malloc(MAX_PERCENTCHANGE_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_PERCENTCHANGE_LENGTH,"%.2f",hst->percent_state_change); macro_ondemand[MAX_PERCENTCHANGE_LENGTH-1]='\x0'; } } /* get the state duration in seconds */ else if(!strcmp(macro,"HOSTDURATIONSEC")){ macro_ondemand=(char *)malloc(MAX_DURATION_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_DURATION_LENGTH,"%lu",duration); macro_ondemand[MAX_DURATION_LENGTH-1]='\x0'; } } /* get the state duration */ else if(!strcmp(macro,"HOSTDURATION")){ macro_ondemand=(char *)malloc(MAX_DURATION_LENGTH); if(macro_ondemand!=NULL){ days=duration/86400; duration-=(days*86400); hours=duration/3600; duration-=(hours*3600); minutes=duration/60; duration-=(minutes*60); seconds=duration; snprintf(macro_ondemand,MAX_DURATION_LENGTH,"%dd %dh %dm %ds",days,hours,minutes,seconds); macro_ondemand[MAX_DURATION_LENGTH-1]='\x0'; } } /* get the execution time macro */ else if(!strcmp(macro,"HOSTEXECUTIONTIME")){ macro_ondemand=(char *)malloc(MAX_EXECUTIONTIME_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_EXECUTIONTIME_LENGTH,"%.3f",hst->execution_time); macro_ondemand[MAX_EXECUTIONTIME_LENGTH-1]='\x0'; } } /* get the latency macro */ else if(!strcmp(macro,"HOSTLATENCY")){ macro_ondemand=(char *)malloc(MAX_LATENCY_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_LATENCY_LENGTH,"%.3f",hst->latency); macro_ondemand[MAX_LATENCY_LENGTH-1]='\x0'; } } /* get the last check time macro */ else if(!strcmp(macro,"LASTHOSTCHECK")){ macro_ondemand=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_DATETIME_LENGTH,"%lu",(unsigned long)hst->last_check); macro_ondemand[MAX_DATETIME_LENGTH-1]='\x0'; } } /* get the last state change time macro */ else if(!strcmp(macro,"LASTHOSTSTATECHANGE")){ macro_ondemand=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_DATETIME_LENGTH,"%lu",(unsigned long)hst->last_state_change); macro_ondemand[MAX_DATETIME_LENGTH-1]='\x0'; } } /* get the last time up macro */ else if(!strcmp(macro,"LASTHOSTUP")){ macro_ondemand=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_DATETIME_LENGTH,"%lu",(unsigned long)hst->last_time_up); macro_ondemand[MAX_DATETIME_LENGTH-1]='\x0'; } } /* get the last time down macro */ else if(!strcmp(macro,"LASTHOSTDOWN")){ macro_ondemand=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_DATETIME_LENGTH,"%lu",(unsigned long)hst->last_time_down); macro_ondemand[MAX_DATETIME_LENGTH-1]='\x0'; } } /* get the last time unreachable macro */ else if(!strcmp(macro,"LASTHOSTUNREACHABLE")){ macro_ondemand=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_DATETIME_LENGTH,"%lu",(unsigned long)hst->last_time_unreachable); macro_ondemand[MAX_DATETIME_LENGTH-1]='\x0'; } } /* get the hostgroup name */ else if(!strcmp(macro,"HOSTGROUPNAME")){ if(temp_hostgroup!=NULL) macro_ondemand=strdup(temp_hostgroup->group_name); } /* get the hostgroup alias */ else if(!strcmp(macro,"HOSTGROUPALIAS")){ if(temp_hostgroup!=NULL) macro_ondemand=strdup(temp_hostgroup->alias); } /* extended info */ else if(!strcmp(macro,"HOSTACTIONURL") || !strcmp(macro,"HOSTNOTESURL") || !strcmp(macro,"HOSTNOTES")){ /* find the extended info entry */ if((temp_hostextinfo=find_hostextinfo(hst->name))){ /* action url */ if(!strcmp(macro,"HOSTACTIONURL")){ if(temp_hostextinfo->action_url) macro_ondemand=strdup(temp_hostextinfo->action_url); /* action URL macros may themselves contain macros, so process them... */ if(macro_ondemand!=NULL){ process_macros(macro_ondemand,temp_buffer,sizeof(temp_buffer),URL_ENCODE_MACRO_CHARS); free(macro_ondemand); macro_ondemand=strdup(temp_buffer); } } /* notes url */ if(!strcmp(macro,"HOSTNOTESURL")){ if(temp_hostextinfo->notes_url) macro_ondemand=strdup(temp_hostextinfo->notes_url); /* action URL macros may themselves contain macros, so process them... */ if(macro_ondemand!=NULL){ process_macros(macro_ondemand,temp_buffer,sizeof(temp_buffer),URL_ENCODE_MACRO_CHARS); free(macro_ondemand); macro_ondemand=strdup(temp_buffer); } } /* notes */ if(!strcmp(macro,"HOSTNOTES")){ if(temp_hostextinfo->notes) macro_ondemand=strdup(temp_hostextinfo->notes); } } } else return ERROR; #ifdef DEBUG0 printf("grab_on_demand_host_macro() end\n"); #endif return OK; } /* grab an on-demand service macro */ int grab_on_demand_service_macro(service *svc, char *macro){ servicegroup *temp_servicegroup; serviceextinfo *temp_serviceextinfo; char temp_buffer[MAX_INPUT_BUFFER]; time_t current_time; unsigned long duration; int days; int hours; int minutes; int seconds; #ifdef DEBUG0 printf("grab_on_demand_service_macro() start\n"); #endif if(svc==NULL || macro==NULL) return ERROR; /* initialize the macro */ macro_ondemand=NULL; time(¤t_time); duration=(unsigned long)(current_time-svc->last_state_change); /* find one servicegroup (there may be none or several) this service is associated with */ for(temp_servicegroup=servicegroup_list;temp_servicegroup!=NULL;temp_servicegroup=temp_servicegroup->next){ if(is_service_member_of_servicegroup(temp_servicegroup,svc)==TRUE) break; } /* get the plugin output */ if(!strcmp(macro,"SERVICEOUTPUT")){ if(svc->plugin_output==NULL) macro_ondemand=NULL; else{ macro_ondemand=strdup(svc->plugin_output); strip(macro_ondemand); } } /* get the performance data */ else if(!strcmp(macro,"SERVICEPERFDATA")){ if(svc->perf_data==NULL) macro_ondemand=NULL; else{ macro_ondemand=strdup(svc->perf_data); strip(macro_ondemand); } } /* grab the servuce check type */ else if(!strcmp(macro,"SERVICECHECKTYPE")){ macro_ondemand=(char *)malloc(MAX_CHECKTYPE_LENGTH); if(macro_ondemand!=NULL) strcpy(macro_ondemand,(svc->check_type==SERVICE_CHECK_PASSIVE)?"PASSIVE":"ACTIVE"); } /* grab the service state type macro (this is usually overridden later on) */ else if(!strcmp(macro,"SERVICESTATETYPE")){ macro_ondemand=(char *)malloc(MAX_STATETYPE_LENGTH); if(macro_ondemand!=NULL) strcpy(macro_ondemand,(svc->state_type==HARD_STATE)?"HARD":"SOFT"); } /* get the service state */ else if(!strcmp(macro,"SERVICESTATE")){ macro_ondemand=(char *)malloc(MAX_STATE_LENGTH); if(macro_ondemand!=NULL){ if(svc->current_state==STATE_OK) strcpy(macro_ondemand,"OK"); else if(svc->current_state==STATE_WARNING) strcpy(macro_ondemand,"WARNING"); else if(svc->current_state==STATE_CRITICAL) strcpy(macro_ondemand,"CRITICAL"); else strcpy(macro_ondemand,"UNKNOWN"); } } /* get the service state id */ else if(!strcmp(macro,"SERVICESTATEID")){ macro_ondemand=(char *)malloc(MAX_STATEID_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_STATEID_LENGTH,"%d",svc->current_state); macro_ondemand[MAX_STATEID_LENGTH-1]='\x0'; } } /* get the current service check attempt macro */ else if(!strcmp(macro,"SERVICEATTEMPT")){ macro_ondemand=(char *)malloc(MAX_ATTEMPT_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_ATTEMPT_LENGTH,"%d",svc->current_attempt); macro_ondemand[MAX_ATTEMPT_LENGTH-1]='\x0'; } } /* get the execution time macro */ else if(!strcmp(macro,"SERVICEEXECUTIONTIME")){ macro_ondemand=(char *)malloc(MAX_EXECUTIONTIME_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_EXECUTIONTIME_LENGTH,"%.3f",svc->execution_time); macro_ondemand[MAX_EXECUTIONTIME_LENGTH-1]='\x0'; } } /* get the latency macro */ else if(!strcmp(macro,"SERVICELATENCY")){ macro_ondemand=(char *)malloc(MAX_LATENCY_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_LATENCY_LENGTH,"%.3f",svc->latency); macro_ondemand[MAX_LATENCY_LENGTH-1]='\x0'; } } /* get the last check time macro */ else if(!strcmp(macro,"LASTSERVICECHECK")){ macro_ondemand=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_DATETIME_LENGTH,"%lu",(unsigned long)svc->last_check); macro_ondemand[MAX_DATETIME_LENGTH-1]='\x0'; } } /* get the last state change time macro */ else if(!strcmp(macro,"LASTSERVICESTATECHANGE")){ macro_ondemand=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_DATETIME_LENGTH,"%lu",(unsigned long)svc->last_state_change); macro_ondemand[MAX_DATETIME_LENGTH-1]='\x0'; } } /* get the last time ok macro */ else if(!strcmp(macro,"LASTSERVICEOK")){ macro_ondemand=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_DATETIME_LENGTH,"%lu",(unsigned long)svc->last_time_ok); macro_ondemand[MAX_DATETIME_LENGTH-1]='\x0'; } } /* get the last time warning macro */ else if(!strcmp(macro,"LASTSERVICEWARNING")){ macro_ondemand=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_DATETIME_LENGTH,"%lu",(unsigned long)svc->last_time_warning); macro_ondemand[MAX_DATETIME_LENGTH-1]='\x0'; } } /* get the last time unknown macro */ else if(!strcmp(macro,"LASTSERVICEUNKNOWN")){ macro_ondemand=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_DATETIME_LENGTH,"%lu",(unsigned long)svc->last_time_unknown); macro_ondemand[MAX_DATETIME_LENGTH-1]='\x0'; } } /* get the last time critical macro */ else if(!strcmp(macro,"LASTSERVICECRITICAL")){ macro_ondemand=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_DATETIME_LENGTH,"%lu",(unsigned long)svc->last_time_critical); macro_ondemand[MAX_DATETIME_LENGTH-1]='\x0'; } } /* get the service downtime depth */ else if(!strcmp(macro,"SERVICEDOWNTIME")){ macro_ondemand=(char *)malloc(MAX_DOWNTIME_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_DOWNTIME_LENGTH,"%d",svc->scheduled_downtime_depth); macro_ondemand[MAX_DOWNTIME_LENGTH-1]='\x0'; } } /* get the percent state change */ else if(!strcmp(macro,"SERVICEPERCENTCHANGE")){ macro_ondemand=(char *)malloc(MAX_PERCENTCHANGE_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_PERCENTCHANGE_LENGTH,"%.2f",svc->percent_state_change); macro_ondemand[MAX_PERCENTCHANGE_LENGTH-1]='\x0'; } } /* get the state duration in seconds */ else if(!strcmp(macro,"SERVICEDURATIONSEC")){ macro_ondemand=(char *)malloc(MAX_DURATION_LENGTH); if(macro_ondemand!=NULL){ snprintf(macro_ondemand,MAX_DURATION_LENGTH,"%lu",duration); macro_ondemand[MAX_DURATION_LENGTH-1]='\x0'; } } /* get the state duration */ else if(!strcmp(macro,"SERVICEDURATION")){ macro_ondemand=(char *)malloc(MAX_DURATION_LENGTH); if(macro_ondemand!=NULL){ days=duration/86400; duration-=(days*86400); hours=duration/3600; duration-=(hours*3600); minutes=duration/60; duration-=(minutes*60); seconds=duration; snprintf(macro_ondemand,MAX_DURATION_LENGTH,"%dd %dh %dm %ds",days,hours,minutes,seconds); macro_ondemand[MAX_DURATION_LENGTH-1]='\x0'; } } /* get the servicegroup name */ else if(!strcmp(macro,"SERVICEGROUPNAME")){ if(temp_servicegroup!=NULL) macro_ondemand=strdup(temp_servicegroup->group_name); } /* get the servicegroup alias */ else if(!strcmp(macro,"SERVICEGROUPALIAS")){ if(temp_servicegroup!=NULL) macro_ondemand=strdup(temp_servicegroup->alias); } /* extended info */ else if(!strcmp(macro,"SERVICEACTIONURL") || !strcmp(macro,"SERVICENOTESURL") || !strcmp(macro,"SERVICENOTES")){ /* find the extended info entry */ if((temp_serviceextinfo=find_serviceextinfo(svc->host_name,svc->description))){ /* action url */ if(!strcmp(macro,"SERVICEACTIONURL")){ if(temp_serviceextinfo->action_url) macro_ondemand=strdup(temp_serviceextinfo->action_url); /* action URL macros may themselves contain macros, so process them... */ if(macro_ondemand!=NULL){ process_macros(macro_ondemand,temp_buffer,sizeof(temp_buffer),URL_ENCODE_MACRO_CHARS); free(macro_ondemand); macro_ondemand=strdup(temp_buffer); } } /* notes url */ if(!strcmp(macro,"SERVICENOTESURL")){ if(temp_serviceextinfo->notes_url) macro_ondemand=strdup(temp_serviceextinfo->notes_url); /* action URL macros may themselves contain macros, so process them... */ if(macro_ondemand!=NULL){ process_macros(macro_ondemand,temp_buffer,sizeof(temp_buffer),URL_ENCODE_MACRO_CHARS); free(macro_ondemand); macro_ondemand=strdup(temp_buffer); } } /* notes */ if(!strcmp(macro,"SERVICENOTES")){ if(temp_serviceextinfo->notes) macro_ondemand=strdup(temp_serviceextinfo->notes); } } } else return ERROR; #ifdef DEBUG0 printf("grab_on_demand_service_macro() end\n"); #endif return OK; } /* grab macros that are specific to a particular contact */ int grab_contact_macros(contact *cntct){ int x; #ifdef DEBUG0 printf("grab_contact_macros() start\n"); #endif /* get the name */ if(macro_x[MACRO_CONTACTNAME]!=NULL) free(macro_x[MACRO_CONTACTNAME]); macro_x[MACRO_CONTACTNAME]=strdup(cntct->name); /* get the alias */ if(macro_x[MACRO_CONTACTALIAS]!=NULL) free(macro_x[MACRO_CONTACTALIAS]); macro_x[MACRO_CONTACTALIAS]=strdup(cntct->alias); /* get the email address */ if(macro_x[MACRO_CONTACTEMAIL]!=NULL) free(macro_x[MACRO_CONTACTEMAIL]); if(cntct->email==NULL) macro_x[MACRO_CONTACTEMAIL]=NULL; else macro_x[MACRO_CONTACTEMAIL]=strdup(cntct->email); /* get the pager number */ if(macro_x[MACRO_CONTACTPAGER]!=NULL) free(macro_x[MACRO_CONTACTPAGER]); if(cntct->pager==NULL) macro_x[MACRO_CONTACTPAGER]=NULL; else macro_x[MACRO_CONTACTPAGER]=strdup(cntct->pager); /* get misc contact addresses */ for(x=0;xaddress[x]==NULL) macro_contactaddress[x]=NULL; else macro_contactaddress[x]=strdup(cntct->address[x]); } /* get the date/time macros */ grab_datetime_macros(); strip(macro_x[MACRO_CONTACTNAME]); strip(macro_x[MACRO_CONTACTALIAS]); strip(macro_x[MACRO_CONTACTEMAIL]); strip(macro_x[MACRO_CONTACTPAGER]); for(x=0;xnext){ /* filter totals based on contact if necessary */ if(temp_contact!=NULL) authorized=is_contact_for_host(temp_host,temp_contact); if(authorized==TRUE){ problem=TRUE; if(temp_host->current_state==HOST_UP && temp_host->has_been_checked==TRUE) hosts_up++; else if(temp_host->current_state==HOST_DOWN){ if(temp_host->scheduled_downtime_depth>0) problem=FALSE; if(temp_host->problem_has_been_acknowledged==TRUE) problem=FALSE; if(temp_host->checks_enabled==FALSE) problem=FALSE; if(problem==TRUE) hosts_down_unhandled++; hosts_down++; } else if(temp_host->current_state==HOST_UNREACHABLE){ if(temp_host->scheduled_downtime_depth>0) problem=FALSE; if(temp_host->problem_has_been_acknowledged==TRUE) problem=FALSE; if(temp_host->checks_enabled==FALSE) problem=FALSE; if(problem==TRUE) hosts_down_unhandled++; hosts_unreachable++; } } } host_problems=hosts_down+hosts_unreachable; host_problems_unhandled=hosts_down_unhandled+hosts_unreachable_unhandled; /* get service totals */ for(temp_service=service_list;temp_service!=NULL;temp_service=temp_service->next){ /* filter totals based on contact if necessary */ if(temp_contact!=NULL) authorized=is_contact_for_service(temp_service,temp_contact); if(authorized==TRUE){ problem=TRUE; if(temp_service->current_state==STATE_OK && temp_service->has_been_checked==TRUE) services_ok++; else if(temp_service->current_state==STATE_WARNING){ temp_host=find_host(temp_service->host_name); if(temp_host!=NULL && (temp_host->current_state==HOST_DOWN || temp_host->current_state==HOST_UNREACHABLE)) problem=FALSE; if(temp_service->scheduled_downtime_depth>0) problem=FALSE; if(temp_service->problem_has_been_acknowledged==TRUE) problem=FALSE; if(temp_service->checks_enabled==FALSE) problem=FALSE; if(problem==TRUE) services_warning_unhandled++; services_warning++; } else if(temp_service->current_state==STATE_UNKNOWN){ temp_host=find_host(temp_service->host_name); if(temp_host!=NULL && (temp_host->current_state==HOST_DOWN || temp_host->current_state==HOST_UNREACHABLE)) problem=FALSE; if(temp_service->scheduled_downtime_depth>0) problem=FALSE; if(temp_service->problem_has_been_acknowledged==TRUE) problem=FALSE; if(temp_service->checks_enabled==FALSE) problem=FALSE; if(problem==TRUE) services_unknown_unhandled++; services_unknown++; } else if(temp_service->current_state==STATE_CRITICAL){ temp_host=find_host(temp_service->host_name); if(temp_host!=NULL && (temp_host->current_state==HOST_DOWN || temp_host->current_state==HOST_UNREACHABLE)) problem=FALSE; if(temp_service->scheduled_downtime_depth>0) problem=FALSE; if(temp_service->problem_has_been_acknowledged==TRUE) problem=FALSE; if(temp_service->checks_enabled==FALSE) problem=FALSE; if(problem==TRUE) services_critical_unhandled++; services_critical++; } } } service_problems=services_warning+services_critical+services_unknown; service_problems_unhandled=services_warning_unhandled+services_critical_unhandled+services_unknown_unhandled; /* get total hosts up */ if(macro_x[MACRO_TOTALHOSTSUP]!=NULL) free(macro_x[MACRO_TOTALHOSTSUP]); macro_x[MACRO_TOTALHOSTSUP]=(char *)malloc(MAX_TOTALS_LENGTH); if(macro_x[MACRO_TOTALHOSTSUP]!=NULL){ snprintf(macro_x[MACRO_TOTALHOSTSUP],MAX_TOTALS_LENGTH,"%d",hosts_up); macro_x[MACRO_TOTALHOSTSUP][MAX_TOTALS_LENGTH-1]='\x0'; } /* get total hosts down */ if(macro_x[MACRO_TOTALHOSTSDOWN]!=NULL) free(macro_x[MACRO_TOTALHOSTSDOWN]); macro_x[MACRO_TOTALHOSTSDOWN]=(char *)malloc(MAX_TOTALS_LENGTH); if(macro_x[MACRO_TOTALHOSTSDOWN]!=NULL){ snprintf(macro_x[MACRO_TOTALHOSTSDOWN],MAX_TOTALS_LENGTH,"%d",hosts_down); macro_x[MACRO_TOTALHOSTSDOWN][MAX_TOTALS_LENGTH-1]='\x0'; } /* get total hosts unreachable */ if(macro_x[MACRO_TOTALHOSTSUNREACHABLE]!=NULL) free(macro_x[MACRO_TOTALHOSTSUNREACHABLE]); macro_x[MACRO_TOTALHOSTSUNREACHABLE]=(char *)malloc(MAX_TOTALS_LENGTH); if(macro_x[MACRO_TOTALHOSTSUNREACHABLE]!=NULL){ snprintf(macro_x[MACRO_TOTALHOSTSUNREACHABLE],MAX_TOTALS_LENGTH,"%d",hosts_unreachable); macro_x[MACRO_TOTALHOSTSUNREACHABLE][MAX_TOTALS_LENGTH-1]='\x0'; } /* get total unhandled hosts down */ if(macro_x[MACRO_TOTALHOSTSDOWNUNHANDLED]!=NULL) free(macro_x[MACRO_TOTALHOSTSDOWNUNHANDLED]); macro_x[MACRO_TOTALHOSTSDOWNUNHANDLED]=(char *)malloc(MAX_TOTALS_LENGTH); if(macro_x[MACRO_TOTALHOSTSDOWNUNHANDLED]!=NULL){ snprintf(macro_x[MACRO_TOTALHOSTSDOWNUNHANDLED],MAX_TOTALS_LENGTH,"%d",hosts_down_unhandled); macro_x[MACRO_TOTALHOSTSDOWNUNHANDLED][MAX_TOTALS_LENGTH-1]='\x0'; } /* get total unhandled hosts unreachable */ if(macro_x[MACRO_TOTALHOSTSUNREACHABLEUNHANDLED]!=NULL) free(macro_x[MACRO_TOTALHOSTSUNREACHABLEUNHANDLED]); macro_x[MACRO_TOTALHOSTSUNREACHABLEUNHANDLED]=(char *)malloc(MAX_TOTALS_LENGTH); if(macro_x[MACRO_TOTALHOSTSUNREACHABLEUNHANDLED]!=NULL){ snprintf(macro_x[MACRO_TOTALHOSTSUNREACHABLEUNHANDLED],MAX_TOTALS_LENGTH,"%d",hosts_unreachable_unhandled); macro_x[MACRO_TOTALHOSTSUNREACHABLEUNHANDLED][MAX_TOTALS_LENGTH-1]='\x0'; } /* get total host problems */ if(macro_x[MACRO_TOTALHOSTPROBLEMS]!=NULL) free(macro_x[MACRO_TOTALHOSTPROBLEMS]); macro_x[MACRO_TOTALHOSTPROBLEMS]=(char *)malloc(MAX_TOTALS_LENGTH); if(macro_x[MACRO_TOTALHOSTPROBLEMS]!=NULL){ snprintf(macro_x[MACRO_TOTALHOSTPROBLEMS],MAX_TOTALS_LENGTH,"%d",host_problems); macro_x[MACRO_TOTALHOSTPROBLEMS][MAX_TOTALS_LENGTH-1]='\x0'; } /* get total unhandled host problems */ if(macro_x[MACRO_TOTALHOSTPROBLEMSUNHANDLED]!=NULL) free(macro_x[MACRO_TOTALHOSTPROBLEMSUNHANDLED]); macro_x[MACRO_TOTALHOSTPROBLEMSUNHANDLED]=(char *)malloc(MAX_TOTALS_LENGTH); if(macro_x[MACRO_TOTALHOSTPROBLEMSUNHANDLED]!=NULL){ snprintf(macro_x[MACRO_TOTALHOSTPROBLEMSUNHANDLED],MAX_TOTALS_LENGTH,"%d",host_problems_unhandled); macro_x[MACRO_TOTALHOSTPROBLEMSUNHANDLED][MAX_TOTALS_LENGTH-1]='\x0'; } /* get total services ok */ if(macro_x[MACRO_TOTALSERVICESOK]!=NULL) free(macro_x[MACRO_TOTALSERVICESOK]); macro_x[MACRO_TOTALSERVICESOK]=(char *)malloc(MAX_TOTALS_LENGTH); if(macro_x[MACRO_TOTALSERVICESOK]!=NULL){ snprintf(macro_x[MACRO_TOTALSERVICESOK],MAX_TOTALS_LENGTH,"%d",services_ok); macro_x[MACRO_TOTALSERVICESOK][MAX_TOTALS_LENGTH-1]='\x0'; } /* get total services warning */ if(macro_x[MACRO_TOTALSERVICESWARNING]!=NULL) free(macro_x[MACRO_TOTALSERVICESWARNING]); macro_x[MACRO_TOTALSERVICESWARNING]=(char *)malloc(MAX_TOTALS_LENGTH); if(macro_x[MACRO_TOTALSERVICESWARNING]!=NULL){ snprintf(macro_x[MACRO_TOTALSERVICESWARNING],MAX_TOTALS_LENGTH,"%d",services_warning); macro_x[MACRO_TOTALSERVICESWARNING][MAX_TOTALS_LENGTH-1]='\x0'; } /* get total services critical */ if(macro_x[MACRO_TOTALSERVICESCRITICAL]!=NULL) free(macro_x[MACRO_TOTALSERVICESCRITICAL]); macro_x[MACRO_TOTALSERVICESCRITICAL]=(char *)malloc(MAX_TOTALS_LENGTH); if(macro_x[MACRO_TOTALSERVICESCRITICAL]!=NULL){ snprintf(macro_x[MACRO_TOTALSERVICESCRITICAL],MAX_TOTALS_LENGTH,"%d",services_critical); macro_x[MACRO_TOTALSERVICESCRITICAL][MAX_TOTALS_LENGTH-1]='\x0'; } /* get total services unknown */ if(macro_x[MACRO_TOTALSERVICESUNKNOWN]!=NULL) free(macro_x[MACRO_TOTALSERVICESUNKNOWN]); macro_x[MACRO_TOTALSERVICESUNKNOWN]=(char *)malloc(MAX_TOTALS_LENGTH); if(macro_x[MACRO_TOTALSERVICESUNKNOWN]!=NULL){ snprintf(macro_x[MACRO_TOTALSERVICESUNKNOWN],MAX_TOTALS_LENGTH,"%d",services_unknown); macro_x[MACRO_TOTALSERVICESUNKNOWN][MAX_TOTALS_LENGTH-1]='\x0'; } /* get total unhandled services warning */ if(macro_x[MACRO_TOTALSERVICESWARNINGUNHANDLED]!=NULL) free(macro_x[MACRO_TOTALSERVICESWARNINGUNHANDLED]); macro_x[MACRO_TOTALSERVICESWARNINGUNHANDLED]=(char *)malloc(MAX_TOTALS_LENGTH); if(macro_x[MACRO_TOTALSERVICESWARNINGUNHANDLED]!=NULL){ snprintf(macro_x[MACRO_TOTALSERVICESWARNINGUNHANDLED],MAX_TOTALS_LENGTH,"%d",services_warning_unhandled); macro_x[MACRO_TOTALSERVICESWARNINGUNHANDLED][MAX_TOTALS_LENGTH-1]='\x0'; } /* get total unhandled services critical */ if(macro_x[MACRO_TOTALSERVICESCRITICALUNHANDLED]!=NULL) free(macro_x[MACRO_TOTALSERVICESCRITICALUNHANDLED]); macro_x[MACRO_TOTALSERVICESCRITICALUNHANDLED]=(char *)malloc(MAX_TOTALS_LENGTH); if(macro_x[MACRO_TOTALSERVICESCRITICALUNHANDLED]!=NULL){ snprintf(macro_x[MACRO_TOTALSERVICESCRITICALUNHANDLED],MAX_TOTALS_LENGTH,"%d",services_critical_unhandled); macro_x[MACRO_TOTALSERVICESCRITICALUNHANDLED][MAX_TOTALS_LENGTH-1]='\x0'; } /* get total unhandled services unknown */ if(macro_x[MACRO_TOTALSERVICESUNKNOWNUNHANDLED]!=NULL) free(macro_x[MACRO_TOTALSERVICESUNKNOWNUNHANDLED]); macro_x[MACRO_TOTALSERVICESUNKNOWNUNHANDLED]=(char *)malloc(MAX_TOTALS_LENGTH); if(macro_x[MACRO_TOTALSERVICESUNKNOWNUNHANDLED]!=NULL){ snprintf(macro_x[MACRO_TOTALSERVICESUNKNOWNUNHANDLED],MAX_TOTALS_LENGTH,"%d",services_unknown_unhandled); macro_x[MACRO_TOTALSERVICESUNKNOWNUNHANDLED][MAX_TOTALS_LENGTH-1]='\x0'; } /* get total service problems */ if(macro_x[MACRO_TOTALSERVICEPROBLEMS]!=NULL) free(macro_x[MACRO_TOTALSERVICEPROBLEMS]); macro_x[MACRO_TOTALSERVICEPROBLEMS]=(char *)malloc(MAX_TOTALS_LENGTH); if(macro_x[MACRO_TOTALSERVICEPROBLEMS]!=NULL){ snprintf(macro_x[MACRO_TOTALSERVICEPROBLEMS],MAX_TOTALS_LENGTH,"%d",service_problems); macro_x[MACRO_TOTALSERVICEPROBLEMS][MAX_TOTALS_LENGTH-1]='\x0'; } /* get total unhandled service problems */ if(macro_x[MACRO_TOTALSERVICEPROBLEMSUNHANDLED]!=NULL) free(macro_x[MACRO_TOTALSERVICEPROBLEMSUNHANDLED]); macro_x[MACRO_TOTALSERVICEPROBLEMSUNHANDLED]=(char *)malloc(MAX_TOTALS_LENGTH); if(macro_x[MACRO_TOTALSERVICEPROBLEMSUNHANDLED]!=NULL){ snprintf(macro_x[MACRO_TOTALSERVICEPROBLEMSUNHANDLED],MAX_TOTALS_LENGTH,"%d",service_problems_unhandled); macro_x[MACRO_TOTALSERVICEPROBLEMSUNHANDLED][MAX_TOTALS_LENGTH-1]='\x0'; } #ifdef DEBUG0 printf("grab_summary_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_x[MACRO_LONGDATETIME]==NULL) macro_x[MACRO_LONGDATETIME]=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_x[MACRO_LONGDATETIME]!=NULL) get_datetime_string(&t,macro_x[MACRO_LONGDATETIME],MAX_DATETIME_LENGTH,LONG_DATE_TIME); /* get the current date/time (short format macro) */ if(macro_x[MACRO_SHORTDATETIME]==NULL) macro_x[MACRO_SHORTDATETIME]=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_x[MACRO_SHORTDATETIME]!=NULL) get_datetime_string(&t,macro_x[MACRO_SHORTDATETIME],MAX_DATETIME_LENGTH,SHORT_DATE_TIME); /* get the short format date macro */ if(macro_x[MACRO_DATE]==NULL) macro_x[MACRO_DATE]=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_x[MACRO_DATE]!=NULL) get_datetime_string(&t,macro_x[MACRO_DATE],MAX_DATETIME_LENGTH,SHORT_DATE); /* get the short format time macro */ if(macro_x[MACRO_TIME]==NULL) macro_x[MACRO_TIME]=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_x[MACRO_TIME]!=NULL) get_datetime_string(&t,macro_x[MACRO_TIME],MAX_DATETIME_LENGTH,SHORT_TIME); /* get the time_t format time macro */ if(macro_x[MACRO_TIMET]==NULL) macro_x[MACRO_TIMET]=(char *)malloc(MAX_DATETIME_LENGTH); if(macro_x[MACRO_TIMET]!=NULL){ snprintf(macro_x[MACRO_TIMET],MAX_DATETIME_LENGTH,"%lu",(unsigned long)t); macro_x[MACRO_TIMET][MAX_DATETIME_LENGTH-1]='\x0'; } strip(macro_x[MACRO_LONGDATETIME]); strip(macro_x[MACRO_SHORTDATETIME]); strip(macro_x[MACRO_DATE]); strip(macro_x[MACRO_TIME]); strip(macro_x[MACRO_TIMET]); #ifdef DEBUG0 printf("grab_datetime_macros() end\n"); #endif return OK; } /* clear argv macros - used in commands */ int clear_argv_macros(void){ int x; #ifdef DEBUG0 printf("clear_argv_macros() start\n"); #endif /* command argument macros */ for(x=0;x=16 && x<=19) set_macro_environment_var(macro_x_names[x],clean_macro_chars(macro_x[x],STRIP_ILLEGAL_MACRO_CHARS|ESCAPE_MACRO_CHARS),set); /* others don't */ else set_macro_environment_var(macro_x_names[x],macro_x[x],set); } #ifdef DEBUG0 printf("set_macrox_environment_vars() end\n"); #endif return OK; } /* sets or unsets argv macro environment variables */ int set_argv_macro_environment_vars(int set){ char macro_name[MAX_INPUT_BUFFER]; int x; #ifdef DEBUG0 printf("set_argv_macro_environment_vars() start\n"); #endif /* set each of the argv macro environment variables */ for(x=0;x3) result=STATE_UNKNOWN; /* try and read the results from the command output (retry if we encountered a signal) */ do{ bytes_read=read(fd[0],buffer,sizeof(buffer)-1); }while(bytes_read==-1 && errno==EINTR); buffer[sizeof(buffer)-1]='\x0'; if(output!=NULL){ strncpy(output,buffer,output_length); output[output_length-1]='\x0'; } 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.tv_sec-start_time.tv_sec)>=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); } #ifdef USE_EVENT_BROKER /* send data to event broker */ broker_system_command(NEBTYPE_SYSTEM_COMMAND_END,NEBFLAG_NONE,NEBATTR_NONE,start_time,end_time,*exectime,timeout,*early_timeout,result,cmd,output,NULL); #endif /* 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, int macro_options){ char temp_arg[MAX_COMMAND_BUFFER]; char arg_buffer[MAX_COMMAND_BUFFER]; command *temp_command; int x,y; int arg_index; #ifdef DEBUG0 printf("get_raw_command_line() start\n"); #endif #ifdef DEBUG1 printf("\tInput: %s\n",cmd); #endif /* clear the argv macros */ clear_argv_macros(); /* make sure we've got all the requirements */ if(cmd==NULL || raw_command==NULL || buffer_length<=0){ #ifdef DEBUG1 printf("\tWe don't have enough data to get the raw command line!\n"); #endif return; } /* initialize the command */ strcpy(raw_command,""); /* clear the old command arguments */ for(x=0;xcommand_line,buffer_length); raw_command[buffer_length-1]='\x0'; strip(raw_command); /* skip the command name (we're about to get the arguments)... */ for(arg_index=0;;arg_index++){ if(cmd[arg_index]=='!' || cmd[arg_index]=='\x0') break; } /* get the command arguments */ for(x=0;xtm_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); 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"}; #ifdef HAVE_TM_ZONE # define tzone tm_ptr->tm_zone #else # define tzone (tm_ptr->tm_isdst)?tzname[1]:tzname[0] #endif 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; /* 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'; /* don't mess up other functions that might want to call a variable 'tzone' */ #undef tzone return; } /* get the next time to schedule a log rotation */ time_t get_next_log_rotation_time(void){ time_t current_time; struct tm *t; int is_dst_now=FALSE; time_t run_time; #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: default: t->tm_mon++; t->tm_mday=1; t->tm_hour=0; run_time=mktime(t); 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 run_time; } /******************************************************************/ /******************** 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(SIGPIPE,SIG_IGN); signal(SIGQUIT,sighandler); signal(SIGTERM,sighandler); signal(SIGHUP,sighandler); #if !defined(DEBUG0) && !defined(DEBUG1) && !defined(DEBUG2) && !defined(DEBUG3) && !defined(DEBUG4) && !defined(DEBUG5) if(daemon_dumps_core==FALSE || daemon_mode==FALSE) signal(SIGSEGV,sighandler); #endif #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); signal(SIGPIPE,SIG_DFL); #ifdef DEBUG0 printf("reset_sighandler() end\n"); #endif return; } /* handle signals */ void sighandler(int sig){ char buffer[MAX_INPUT_BUFFER]; int x=0; /* if shutdown is already true, we're in a signal trap loop! */ /* changed 09/07/06 to only exit on segfaults */ if(sigshutdown==TRUE && sig==SIGSEGV) exit(ERROR); caught_signal=TRUE; if(sig<0) sig=-sig; for(x=0;sigs[x]!=(char *)NULL;x++); sig%=x; sig_id=sig; /* log errors about segfaults now, as we might not get a chance to later */ /* all other signals are logged at a later point in main() to prevent problems with NPTL */ if(sig==SIGSEGV){ snprintf(buffer,sizeof(buffer),"Caught SIG%s, shutting down...\n",sigs[sig]); buffer[sizeof(buffer)-1]='\x0'; #ifdef DEBUG2 printf("%s\n",buffer); #endif write_to_all_logs(buffer,NSLOG_PROCESS_INFO); } /* we received a SIGHUP, so restart... */ if(sig==SIGHUP) sigrestart=TRUE; /* else begin shutting down... */ else if(sig<16) sigshutdown=TRUE; return; } /* handle timeouts when executing service checks */ void service_check_sighandler(int sig){ struct timeval end_time; /* get the current time */ gettimeofday(&end_time,NULL); /* 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'; #ifdef SERVICE_CHECK_TIMEOUTS_RETURN_UNKNOWN svc_msg.return_code=STATE_UNKNOWN; #else svc_msg.return_code=STATE_CRITICAL; #endif svc_msg.exited_ok=TRUE; svc_msg.check_type=SERVICE_CHECK_ACTIVE; svc_msg.finish_time=end_time; svc_msg.early_timeout=TRUE; 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]; char *homedir=NULL; #ifdef RLIMIT_CORE struct rlimit limit; #endif /* change working directory. scuttle home if we're dumping core */ homedir=getenv("HOME"); if(daemon_dumps_core==TRUE && homedir!=NULL) chdir(homedir); else chdir("/"); 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){ fcntl(lockfile,F_GETLK,&lock); 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 if(daemon_dumps_core==FALSE){ 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); #ifdef USE_EVENT_BROKER /* send program data to broker */ broker_program_state(NEBTYPE_PROCESS_DAEMONIZE,NEBFLAG_NONE,NEBATTR_NONE,NULL); #endif 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; int result=OK; #ifdef DEBUG0 printf("drop_privileges() start\n"); #endif #ifdef DEBUG1 printf("Original UID/GID: %d/%d\n",(int)getuid(),(int)getgid()); #endif /* only drop privileges if we're running as root, so we don't interfere with being debugged while running as some random user */ if(getuid()!=0) return OK; /* 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); result=ERROR; } } } /* 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); result=ERROR; } } #ifdef DEBUG1 printf("New UID/GID: %d/%d\n",(int)getuid(),(int)getgid()); #endif #ifdef DEBUG0 printf("drop_privileges() end\n"); #endif return result; } /******************************************************************/ /************************* IPC FUNCTIONS **************************/ /******************************************************************/ /* reads a service message from the circular buffer */ int read_svc_message(service_message *message){ char buffer[MAX_INPUT_BUFFER]; int result; #ifdef DEBUG0 printf("read_svc_message() start\n"); #endif if(message==NULL) return -1; /* clear the message buffer */ memset((void *)message,0,sizeof(service_message)); /* get a lock on the buffer */ pthread_mutex_lock(&service_result_buffer.buffer_lock); /* handle detected overflows */ if(service_result_buffer.overflow>0){ /* log the warning */ snprintf(buffer,sizeof(buffer)-1,"Warning: Overflow detected in service check result buffer - %lu message(s) lost.\n",service_result_buffer.overflow); buffer[sizeof(buffer)-1]='\x0'; write_to_logs_and_console(buffer,NSLOG_RUNTIME_WARNING,TRUE); /* reset overflow counter */ service_result_buffer.overflow=0; } /* there are no items in the buffer */ if(service_result_buffer.items==0) result=-1; /* return the message from the tail of the buffer */ else{ /* copy message to user-supplied structure */ memcpy(message,((service_message **)service_result_buffer.buffer)[service_result_buffer.tail],sizeof(service_message)); /* free memory allocated for buffer slot */ free(((service_message **)service_result_buffer.buffer)[service_result_buffer.tail]); service_result_buffer.buffer[service_result_buffer.tail]=NULL; /* adjust tail counter and number of items */ service_result_buffer.tail=(service_result_buffer.tail + 1) % check_result_buffer_slots; service_result_buffer.items--; result=0; } /* release the lock on the buffer */ pthread_mutex_unlock(&service_result_buffer.buffer_lock); #ifdef DEBUG0 printf("read_svc_message() end\n"); #endif return result; } /* writes a service message to the message pipe */ int write_svc_message(service_message *message){ struct timeval tv; int write_result; #ifdef DEBUG0 printf("write_svc_message() start\n"); #endif if(message==NULL) return 0; while(1){ write_result=write(ipc_pipe[1],message,sizeof(service_message)); if(write_result==-1){ /* pipe is full - wait a bit and retry */ if(errno==EAGAIN){ tv.tv_sec=0; tv.tv_usec=250; select(0,NULL,NULL,NULL,&tv); continue; } /* an interrupt occurred - retry */ if(errno==EINTR) continue; /* some other error occurred - bail out */ 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]; struct stat st; 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); /* use existing FIFO if possible */ if(!(stat(command_file,&st)!=-1 && (st.st_mode & S_IFIFO))){ /* 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; } /* initialize worker thread */ if(init_command_file_worker_thread()==ERROR){ snprintf(buffer,sizeof(buffer)-1,"Error: Could not initialize command file worker thread.\n"); buffer[sizeof(buffer)-1]='\x0'; write_to_logs_and_console(buffer,NSLOG_RUNTIME_ERROR,TRUE); /* close the command file */ fclose(command_file_fp); /* delete the named pipe */ unlink(command_file); 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){ #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; /* the command file wasn't created or was already cleaned up */ if(command_file_created==FALSE) return OK; /* reset our flag */ command_file_created=FALSE; /* shutdown the worker thread */ shutdown_command_file_worker_thread(); /* close the command file */ fclose(command_file_fp); /* 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 beginning and end of a string */ void strip(char *buffer){ register int x; register int y; register int z; if(buffer==NULL || buffer[0]=='\x0') return; /* strip end of string */ y=(int)strlen(buffer); for(x=y-1;x>=0;x--){ if(buffer[x]==' ' || buffer[x]=='\n' || buffer[x]=='\r' || buffer[x]=='\t' || buffer[x]==13) buffer[x]='\x0'; else break; } /* strip beginning of string (by shifting) */ y=(int)strlen(buffer); for(x=0;x0){ for(z=x;z=0;x--){ ch=(int)name[x]; /* illegal ASCII characters */ if(ch<32 || ch==127) return TRUE; /* REMOVED 3/11/05 to allow for non-english spellings, etc. */ /* 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=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=strchr(my_strtok_buffer,tokens[0]); if(token_position==NULL){ my_strtok_buffer=strchr(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; } /* encodes a string in proper URL format */ char *get_url_encoded_string(char *input){ register int x,y; char *encoded_url_string=NULL; char temp_expansion[4]; /* bail if no input */ if(input==NULL) return NULL; /* allocate enough memory to escape all characters if necessary */ if((encoded_url_string=(char *)malloc((strlen(input)*3)+1))==NULL) return NULL; /* check/encode all characters */ for(x=0,y=0;input[x]!=(char)'\x0';x++){ /* alpha-numeric characters and a few other characters don't get encoded */ if(((char)input[x]>='0' && (char)input[x]<='9') || ((char)input[x]>='A' && (char)input[x]<='Z') || ((char)input[x]>=(char)'a' && (char)input[x]<=(char)'z') || (char)input[x]==(char)'.' || (char)input[x]==(char)'-' || (char)input[x]==(char)'_'){ encoded_url_string[y]=input[x]; y++; } /* spaces are pluses */ else if((char)input[x]<=(char)' '){ encoded_url_string[y]='+'; y++; } /* anything else gets represented by its hex value */ else{ encoded_url_string[y]='\x0'; sprintf(temp_expansion,"%%%02X",(unsigned int)input[x]); strcat(encoded_url_string,temp_expansion); y+=3; } } /* terminate encoded string */ encoded_url_string[y]='\x0'; return encoded_url_string; } /******************************************************************/ /************************* HASH FUNCTIONS *************************/ /******************************************************************/ /* single hash function */ int hashfunc1(const char *name1,int hashslots){ unsigned int i,result; result=0; if(name1) for(i=0;i0) return 1; else if(result<0) return -1; else return strcmp(val1b,val2b); } /******************************************************************/ /************************* 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 successfully copied file */ rename_result=0; } else{ close(dest_fd); return rename_result; } } else return rename_result; } return rename_result; } /* open a file read-only via mmap() */ mmapfile *mmap_fopen(char *filename){ mmapfile *new_mmapfile; int fd; void *mmap_buf; struct stat statbuf; int mode=O_RDONLY; /* allocate memory */ if((new_mmapfile=(mmapfile *)malloc(sizeof(mmapfile)))==NULL) return NULL; /* open the file */ if((fd=open(filename,mode))==-1){ free(new_mmapfile); return NULL; } /* get file info */ if((fstat(fd,&statbuf))==-1){ close(fd); free(new_mmapfile); return NULL; } /* mmap() the file - allocate one extra byte for processing zero-byte files */ if((mmap_buf=(void *)mmap(0,statbuf.st_size+1,PROT_READ,MAP_PRIVATE,fd,0))==MAP_FAILED){ close(fd); free(new_mmapfile); return NULL; } /* populate struct info for later use */ /*new_mmapfile->path=strdup(filename);*/ new_mmapfile->path=NULL; new_mmapfile->fd=fd; new_mmapfile->file_size=(unsigned long)(statbuf.st_size); new_mmapfile->current_position=0L; new_mmapfile->current_line=0L; new_mmapfile->mmap_buf=mmap_buf; return new_mmapfile; } /* close a file originally opened via mmap() */ int mmap_fclose(mmapfile *temp_mmapfile){ if(temp_mmapfile==NULL) return ERROR; /* un-mmap() the file */ munmap(temp_mmapfile->mmap_buf,temp_mmapfile->file_size); /* close the file */ close(temp_mmapfile->fd); /* free memory */ if(temp_mmapfile->path!=NULL) free(temp_mmapfile->path); free(temp_mmapfile); return OK; } /* gets one line of input from an mmap()'ed file */ char *mmap_fgets(mmapfile *temp_mmapfile){ char *buf=NULL; unsigned long x=0L; int len=0; if(temp_mmapfile==NULL) return NULL; /* we've reached the end of the file */ if(temp_mmapfile->current_position>=temp_mmapfile->file_size) return NULL; /* find the end of the string (or buffer) */ for(x=temp_mmapfile->current_position;xfile_size;x++){ if(*((char *)(temp_mmapfile->mmap_buf)+x)=='\n'){ x++; break; } } /* calculate length of line we just read */ len=(int)(x-temp_mmapfile->current_position); /* allocate memory for the new line */ if((buf=(char *)malloc(len+1))==NULL) return NULL; /* copy string to newly allocated memory and terminate the string */ memcpy(buf,((char *)(temp_mmapfile->mmap_buf)+temp_mmapfile->current_position),len); buf[len]='\x0'; /* update the current position */ temp_mmapfile->current_position=x; /* increment the current line */ temp_mmapfile->current_line++; return buf; } /* gets one line of input from an mmap()'ed file (may be contained on more than one line in the source file) */ char *mmap_fgets_multiline(mmapfile *temp_mmapfile){ char *buf=NULL; char *tempbuf=NULL; int len; int len2; if(temp_mmapfile==NULL) return NULL; while(1){ free(tempbuf); if((tempbuf=mmap_fgets(temp_mmapfile))==NULL) break; if(buf==NULL){ len=strlen(tempbuf); if((buf=(char *)malloc(len+1))==NULL) break; memcpy(buf,tempbuf,len); buf[len]='\x0'; } else{ len=strlen(tempbuf); len2=strlen(buf); if((buf=(char *)realloc(buf,len+len2+1))==NULL) break; strcat(buf,tempbuf); len+=len2; buf[len]='\x0'; } /* we shouldn't continue to the next line... */ if(!(len>0 && buf[len-1]=='\\' && (len==1 || buf[len-2]!='\\'))) break; } free(tempbuf); return buf; } /******************************************************************/ /******************** EMBEDDED PERL FUNCTIONS *********************/ /******************************************************************/ /* initializes embedded perl interpreter */ int init_embedded_perl(char **env){ #ifdef EMBEDDEDPERL char *embedding[] = { "", "" }; int exitstatus = 0; char buffer[MAX_INPUT_BUFFER]; int argc = 2; struct stat stat_buf; /* make sure the P1 file exists... */ if(p1_file==NULL || stat(p1_file,&stat_buf)!=0){ use_embedded_perl=FALSE; snprintf(buffer,sizeof(buffer),"Error: p1.pl file required for embedded Perl interpreter is missing!\n"); buffer[sizeof(buffer)-1]='\x0'; write_to_logs_and_console(buffer,NSLOG_RUNTIME_ERROR,TRUE); } else{ embedding[1]=p1_file; use_embedded_perl=TRUE; PERL_SYS_INIT3(&argc,&embedding,&env); if((my_perl=perl_alloc())==NULL){ use_embedded_perl=FALSE; snprintf(buffer,sizeof(buffer),"Error: Could not allocate memory for embedded Perl interpreter!\n"); buffer[sizeof(buffer)-1]='\x0'; write_to_logs_and_console(buffer,NSLOG_RUNTIME_ERROR,TRUE); } } /* a fatal error occurred... */ if(use_embedded_perl==FALSE){ snprintf(buffer,sizeof(buffer),"Bailing out due to errors encountered while initializing the embedded Perl interpreter. (PID=%d)\n",(int)getpid()); buffer[sizeof(buffer)-1]='\x0'; write_to_logs_and_console(buffer,NSLOG_PROCESS_INFO | NSLOG_RUNTIME_ERROR,TRUE); cleanup(); exit(ERROR); } perl_construct(my_perl); exitstatus=perl_parse(my_perl,xs_init,2,embedding,env); if(!exitstatus) exitstatus=perl_run(my_perl); #endif return OK; } /* closes embedded perl interpreter */ int deinit_embedded_perl(void){ #ifdef EMBEDDEDPERL PL_perl_destruct_level=0; perl_destruct(my_perl); perl_free(my_perl); PERL_SYS_TERM(); #endif return OK; } /******************************************************************/ /************************ THREAD FUNCTIONS ************************/ /******************************************************************/ /* initializes service result worker thread */ int init_service_result_worker_thread(void){ int result; sigset_t newmask; /* initialize circular buffer */ service_result_buffer.head=0; service_result_buffer.tail=0; service_result_buffer.items=0; service_result_buffer.high=0; service_result_buffer.overflow=0L; service_result_buffer.buffer=(void **)malloc(check_result_buffer_slots*sizeof(service_message **)); if(service_result_buffer.buffer==NULL) return ERROR; /* initialize mutex */ pthread_mutex_init(&service_result_buffer.buffer_lock,NULL); /* new thread should block all signals */ sigfillset(&newmask); pthread_sigmask(SIG_BLOCK,&newmask,NULL); /* create worker thread */ result=pthread_create(&worker_threads[SERVICE_WORKER_THREAD],NULL,service_result_worker_thread,NULL); /* main thread should unblock all signals */ pthread_sigmask(SIG_UNBLOCK,&newmask,NULL); #ifdef DEBUG1 printf("SERVICE CHECK THREAD: %lu\n",(unsigned long)worker_threads[SERVICE_WORKER_THREAD]); #endif if(result) return ERROR; return OK; } /* shutdown the service result worker thread */ int shutdown_service_result_worker_thread(void){ /* tell the worker thread to exit */ pthread_cancel(worker_threads[SERVICE_WORKER_THREAD]); /* wait for the worker thread to exit */ pthread_join(worker_threads[SERVICE_WORKER_THREAD],NULL); return OK; } /* clean up resources used by service result worker thread */ void cleanup_service_result_worker_thread(void *arg){ int x; /* release memory allocated to circular buffer */ for(x=service_result_buffer.tail;x!=service_result_buffer.head;x=(x+1) % check_result_buffer_slots){ free(((service_message **)service_result_buffer.buffer)[x]); ((service_message **)service_result_buffer.buffer)[x]=NULL; } free(service_result_buffer.buffer); return; } /* initializes command file worker thread */ int init_command_file_worker_thread(void){ int result; sigset_t newmask; /* initialize circular buffer */ external_command_buffer.head=0; external_command_buffer.tail=0; external_command_buffer.items=0; external_command_buffer.high=0; external_command_buffer.overflow=0L; external_command_buffer.buffer=(void **)malloc(external_command_buffer_slots*sizeof(char **)); if(external_command_buffer.buffer==NULL) return ERROR; /* initialize mutex */ pthread_mutex_init(&external_command_buffer.buffer_lock,NULL); /* new thread should block all signals */ sigfillset(&newmask); pthread_sigmask(SIG_BLOCK,&newmask,NULL); /* create worker thread */ result=pthread_create(&worker_threads[COMMAND_WORKER_THREAD],NULL,command_file_worker_thread,NULL); /* main thread should unblock all signals */ pthread_sigmask(SIG_UNBLOCK,&newmask,NULL); #ifdef DEBUG1 printf("COMMAND FILE THREAD: %lu\n",(unsigned long)worker_threads[COMMAND_WORKER_THREAD]); #endif if(result) return ERROR; return OK; } /* shutdown command file worker thread */ int shutdown_command_file_worker_thread(void){ /* tell the worker thread to exit */ pthread_cancel(worker_threads[COMMAND_WORKER_THREAD]); /* wait for the worker thread to exit */ pthread_join(worker_threads[COMMAND_WORKER_THREAD],NULL); return OK; } /* clean up resources used by command file worker thread */ void cleanup_command_file_worker_thread(void *arg){ int x; /* release memory allocated to circular buffer */ for(x=external_command_buffer.tail;x!=external_command_buffer.head;x=(x+1) % external_command_buffer_slots){ free(((char **)external_command_buffer.buffer)[x]); ((char **)external_command_buffer.buffer)[x]=NULL; } free(external_command_buffer.buffer); return; } /* service worker thread - artificially increases buffer of IPC pipe */ void * service_result_worker_thread(void *arg){ struct pollfd pfd; int pollval; struct timeval tv; int read_result; int bytes_to_read; int write_offset; int buffer_items; service_message message; service_message *new_message; /* specify cleanup routine */ pthread_cleanup_push(cleanup_service_result_worker_thread,NULL); /* set cancellation info */ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL); while(1){ /* should we shutdown? */ pthread_testcancel(); /* wait for data to arrive */ /* select seems to not work, so we have to use poll instead */ pfd.fd=ipc_pipe[0]; pfd.events=POLLIN; pollval=poll(&pfd,1,500); /* loop if no data */ if(pollval==0) continue; /* check for errors */ if(pollval==-1){ switch(errno){ case EBADF: write_to_log("service_result_worker_thread(): poll(): EBADF",logging_options,NULL); break; case ENOMEM: write_to_log("service_result_worker_thread(): poll(): ENOMEM",logging_options,NULL); break; case EFAULT: write_to_log("service_result_worker_thread(): poll(): EFAULT",logging_options,NULL); break; case EINTR: /* this can happen when running under a debugger like gdb */ /* write_to_log("service_result_worker_thread(): poll(): EINTR (impossible)",logging_options,NULL); */ break; default: write_to_log("service_result_worker_thread(): poll(): Unknown errno value.",logging_options,NULL); break; } continue; } /* should we shutdown? */ pthread_testcancel(); /* get number of items in the buffer */ pthread_mutex_lock(&service_result_buffer.buffer_lock); buffer_items=service_result_buffer.items; pthread_mutex_unlock(&service_result_buffer.buffer_lock); /* process data in the pipe (one message max) if there's some free space in the circular buffer */ if(buffer_items=0){ /* allocate memory for the message */ new_message=(service_message *)malloc(sizeof(service_message)); if(new_message==NULL) break; /* copy the data we read to the message buffer */ memcpy(new_message,&message,sizeof(service_message)); /* obtain a lock for writing to the buffer */ pthread_mutex_lock(&service_result_buffer.buffer_lock); /* handle overflow conditions */ /* NOTE: This should never happen (see check above) - child processes will instead block trying to write messages to the pipe... */ if(service_result_buffer.items==check_result_buffer_slots){ /* record overflow */ service_result_buffer.overflow++; /* update tail pointer */ service_result_buffer.tail=(service_result_buffer.tail + 1) % check_result_buffer_slots; } /* save the data to the buffer */ ((service_message **)service_result_buffer.buffer)[service_result_buffer.head]=new_message; /* increment the head counter and items */ service_result_buffer.head=(service_result_buffer.head + 1) % check_result_buffer_slots; if(service_result_buffer.itemsservice_result_buffer.high) service_result_buffer.high=service_result_buffer.items; /* release lock on buffer */ pthread_mutex_unlock(&service_result_buffer.buffer_lock); } } /* no free space in the buffer, so wait a bit */ else{ tv.tv_sec=0; tv.tv_usec=500; select(0,NULL,NULL,NULL,&tv); } } /* removes cleanup handler - should never be reached */ pthread_cleanup_pop(0); return NULL; } /* worker thread - artificially increases buffer of named pipe */ void * command_file_worker_thread(void *arg){ char input_buffer[MAX_INPUT_BUFFER]; struct timeval tv; int buffer_items; int result; /* specify cleanup routine */ pthread_cleanup_push(cleanup_command_file_worker_thread,NULL); /* set cancellation info */ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL); while(1){ /* should we shutdown? */ pthread_testcancel(); /**** POLL() AND SELECT() DON'T SEEM TO WORK ****/ /* wait a bit */ tv.tv_sec=0; tv.tv_usec=500000; select(0,NULL,NULL,NULL,&tv); /* should we shutdown? */ pthread_testcancel(); /* get number of items in the buffer */ pthread_mutex_lock(&external_command_buffer.buffer_lock); buffer_items=external_command_buffer.items; pthread_mutex_unlock(&external_command_buffer.buffer_lock); #ifdef DEBUG_CFWT printf("(CFWT) BUFFER ITEMS: %d/%d\n",buffer_items,external_command_buffer_slots); #endif /* process all commands in the file (named pipe) if there's some space in the buffer */ if(buffer_itemsexternal_command_buffer.high) external_command_buffer.high=external_command_buffer.items; } /* buffer was full */ else result=ERROR; /* return number of items now in buffer */ if(buffer_items!=NULL) *buffer_items=external_command_buffer.items; /* release lock on buffer */ pthread_mutex_unlock(&external_command_buffer.buffer_lock); return result; } /* submits a raw external command (without timestamp) for processing */ int submit_raw_external_command(char *cmd, time_t *ts, int *buffer_items){ char *newcmd=NULL; int length=0; int result=OK; time_t timestamp; if(cmd==NULL) return ERROR; /* allocate memory for the command string */ length=strlen(cmd)+16; newcmd=(char *)malloc(length); if(newcmd==NULL) return ERROR; /* get the time */ if(ts!=NULL) timestamp=*ts; else time(×tamp); /* create the command string */ snprintf(newcmd,length-1,"[%lu] %s",(unsigned long)timestamp,cmd); newcmd[length-1]='\x0'; /* submit the command */ result=submit_external_command(newcmd,buffer_items); /* free allocated memory */ free(newcmd); return result; } /******************************************************************/ /************************* MISC FUNCTIONS *************************/ /******************************************************************/ /* returns Nagios version */ char *get_program_version(void){ return (char *)PROGRAM_VERSION; } /* returns Nagios modification date */ char *get_program_modification_date(void){ return (char *)PROGRAM_MODIFICATION_DATE; } /******************************************************************/ /*********************** CLEANUP FUNCTIONS ************************/ /******************************************************************/ /* do some cleanup before we exit */ void cleanup(void){ #ifdef DEBUG0 printf("cleanup() start\n"); #endif #ifdef USE_EVENT_BROKER /* unload modules */ if(test_scheduling==FALSE && verify_config==FALSE){ neb_free_callback_list(); neb_unload_all_modules(NEBMODULE_FORCE_UNLOAD,(sigshutdown==TRUE)?NEBMODULE_NEB_SHUTDOWN:NEBMODULE_NEB_RESTART); neb_free_module_list(); neb_deinit_modules(); } #endif /* free all allocated memory - including macros */ free_memory(); #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; int x; #ifdef DEBUG0 printf("free_memory() start\n"); #endif /* free all allocated memory for the object definitions */ free_object_data(); /* free memory allocated to comments */ free_comment_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 commands */ if(ocsp_command!=NULL){ free(ocsp_command); ocsp_command=NULL; } if(ochp_command!=NULL){ free(ochp_command); ochp_command=NULL; } /* free memory associated with macros */ for(x=0;xnext; 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 log_file=(char *)strdup(DEFAULT_LOG_FILE); temp_file=(char *)strdup(DEFAULT_TEMP_FILE); command_file=(char *)strdup(DEFAULT_COMMAND_FILE); lock_file=(char *)strdup(DEFAULT_LOCK_FILE); auth_file=(char *)strdup(DEFAULT_AUTH_FILE); p1_file=(char *)strdup(DEFAULT_P1_FILE); log_archive_path=(char *)strdup(DEFAULT_LOG_ARCHIVE_PATH); nagios_user=(char *)strdup(DEFAULT_NAGIOS_USER); nagios_group=(char *)strdup(DEFAULT_NAGIOS_GROUP); use_regexp_matches=FALSE; use_true_regexp_matching=FALSE; 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; ochp_timeout=DEFAULT_OCHP_TIMEOUT; sleep_time=DEFAULT_SLEEP_TIME; interval_length=DEFAULT_INTERVAL_LENGTH; service_inter_check_delay_method=ICD_SMART; host_inter_check_delay_method=ICD_SMART; service_interleave_factor_method=ILF_SMART; max_service_check_spread=DEFAULT_SERVICE_CHECK_SPREAD; max_host_check_spread=DEFAULT_HOST_CHECK_SPREAD; 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; use_retained_scheduling_info=FALSE; retention_scheduling_horizon=DEFAULT_RETENTION_SCHEDULING_HORIZON; modified_host_process_attributes=MODATTR_NONE; modified_service_process_attributes=MODATTR_NONE; command_check_interval=DEFAULT_COMMAND_CHECK_INTERVAL; service_check_reaper_interval=DEFAULT_SERVICE_REAPER_INTERVAL; service_freshness_check_interval=DEFAULT_FRESHNESS_CHECK_INTERVAL; host_freshness_check_interval=DEFAULT_FRESHNESS_CHECK_INTERVAL; auto_rescheduling_interval=DEFAULT_AUTO_RESCHEDULING_INTERVAL; auto_rescheduling_window=DEFAULT_AUTO_RESCHEDULING_WINDOW; check_external_commands=DEFAULT_CHECK_EXTERNAL_COMMANDS; check_orphaned_services=DEFAULT_CHECK_ORPHANED_SERVICES; check_service_freshness=DEFAULT_CHECK_SERVICE_FRESHNESS; check_host_freshness=DEFAULT_CHECK_HOST_FRESHNESS; auto_reschedule_checks=DEFAULT_AUTO_RESCHEDULE_CHECKS; log_rotation_method=LOG_ROTATION_NONE; last_command_check=0L; last_command_status_update=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; execute_host_checks=TRUE; accept_passive_service_checks=TRUE; enable_event_handlers=TRUE; obsess_over_services=FALSE; obsess_over_hosts=FALSE; enable_failure_prediction=TRUE; aggregate_status_updates=TRUE; status_update_interval=DEFAULT_STATUS_UPDATE_INTERVAL; event_broker_options=BROKER_NOTHING; 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; external_command_buffer_slots=DEFAULT_EXTERNAL_COMMAND_BUFFER_SLOTS; check_result_buffer_slots=DEFAULT_CHECK_RESULT_BUFFER_SLOTS; date_format=DATE_FORMAT_US; for(x=0;x